--- /dev/null
+config VIDEO_EXYNOS_FIMC_IS
+ bool "Exynos FIMC-IS (Image Subsystem) driver"
+ depends on VIDEO_EXYNOS
+ select MEDIA_EXYNOS
+ select USE_VENDER_FEATURE
+ default n
+ help
+ This is a v4l2 driver for exynos FIMC-IS device.
+config CAMERA_EEPROM_SUPPORT_REAR
+ bool "Enable eeprom for rear cam"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Enable eeprom for rear cam.
+config CAMERA_EEPROM_SUPPORT_FRONT
+ bool "Enable eeprom for front cam"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Enable eeprom for front cam.
+config COMPANION_USE
+ bool "Enable to companion"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Enable to companion.
+config OIS_USE
+ bool "Enable to ois"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Enable to ois.
+config OIS_FW_UPDATE_THREAD_USE
+ bool "Enable to ois fw update thread"
+ depends on OIS_USE
+ default n
+ help
+ Enable to ois fw update thread.
+config AF_HOST_CONTROL
+ bool "Enable to af control"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Enable to af control.
+config USE_VENDER_FEATURE
+ bool "Use vendor specific features"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Enable to use the vender.
+config CAMERA_SENSOR_8B1
+ bool "Use 8B1 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use 8B1 camera sensor.
+config CAMERA_SENSOR_6D1
+ bool "Use 6D1 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use 6D1 camera sensor.
+config CAMERA_SENSOR_8B1_OBJ
+ bool "Use 8B1 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 8B1 camera sensor.
+config CAMERA_SENSOR_6D1_OBJ
+ bool "Use 6D1 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 6D1 camera sensor.
+config CAMERA_SENSOR_6B2_OBJ
+ bool "Use 6B2 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 6B2 camera sensor.
+config CAMERA_SENSOR_6A3_OBJ
+ bool "Use 6A3 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 6A3 camera sensor.
+config CAMERA_SENSOR_IMX135_OBJ
+ bool "Use IMX135 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build IMX135 camera sensor.
+config CAMERA_SENSOR_IMX134_OBJ
+ bool "Use IMX134 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build IMX134 camera sensor.
+config CAMERA_SENSOR_3L2_OBJ
+ bool "Use 3L2 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 3L2 camera sensor.
+config CAMERA_SENSOR_2P2_OBJ
+ bool "Use 2P2 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 2P2 camera sensor.
+config CAMERA_SENSOR_2P2_12M_OBJ
+ bool "Use 2P2_12M camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 2P2_12M camera sensor.
+config CAMERA_SENSOR_2P3_OBJ
+ bool "Use 2P3 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 2P3 camera sensor.
+config CAMERA_SENSOR_3H5_OBJ
+ bool "Use 3H5 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 3H5 camera sensor.
+config CAMERA_SENSOR_3H7_OBJ
+ bool "Use 3H7 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 3H7 camera sensor.
+config CAMERA_SENSOR_3H7_SUNNY_OBJ
+ bool "Use 3H7_SUNNY camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 3H7_SUNNY camera sensor.
+config CAMERA_SENSOR_4E5_OBJ
+ bool "Use 4E5 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 4E5 camera sensor.
+config CAMERA_SENSOR_IMX175_OBJ
+ bool "Use IMX175 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build IMX175 camera sensor.
+config CAMERA_SENSOR_IMX219_OBJ
+ bool "Use IMX219 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build IMX219 camera sensor.
+config CAMERA_SENSOR_IMX240_OBJ
+ bool "Use IMX240 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build IMX240 camera sensor.
+config CAMERA_SENSOR_4H5_OBJ
+ bool "Use 4H5 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build 4H5 camera sensor.
+config CAMERA_SENSOR_SR261_OBJ
+ bool "Use SR261 camera sensor"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build SR261 camera sensor.
+config CAMERA_SENSOR_TEMP
+ bool "camera sensor temp"
+ depends on VIDEO_EXYNOS_FIMC_IS
+ default n
+ help
+ Use to build camera sensor temp.
--- /dev/null
+fimc-is-objs := fimc-is-core.o \
+ fimc-is-mem.o \
+ fimc-is-framemgr.o \
+ fimc-is-groupmgr.o \
+ fimc-is-resourcemgr.o \
+ fimc-is-video.o \
+ fimc-is-video-sensor.o \
+ fimc-is-video-3aa.o \
+ fimc-is-video-3aac.o \
+ fimc-is-video-isp.o \
+ fimc-is-video-scc.o \
+ fimc-is-video-scp.o \
+ fimc-is-video-vdisc.o \
+ fimc-is-video-vdiso.o \
+ fimc-is-hw-csi.o \
+ fimc-is-hw-ischain.o \
+ fimc-is-subdev-ctrl.o \
+ fimc-is-device-csi.o \
+ fimc-is-device-flite.o \
+ fimc-is-device-sensor.o \
+ fimc-is-device-ischain.o \
+ fimc-is-interface.o \
+ fimc-is-time.o \
+ fimc-is-dvfs.o \
+ fimc-is-dt.o \
+ fimc-is-clk-gate.o
+
+obj-$(CONFIG_USE_VENDER_FEATURE) := fimc-is-spi.o \
+ fimc-is-sec-define.o \
+ crc32.o
+
+obj-$(CONFIG_COMPANION_USE) += fimc-is-companion.o \
+ fimc-is-fan53555.o \
+ fimc-is-ncp6335b.o \
+ fimc-is-companion-dt.o \
+ fimc-is-device-companion.o \
+ fimc-is-video-companion.o
+
+obj-$(CONFIG_VIDEO_EXYNOS_FIMC_IS) += fimc-is.o
+obj-$(CONFIG_OIS_USE) += fimc-is-device-ois.o
+obj-$(CONFIG_AF_HOST_CONTROL) += fimc-is-device-af.o
+obj-$(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) += fimc-is-device-eeprom.o
+obj-$(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) += fimc-is-device-eeprom.o
+
+obj-$(CONFIG_CAMERA_SENSOR_6B2_OBJ) += sensor/fimc-is-device-6b2.o
+obj-$(CONFIG_CAMERA_SENSOR_8B1_OBJ) += sensor/fimc-is-device-8b1.o
+obj-$(CONFIG_CAMERA_SENSOR_6D1_OBJ) += sensor/fimc-is-device-6d1.o
+obj-$(CONFIG_CAMERA_SENSOR_IMX134_OBJ) += sensor/fimc-is-device-imx134.o
+obj-$(CONFIG_CAMERA_SENSOR_IMX135_OBJ) += sensor/fimc-is-device-imx135.o
+obj-$(CONFIG_CAMERA_SENSOR_3L2_OBJ) += sensor/fimc-is-device-3l2.o
+obj-$(CONFIG_CAMERA_SENSOR_2P2_OBJ) += sensor/fimc-is-device-2p2.o
+obj-$(CONFIG_CAMERA_SENSOR_2P2_12M_OBJ) += sensor/fimc-is-device-2p2_12m.o
+obj-$(CONFIG_CAMERA_SENSOR_2P3_OBJ) += sensor/fimc-is-device-2p3.o
+obj-$(CONFIG_CAMERA_SENSOR_3H5_OBJ) += sensor/fimc-is-device-3h5.o
+obj-$(CONFIG_CAMERA_SENSOR_3H7_OBJ) += sensor/fimc-is-device-3h7.o
+obj-$(CONFIG_CAMERA_SENSOR_3H7_SUNNY_OBJ) += sensor/fimc-is-device-3h7_sunny.o
+obj-$(CONFIG_CAMERA_SENSOR_4E5_OBJ) += sensor/fimc-is-device-4e5.o
+obj-$(CONFIG_CAMERA_SENSOR_6A3_OBJ) += sensor/fimc-is-device-6a3.o
+obj-$(CONFIG_CAMERA_SENSOR_IMX175_OBJ) += sensor/fimc-is-device-imx175.o
+obj-$(CONFIG_CAMERA_SENSOR_IMX240_OBJ) += sensor/fimc-is-device-imx240.o
+obj-$(CONFIG_CAMERA_SENSOR_IMX219_OBJ) += sensor/fimc-is-device-imx219.o
+obj-$(CONFIG_CAMERA_SENSOR_4H5_OBJ) += sensor/fimc-is-device-4h5.o
\ No newline at end of file
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 "crc32.h"
+
+/* #define DEBUG_CRC */
+
+static void makeCRCtable(unsigned long *table, unsigned long id)
+{
+ unsigned long i, j, k;
+
+ for(i = 0; i < 256; ++i) {
+ k = i;
+
+ for(j = 0; j < 8; ++j) {
+ if(k & 1)
+ k = (k >> 1) ^ id;
+ else
+ k >>= 1;
+ }
+
+ table[i] = k;
+ }
+}
+
+unsigned long getCRC(volatile unsigned short *mem, signed long count,
+ volatile unsigned short *crcH, volatile unsigned short *crcL)
+{
+ unsigned char mem0, mem1;
+ int i;
+ unsigned long CRC = 0;
+#ifndef DEBUG_CRC
+ unsigned long table[256];
+#else
+ unsigned long table[256] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+ };
+#endif
+
+ /* duration : under 1 ms */
+ makeCRCtable(table, 0xEDB88320);
+
+ CRC = ~CRC;
+ for(i = 0; i < count; i++) {
+ mem0 = (unsigned char)(mem[i] & 0x00ff);
+ mem1 = (unsigned char)((mem[i] >> 8) & 0x00ff);
+
+ CRC = table[(CRC ^ (mem0)) & 0xFF] ^ (CRC >> 8);
+ CRC = table[(CRC ^ (mem1)) & 0xFF] ^ (CRC >> 8);
+ }
+ CRC = ~CRC;
+
+ /*
+ * high 2 byte of crc32
+ * g_CAL[0page 31 addr.] or g_CAL[127page 31 addr.]
+ */
+ if(crcH)
+ *crcH = (unsigned short)((CRC >> 16)&(0x0000ffff));
+ /*
+ * low 2 byte of crc32
+ * g_CAL[0page 30 addr.] or g_CAL[127page 30 addr.]
+ */
+ if(crcL)
+ *crcL = (unsigned short)((CRC) & (0x0000ffff));
+
+ return CRC;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 CRC32_H
+#define CRC32_H
+
+/* unit of count is 2byte */
+unsigned long getCRC(volatile unsigned short *mem, signed long count,
+ volatile unsigned short *crcH, volatile unsigned short *crcL);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos SoC series FIMC-IS driver
+ *
+ * exynos fimc-is core functions
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
+ *
+ * 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 "fimc-is-clk-gate.h"
+
+int fimc_is_clk_gate_init(struct fimc_is_core *core)
+{
+ struct fimc_is_clk_gate_ctrl *gate_ctrl;
+
+ pr_info("%s\n", __func__);
+
+ if (!core) {
+ err("core is NULL\n");
+ return -EINVAL;
+ }
+
+ gate_ctrl = &core->resourcemgr.clk_gate_ctrl;
+ memset(gate_ctrl, 0x0, sizeof(struct fimc_is_clk_gate_ctrl));
+
+ /* init spin_lock for clock gating */
+ spin_lock_init(&gate_ctrl->lock);
+ core->resourcemgr.clk_gate_ctrl.gate_info = core->pdata->gate_info;
+
+ /* ISSR53 is clock gating debugging region.
+ * High means clock on state.
+ * To prevent telling A5 wrong clock off state,
+ * clock on state should be set before clock off is set.
+ */
+ writel(0xFFFFFFFF, core->ischain[0].interface->regs + ISSR53);
+
+ return 0;
+}
+
+int fimc_is_clk_gate_lock_set(struct fimc_is_core *core, u32 instance, u32 is_start)
+{
+ spin_lock(&core->resourcemgr.clk_gate_ctrl.lock);
+ core->resourcemgr.clk_gate_ctrl.msk_lock_by_ischain[instance] = is_start;
+ spin_unlock(&core->resourcemgr.clk_gate_ctrl.lock);
+ return 0;
+}
+
+#if 0
+/* This function may be used when clk_enable api will be faster than now */
+int fimc_is_clk_gate_reg_set(struct fimc_is_core *core,
+ bool is_on, const char* gate_str, u32 clk_gate_id,
+ struct exynos_fimc_is_clk_gate_info *gate_info)
+{
+ struct platform_device *pdev = core->pdev;
+ if (is_on) {
+ if (gate_info->clk_on(pdev, gate_str) < 0) {
+ pr_err("%s: could not enable %s\n", __func__, gate_str);
+ return -EINVAL;
+ }
+ } else {
+ if (gate_info->clk_off(pdev, gate_str) < 0) {
+ pr_err("%s: could not disable %s\n", __func__, gate_str);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+#endif
+
+int fimc_is_wrap_clk_gate_set(struct fimc_is_core *core,
+ int msk_group_id, bool is_on)
+{
+ int i;
+
+ for (i = 0; i < FIMC_IS_GRP_MAX; i++) {
+ if (msk_group_id & (1 << i))
+ fimc_is_clk_gate_set(core, i, is_on, true, false);
+ }
+
+ return 0;
+}
+
+inline bool fimc_is_group_otf(struct fimc_is_device_ischain *device, int group_id)
+{
+ struct fimc_is_group *group;
+
+ switch (group_id) {
+ case GROUP_ID_3A0:
+ case GROUP_ID_3A1:
+ group = &device->group_3aa;
+ break;
+ case GROUP_ID_ISP:
+ group = &device->group_isp;
+ break;
+ case GROUP_ID_DIS:
+ group = &device->group_dis;
+ break;
+ default:
+ group = NULL;
+ pr_err("%s unresolved group id %d", __func__, group_id);
+ return false;
+ }
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state))
+ return true;
+ else
+ return false;
+}
+
+int fimc_is_clk_gate_set(struct fimc_is_core *core,
+ int group_id, bool is_on, bool skip_set_state, bool user_scenario)
+{
+ int ret = 0;
+ int cfg = 0;
+ int i;
+ struct fimc_is_clk_gate_ctrl *gate_ctrl;
+ struct exynos_fimc_is_clk_gate_info *gate_info;
+ u32 mask_on, mask_off, mask_cond_depend;
+
+ gate_ctrl = &core->resourcemgr.clk_gate_ctrl;
+ gate_info = gate_ctrl->gate_info;
+
+ pr_debug("%s in\n", __func__);
+ spin_lock(&gate_ctrl->lock);
+
+ /* Set State */
+ if (is_on) {
+ if (skip_set_state == false) {
+ (gate_ctrl->chk_on_off_cnt[group_id])++; /* for debuging */
+ (gate_ctrl->msk_cnt[group_id])++;
+ set_bit(group_id, &gate_ctrl->msk_state);
+ }
+ gate_info->groups[group_id].mask_clk_on_mod =
+ gate_info->groups[group_id].mask_clk_on_org;
+ } else {
+ (gate_ctrl->chk_on_off_cnt[group_id])--; /* for debuging */
+ (gate_ctrl->msk_cnt[group_id])--;
+ if ((gate_ctrl->msk_cnt[group_id]) < 0) {
+ pr_warn("%s msk_cnt[%d] is lower than zero !!\n", __func__, group_id);
+ (gate_ctrl->msk_cnt[group_id]) = 0;
+ }
+ if ((gate_ctrl->msk_cnt[group_id]) == 0)
+ clear_bit(group_id, &gate_ctrl->msk_state);
+ /* if there's some processing group shot, don't clock off */
+ if (test_bit(group_id, &gate_ctrl->msk_state))
+ goto exit;
+ gate_info->groups[group_id].mask_clk_off_self_mod =
+ gate_info->groups[group_id].mask_clk_off_self_org;
+ }
+
+ /* Don't off!! when other instance opening/closing */
+ if (is_on == false) {
+ for (i = 0; i < FIMC_IS_MAX_NODES; i++) {
+ if ((!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &core->ischain[i].state)) &&
+ (gate_ctrl->msk_lock_by_ischain[i])) {
+ pr_info("%s lock(on) due to instance(%d)\n", __func__, i);
+ goto exit;
+ }
+ /* don't off! if there is at least this group that is OTF */
+ if (fimc_is_group_otf(&core->ischain[i], group_id)) {
+ pr_debug("%s don't off!! this instance(%d) group(%d) is OTF\n",
+ __func__, i, group_id);
+ goto exit;
+ }
+ }
+ }
+
+ /* Check user scenario */
+ if (user_scenario && gate_info->user_clk_gate) {
+ if (fimc_is_set_user_clk_gate(group_id,
+ core,
+ is_on,
+ gate_ctrl->msk_state,
+ gate_info) < 0) {
+ pr_debug("%s user scenario is skip!! [%d] !!\n", __func__, group_id);
+ goto exit;
+ }
+ }
+
+ /* Get the region for clock gating debug */
+ cfg = readl(core->ischain[0].interface->regs + ISSR53);
+
+ /* Get Mask of self-on/off */
+ if (is_on)
+ mask_on = gate_info->groups[group_id].mask_clk_on_mod;
+ else
+ mask_off = gate_info->groups[group_id].mask_clk_off_self_mod;
+
+ /* Clock on */
+ if (is_on && ((gate_ctrl->msk_clk_on_off_state) != mask_on)) {
+ cfg |= (mask_on << 16); /* shortly before clock on */
+ writel(cfg, core->ischain[0].interface->regs + ISSR53);
+
+ ret = gate_info->clk_on_off(mask_on, is_on);
+ gate_ctrl->msk_clk_on_off_state |= mask_on;
+
+ cfg |= (mask_on); /* after clock on */
+ writel(cfg, core->ischain[0].interface->regs + ISSR53);
+ }
+
+ /* Clock off and check dependancy (it's for only clock-off) */
+ if (is_on == false) {
+ mask_cond_depend = gate_info->groups[group_id].mask_cond_for_depend;
+ /* check dependancy */
+ if (mask_cond_depend > 0 &&
+ (mask_cond_depend & (gate_ctrl->msk_state))) {
+ mask_off |= gate_info->groups[group_id].mask_clk_off_depend;
+ }
+ /* clock off */
+ if (((gate_ctrl->msk_clk_on_off_state) & mask_off) > 0) {
+ cfg &= ~(mask_off << 16); /* shortly before clock off */
+ writel(cfg, core->ischain[0].interface->regs + ISSR53);
+
+ ret = gate_info->clk_on_off(mask_off, is_on);
+ gate_ctrl->msk_clk_on_off_state &= ~(mask_off);
+
+ cfg &= ~(mask_off); /* after clock off */
+ writel(cfg, core->ischain[0].interface->regs + ISSR53);
+ }
+ }
+exit:
+ spin_unlock(&gate_ctrl->lock);
+ pr_debug("%s out\n", __func__);
+
+ return ret;
+}
+
+int fimc_is_set_user_clk_gate(u32 group_id,
+ struct fimc_is_core *core,
+ bool is_on,
+ unsigned long msk_state,
+ struct exynos_fimc_is_clk_gate_info *gate_info)
+{
+ u32 user_scenario_id = 0;
+
+ /* deside what user scenario is */
+#if defined(ENABLE_FULL_BYPASS)
+ if (group_id == GROUP_ID_ISP)
+ user_scenario_id = CLK_GATE_FULL_BYPASS_SN;
+#else
+ if (group_id == GROUP_ID_ISP)
+ user_scenario_id = CLK_GATE_NOT_FULL_BYPASS_SN;
+
+#endif
+ if (group_id == GROUP_ID_ISP &&
+ test_bit(FIMC_IS_SUBDEV_START,
+ &core->ischain[0].dis.state))
+ user_scenario_id = CLK_GATE_DIS_SN;
+
+ if (gate_info->user_clk_gate(group_id,
+ is_on,
+ user_scenario_id,
+ msk_state,
+ gate_info) < 0) {
+ pr_err("%s user_clk_gate failed(%d) !!\n", __func__, group_id);
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_CLK_GATE_H
+#define FIMC_IS_CLK_GATE_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-groupmgr.h"
+#include "fimc-is-device-ischain.h"
+
+int fimc_is_clk_gate_init(struct fimc_is_core *core);
+int fimc_is_clk_gate_lock_set(struct fimc_is_core *core, u32 instance, u32 is_start);
+int fimc_is_clk_gate_reg_set(struct fimc_is_core *core,
+ bool is_on, const char* gate_str, u32 clk_gate_id,
+ struct exynos_fimc_is_clk_gate_info *gate_info);
+/* For several groups */
+int fimc_is_wrap_clk_gate_set(struct fimc_is_core *core,
+ int msk_group_id, bool is_on);
+/* For only single group */
+int fimc_is_clk_gate_set(struct fimc_is_core *core,
+ int group_id, bool is_on, bool skip_set_state, bool user_scenario);
+
+int fimc_is_set_user_clk_gate(u32 group_id,
+ struct fimc_is_core *core,
+ bool is_on,
+ unsigned long msk_state,
+ struct exynos_fimc_is_clk_gate_info *gate_info);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_CMD_H
+#define FIMC_IS_CMD_H
+
+#include "fimc-is-config.h"
+
+#define IS_COMMAND_VER 132 /* IS COMMAND VERSION 1.32 */
+
+enum is_cmd {
+ /* HOST -> IS */
+ HIC_PREVIEW_STILL = 0x1,
+ HIC_PREVIEW_VIDEO,
+ HIC_CAPTURE_STILL,
+ HIC_CAPTURE_VIDEO,
+ HIC_PROCESS_START,
+ HIC_PROCESS_STOP,
+ HIC_STREAM_ON /* 7 */,
+ HIC_STREAM_OFF /* 8 */,
+ HIC_SHOT,
+ HIC_GET_STATIC_METADATA /* 10 */,
+ HIC_SET_CAM_CONTROL,
+ HIC_GET_CAM_CONTROL,
+ HIC_SET_PARAMETER /* 13 */,
+ HIC_GET_PARAMETER,
+ HIC_SET_A5_MAP /* 15 */,
+ HIC_SET_A5_UNMAP /* 16 */,
+ HIC_GET_STATUS,
+ /* SENSOR PART*/
+ HIC_OPEN_SENSOR,
+ HIC_CLOSE_SENSOR,
+ HIC_SIMMIAN_INIT /* 20 */,
+ HIC_SIMMIAN_WRITE,
+ HIC_SIMMIAN_READ,
+ HIC_POWER_DOWN,
+ HIC_GET_SET_FILE_ADDR,
+ HIC_LOAD_SET_FILE,
+ HIC_MSG_CONFIG,
+ HIC_MSG_TEST,
+ HIC_ISP_I2C_CONTROL,
+ HIC_CALIBRATE_ACTUATOR,
+ HIC_GET_IP_STATUS /* 30 */,
+ HIC_I2C_CONTROL_LOCK,
+#if (SUPPORTED_IS_CMD_VER >= 132)
+ HIC_SYSTEM_CONTROL,
+ HIC_SENSOR_MODE_CHANGE,
+#elif (SUPPORTED_IS_CMD_VER >= 131)
+ HIC_SENSOR_MODE_CHANGE,
+#endif
+ HIC_ADJUST_SET_FILE,
+ HIC_CHECK_A5_TASK_CPU_USAGE,
+ HIC_COMMAND_END,
+
+ /* IS -> HOST */
+ IHC_GET_SENSOR_NUMBER = 0x1000,
+ /* Parameter1 : Address of space to copy a setfile */
+ /* Parameter2 : Space szie */
+ IHC_SET_SHOT_MARK,
+ /* PARAM1 : a frame number */
+ /* PARAM2 : confidence level(smile 0~100) */
+ /* PARMA3 : confidence level(blink 0~100) */
+ IHC_SET_FACE_MARK,
+ /* PARAM1 : coordinate count */
+ /* PARAM2 : coordinate buffer address */
+ IHC_FRAME_DONE,
+ /* PARAM1 : frame start number */
+ /* PARAM2 : frame count */
+ IHC_AA_DONE,
+ IHC_NOT_READY,
+ IHC_FLASH_READY,
+#if (SUPPORTED_IS_CMD_VER >= 131)
+ IHC_REPORT_ERR,
+#endif
+ IHC_COMMAND_END
+};
+
+/* supported command macros by F/W version */
+#define FW_HAS_SYS_CTRL_CMD (SUPPORTED_IS_CMD_VER >= 132)
+#define FW_HAS_SENSOR_MODE_CMD (SUPPORTED_IS_CMD_VER >= 131)
+#define FW_HAS_REPORT_ERR_CMD (SUPPORTED_IS_CMD_VER >= 131)
+
+enum is_reply {
+ ISR_DONE = 0x2000,
+ ISR_NDONE
+};
+
+enum is_scenario_id {
+ ISS_PREVIEW_STILL,
+ ISS_PREVIEW_VIDEO,
+ ISS_CAPTURE_STILL,
+ ISS_CAPTURE_VIDEO,
+ ISS_END
+};
+
+enum is_subscenario_id {
+ ISS_SUB_SCENARIO_STILL_PREVIEW = 0, /* 0: still preview */
+ ISS_SUB_SCENARIO_VIDEO = 1, /* 1: video */
+ ISS_SUB_SCENARIO_DUAL_STILL = 2, /* 2: dual still preview */
+ ISS_SUB_SCENARIO_DUAL_VIDEO = 3, /* 3: dual video */
+ ISS_SUB_SCENARIO_VIDEO_HIGH_SPEED = 4, /* 4: video high speed */
+ ISS_SUB_SCENARIO_STILL_CAPTURE = 5, /* 5: still capture */
+ ISS_SUB_SCENARIO_FHD_60FPS = 6, /* 6: video FHD 60fps */
+ ISS_SUB_SCENARIO_UHD_30FPS = 7, /* 7: video UHD 30fps */
+ ISS_SUB_SCENARIO_WVGA_300FPS = 8, /* 8: video WVGA 300fps */
+ ISS_SUB_SCENARIO_STILL_PREVIEW_WDR = 9,
+ ISS_SUB_SCENARIO_VIDEO_WDR = 10,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_WDR = 11,
+ ISS_SUB_SCENARIO_UHD_30FPS_WDR = 12,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_ZOOM = 13,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_ZOOM_OUTDOOR = 14,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_ZOOM_INDOOR = 15,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_WDR_ZOOM = 16,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_WDR_ZOOM_OUTDOOR = 17,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_WDR_ZOOM_INDOOR = 18,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_LLS = 19,
+ ISS_SUB_SCENARIO_STILL_CAPTURE_WDR_LLS = 20,
+ ISS_SUB_END,
+
+ /* These values will be deprecated */
+ ISS_SUB_SCENARIO_FRONT_VT1 = 4, /* 4: front camera VT1 for 3G (Temporary) */
+ ISS_SUB_SCENARIO_FRONT_VT2 = 5, /* 5: front camera VT2 for LTE (Temporary) */
+ ISS_SUB_SCENARIO_FRONT_SMART_STAY = 6, /* 6: front camera smart stay (Temporary) */
+ ISS_SUB_SCENARIO_FRONT_PANORAMA = 7, /* 7: front camera front panorama (Temporary) */
+};
+
+enum is_system_control_id {
+ IS_SYS_CLOCK_GATE = 0,
+ IS_SYS_END = 1,
+};
+
+enum is_system_control_cmd {
+ SYS_CONTROL_DISABLE = 0,
+ SYS_CONTROL_ENABLE = 1,
+};
+
+enum is_msg_test_id {
+ IS_MSG_TEST_SYNC_LOG = 1,
+};
+
+struct is_setfile_header_element {
+ u32 binary_addr;
+ u32 binary_size;
+};
+
+struct is_setfile_header {
+ struct is_setfile_header_element isp[ISS_END];
+ struct is_setfile_header_element drc[ISS_END];
+ struct is_setfile_header_element fd[ISS_END];
+};
+
+#define HOST_SET_INT_BIT 0x00000001
+#define HOST_CLR_INT_BIT 0x00000001
+#define IS_SET_INT_BIT 0x00000001
+#define IS_CLR_INT_BIT 0x00000001
+
+#define HOST_SET_INTERRUPT(base) (base->uiINTGR0 |= HOST_SET_INT_BIT)
+#define HOST_CLR_INTERRUPT(base) (base->uiINTCR0 |= HOST_CLR_INT_BIT)
+#define IS_SET_INTERRUPT(base) (base->uiINTGR1 |= IS_SET_INT_BIT)
+#define IS_CLR_INTERRUPT(base) (base->uiINTCR1 |= IS_CLR_INT_BIT)
+
+struct is_common_reg {
+ u32 hicmd;
+ u32 hic_sensorid;
+ u32 hic_param1;
+ u32 hic_param2;
+ u32 hic_param3;
+ u32 hic_param4;
+
+ u32 power_down_debug_number;
+
+ u32 reserved1[2];
+
+ u32 ihcmd_iflag;
+ u32 ihcmd;
+ u32 ihc_sensorid;
+ u32 ihc_param1;
+ u32 ihc_param2;
+ u32 ihc_param3;
+ u32 ihc_param4;
+
+ u32 reserved2[2];
+
+ u32 taa0c_iflag;
+ u32 taa0c_sensor_id;
+ u32 taa0c_param1;
+ u32 taa0c_param2;
+ u32 taa0c_param3;
+
+ u32 reserved3[2];
+
+ u32 taa1c_iflag;
+ u32 taa1c_sensor_id;
+ u32 taa1c_param1;
+ u32 taa1c_param2;
+ u32 taa1c_param3;
+
+ u32 reserved4[2];
+
+ u32 scc_iflag;
+ u32 scc_sensor_id;
+ u32 scc_param1;
+ u32 scc_param2;
+ u32 scc_param3;
+
+ u32 reserved5[2];
+
+ u32 dis_iflag;
+ u32 dis_sensor_id;
+ u32 dis_param1;
+ u32 dis_param2;
+ u32 dis_param3;
+
+ u32 reserved6[2];
+
+ u32 scp_iflag;
+ u32 scp_sensor_id;
+ u32 scp_param1;
+ u32 scp_param2;
+ u32 scp_param3;
+
+ u32 reserved7[3];
+
+ u32 shot_iflag;
+ u32 shot_sensor_id;
+ u32 shot_param1;
+ u32 shot_param2;
+ u32 shot_param3;
+
+ u32 grp1_done_frame_num;
+
+ u32 fcount_sen3;
+ u32 fcount_sen2;
+ u32 fcount_sen1;
+ u32 fcount_sen0;
+};
+
+struct is_mcuctl_reg {
+ u32 mcuctl;
+ u32 bboar;
+
+ u32 intgr0;
+ u32 intcr0;
+ u32 intmr0;
+ u32 intsr0;
+ u32 intmsr0;
+
+ u32 intgr1;
+ u32 intcr1;
+ u32 intmr1;
+ u32 intsr1;
+ u32 intmsr1;
+
+ u32 intcr2;
+ u32 intmr2;
+ u32 intsr2;
+ u32 intmsr2;
+
+ u32 gpoctrl;
+ u32 cpoenctlr;
+ u32 gpictlr;
+
+ u32 pad[0xD];
+
+ struct is_common_reg common_reg;
+};
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/sched.h>
+#include <mach/exynos-fimc-is-sensor.h>
+#include <mach/exynos-fimc-is.h>
+#include <media/exynos_mc.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+
+#include "fimc-is-dt.h"
+#include "fimc-is-companion-dt.h"
+
+#ifdef CONFIG_OF
+int fimc_is_sensor_parse_dt_with_companion(struct platform_device *pdev)
+{
+ int ret = 0;
+ u32 temp;
+ char *pprop;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ struct device *dev;
+ const char *name;
+ u32 id;
+
+ BUG_ON(!pdev);
+ BUG_ON(!pdev->dev.of_node);
+
+ dev = &pdev->dev;
+ dnode = dev->of_node;
+
+ pdata = kzalloc(sizeof(struct exynos_platform_fimc_is_sensor), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("%s: no memory for platform data\n", __func__);
+ return -ENOMEM;
+ }
+
+ pdata->gpio_cfg = exynos_fimc_is_sensor_pins_cfg;
+ pdata->iclk_cfg = exynos_fimc_is_sensor_iclk_cfg;
+ pdata->iclk_on = exynos_fimc_is_sensor_iclk_on;
+ pdata->iclk_off = exynos_fimc_is_sensor_iclk_off;
+ pdata->mclk_on = exynos_fimc_is_sensor_mclk_on;
+ pdata->mclk_off = exynos_fimc_is_sensor_mclk_off;
+
+ ret = of_property_read_u32(dnode, "scenario", &pdata->scenario);
+ if (ret) {
+ err("scenario read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "mclk_ch", &pdata->mclk_ch);
+ if (ret) {
+ err("mclk_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "csi_ch", &pdata->csi_ch);
+ if (ret) {
+ err("csi_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "flite_ch", &pdata->flite_ch);
+ if (ret) {
+ err("flite_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "i2c_ch", &pdata->i2c_ch);
+ if (ret) {
+ err("i2c_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "i2c_addr", &pdata->i2c_addr);
+ if (ret) {
+ err("i2c_addr read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "is_bns", &pdata->is_bns);
+ if (ret) {
+ err("is_bns read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "id", &id);
+ if (ret) {
+ err("id read is fail(%d)", ret);
+ goto p_err;
+ }
+ pdata->id = id;
+
+ DT_READ_U32(dnode, "flash_first_gpio", pdata->flash_first_gpio);
+ DT_READ_U32(dnode, "flash_second_gpio", pdata->flash_second_gpio);
+
+ ret = of_property_read_string(dnode, "sensor_name", &name);
+ if (ret) {
+ err("sensor_name read is fail(%d)", ret);
+ goto p_err;
+ }
+ strcpy(pdata->sensor_name, name);
+
+ ret = of_property_read_u32(dnode, "sensor_id", &pdata->sensor_id);
+ if (ret) {
+ err("sensor_id read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ dev->platform_data = pdata;
+
+ if (id == SENSOR_POSITION_REAR)
+ ret = fimc_is_power_initpin(dev);
+ else {
+ ret = fimc_is_power_setpin(dev, id, pdata->sensor_id);
+ }
+ if (ret)
+ err("power_setpin(or initpin) failed(%d). id %d", ret, id);
+
+ pdev->id = id;
+
+ pdata->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pdata->pinctrl)) {
+ err("devm_pinctrl_get is fail");
+ goto p_err;
+ } else {
+ ret = get_pin_lookup_state(dev, pdata);
+ if (ret < 0) {
+ err("fimc_is_get_pin_lookup_state is fail");
+ goto p_err;
+ }
+ }
+
+ return ret;
+p_err:
+ kfree(pdata);
+ return ret;
+}
+
+int fimc_is_companion_parse_dt(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ struct device *dev;
+
+ BUG_ON(!pdev);
+ BUG_ON(!pdev->dev.of_node);
+
+ dev = &pdev->dev;
+ dnode = dev->of_node;
+
+ pdata = kzalloc(sizeof(struct exynos_platform_fimc_is_sensor), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("%s: no memory for platform data\n", __func__);
+ return -ENOMEM;
+ }
+
+ pdata->gpio_cfg = exynos_fimc_is_sensor_pins_cfg;
+ pdata->iclk_cfg = exynos_fimc_is_companion_iclk_cfg;
+ pdata->iclk_on = exynos_fimc_is_companion_iclk_on;
+ pdata->iclk_off = exynos_fimc_is_companion_iclk_off;
+ pdata->mclk_on = exynos_fimc_is_companion_mclk_on;
+ pdata->mclk_off = exynos_fimc_is_companion_mclk_off;
+
+ ret = of_property_read_u32(dnode, "scenario", &pdata->scenario);
+ if (ret) {
+ err("scenario read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "mclk_ch", &pdata->mclk_ch);
+ if (ret) {
+ err("mclk_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ pdata->companion_use_pmic = of_property_read_bool(dnode, "companion_use_pmic");
+ if (!pdata->companion_use_pmic) {
+ err("use_pmic not use(%d)", pdata->companion_use_pmic);
+ }
+
+ ret = of_property_read_u32(dnode, "sensor_id", &pdata->sensor_id);
+ if (ret) {
+ err("sensor_id read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ dev->platform_data = pdata;
+
+ ret = fimc_is_power_setpin(dev, SENSOR_POSITION_REAR, pdata->sensor_id);
+ if (ret)
+ err("power_setpin failed(%d)", ret);
+
+ pdata->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pdata->pinctrl)) {
+ err("devm_pinctrl_get is fail");
+ goto p_err;
+ } else {
+ ret = get_pin_lookup_state(dev, pdata);
+ if (ret < 0) {
+ err("fimc_is_get_pin_lookup_state is fail");
+ goto p_err;
+ }
+ }
+
+ return ret;
+p_err:
+ kfree(pdata);
+ return ret;
+}
+#endif
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_COMPANION_DT_H
+#define FIMC_IS_COMPANION_DT_H
+
+int fimc_is_sensor_parse_dt_with_companion(struct platform_device *pdev);
+int fimc_is_companion_parse_dt(struct platform_device *pdev);
+#endif
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/platform_device.h>
+#include <linux/spi/spi.h>
+#include "fimc-is-sec-define.h"
+#include "fimc-is-companion.h"
+#include "fimc-is-device-ischain.h"
+#include "fimc-is-fan53555.h"
+#ifdef USE_ION_ALLOC
+#include <linux/dma-buf.h>
+#include <linux/exynos_ion.h>
+#include <linux/ion.h>
+#endif
+
+#define COMP_FW_EVT0 "companion_fw_evt0.bin"
+#define COMP_FW_EVT1 "companion_fw_evt1.bin"
+#define COMP_SETFILE_MASTER "companion_master_setfile.bin"
+#define COMP_SETFILE_MODE "companion_mode_setfile.bin"
+#define COMP_CAL_DATA "cal"
+#define COMP_LSC "lsc"
+#define COMP_PDAF "pdaf"
+#define COMP_COEF_CAL "coef"
+#define COMP_DEFAULT_LSC "companion_default_lsc.bin"
+#define COMP_DEFAULT_COEF "companion_default_coef.bin"
+
+#define COMP_SETFILE_VIRSION_SIZE 16
+#define COMP_MAGIC_NUMBER (0x73c1)
+#define FIMC_IS_COMPANION_LSC_SIZE 6600
+#define FIMC_IS_COMPANION_PDAF_SIZE 512
+#define FIMC_IS_COMPANION_COEF_TOTAL_SIZE (4096 * 6)
+#define FIMC_IS_COMPANION_LSC_I0_SIZE 2
+#define FIMC_IS_COMPANION_LSC_J0_SIZE 2
+#define FIMC_IS_COMPANION_LSC_A_SIZE 4
+#define FIMC_IS_COMPANION_LSC_K4_SIZE 4
+#define FIMC_IS_COMPANION_LSC_SCALE_SIZE 2
+#define FIMC_IS_COMPANION_WCOEF1_SIZE 10
+#define FIMC_IS_COMPANION_COEF_CAL_SIZE 4032
+#define FIMC_IS_COMPANION_AF_INF_SIZE 2
+#define FIMC_IS_COMPANION_AF_MACRO_SIZE 2
+#define LITTLE_ENDIAN 0
+#define BIG_ENDIAN 1
+extern bool companion_lsc_isvalid;
+extern bool companion_coef_isvalid;
+extern bool crc32_c1_check;
+static u16 companion_ver;
+static u32 concord_fw_size;
+char companion_crc[10];
+
+#if 1
+static int fimc_is_comp_spi_read(struct spi_device *spi,
+ void *buf, u16 rx_addr, size_t size)
+{
+ unsigned char req_data[4] = { 0x03, };
+ int ret;
+
+ struct spi_transfer t_c;
+ struct spi_transfer t_r;
+
+ struct spi_message m;
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ req_data[1] = (rx_addr & 0xFF00) >> 8;
+ req_data[2] = (rx_addr & 0xFF);
+
+ t_c.tx_buf = req_data;
+ t_c.len = 4;
+ t_c.cs_change = 1;
+ t_c.bits_per_word = 32;
+
+ t_r.rx_buf = buf;
+ t_r.len = size;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+ spi_message_add_tail(&t_r, &m);
+
+ ret = spi_sync(spi, &m);
+ if (ret) {
+ err("spi sync error - can't read data");
+ return -EIO;
+ } else
+ return 0;
+}
+#endif
+
+static int fimc_is_comp_spi_single_write(struct spi_device *spi, u16 addr, u16 data)
+{
+ int ret = 0;
+ u8 tx_buf[5];
+
+ tx_buf[0] = 0x02; /* write cmd */
+ tx_buf[1] = (addr >> 8) & 0xFF; /* address */
+ tx_buf[2] = (addr >> 0) & 0xFF; /* address */
+ tx_buf[3] = (data >> 8) & 0xFF; /* data */
+ tx_buf[4] = (data >> 0) & 0xFF; /* data */
+
+ ret = spi_write(spi, &tx_buf[0], 5);
+ if (ret)
+ err("spi sync error - can't read data");
+
+ return ret;
+}
+
+/* Burst mode: <command><address><data data data ...>
+ * Burst width: Maximun value is 512.
+ */
+static int fimc_is_comp_spi_burst_write(struct spi_device *spi,
+ u8 *buf, size_t size, size_t burst_width, int endian)
+{
+ int ret = 0;
+ u32 i = 0, j = 0;
+ u8 tx_buf[512];
+ size_t burst_size;
+
+ /* check multiples of 2 */
+ burst_width = (burst_width + 2 - 1) / 2 * 2;
+
+ burst_size = size / burst_width * burst_width;
+
+ for (i = 0; i < burst_size; i += burst_width) {
+ tx_buf[0] = 0x02; /* write cmd */
+ tx_buf[1] = 0x6F; /* address */
+ tx_buf[2] = 0x12; /* address */
+ if (endian == LITTLE_ENDIAN) {
+ for (j = 0; j < burst_width; j++)
+ tx_buf[j + 3] = *(buf + i + j); /* data for big endian */
+ } else if (endian == BIG_ENDIAN) {
+ for (j = 0; j < burst_width; j += 2) {
+ tx_buf[j + 3] = *(buf + i + j + 1); /* data for little endian */
+ tx_buf[j + 4] = *(buf + i + j);
+ }
+ }
+
+ ret = spi_write(spi, &tx_buf[0], j + 3);
+ if (ret) {
+ err("spi write error - can't write data");
+ goto p_err;
+ }
+ }
+
+ tx_buf[0] = 0x02; /* write cmd */
+ tx_buf[1] = 0x6F; /* address */
+ tx_buf[2] = 0x12; /* address */
+ if (endian == LITTLE_ENDIAN) {
+ for (j = 0; j < (size - burst_size); j ++) {
+ tx_buf[j + 3] = *(buf + i + j); /* data for big endian */
+ }
+ } else if (endian == BIG_ENDIAN) {
+ for (j = 0; j < (size - burst_size); j += 2) {
+ tx_buf[j + 3] = *(buf + i + j + 1); /* data for little endian */
+ tx_buf[j + 4] = *(buf + i + j);
+ }
+ }
+
+ ret = spi_write(spi, &tx_buf[0], j + 3);
+ if (ret)
+ err("spi write error - can't write data");
+
+
+p_err:
+ return ret;
+}
+
+#if 0
+static int fimc_is_comp_i2c_read(struct i2c_client *client, u16 addr, u16 *data)
+{
+ int err;
+ u8 rxbuf[2], txbuf[2];
+ struct i2c_msg msg[2];
+
+ rxbuf[0] = (addr & 0xff00) >> 8;
+ rxbuf[1] = (addr & 0xff);
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = rxbuf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = txbuf;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (unlikely(err != 2)) {
+ pr_err("%s: register read fail\n", __func__);
+ return -EIO;
+ }
+
+ *data = ((txbuf[0] << 8) | txbuf[1]);
+ return 0;
+}
+#endif
+
+#ifndef USE_SPI
+static int fimc_is_comp_i2c_write(struct i2c_client *client ,u16 addr, u16 data)
+{
+ int retries = I2C_RETRY_COUNT;
+ int ret = 0, err = 0;
+ u8 buf[4] = {0,};
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 4,
+ .buf = buf,
+ };
+
+ buf[0] = addr >> 8;
+ buf[1] = addr;
+ buf[2] = data >> 8;
+ buf[3] = data & 0xff;
+
+#if 0
+ pr_info("%s : W(0x%02X%02X%02X%02X)\n",__func__, buf[0], buf[1], buf[2], buf[3]);
+#endif
+
+ do {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (likely(ret == 1))
+ break;
+
+ usleep_range(10000,11000);
+ err = ret;
+ } while (--retries > 0);
+
+ /* Retry occured */
+ if (unlikely(retries < I2C_RETRY_COUNT)) {
+ pr_err("i2c_write: error %d, write (%04X, %04X), retry %d\n",
+ err, addr, data, I2C_RETRY_COUNT - retries);
+ }
+
+ if (unlikely(ret != 1)) {
+ pr_err("I2C does not work\n\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+#endif
+
+static int fimc_is_comp_single_write(struct fimc_is_core *core , u16 addr, u16 data)
+{
+ int ret = 0;
+#ifdef USE_SPI
+ struct spi_device *spi = core->spi1;
+ ret = fimc_is_comp_spi_single_write(spi, addr, data);
+ if (ret) {
+ err("spi_single_write() fail");
+ }
+#else
+ struct i2c_client *client = core->client0;
+ fimc_is_s_int_comb_isp(core, true, INTMR2_INTMCIS22); /* interrupt on */
+ ret = fimc_is_comp_i2c_write(client, addr, data);
+ if (ret) {
+ err("i2c write fail");
+ }
+ fimc_is_s_int_comb_isp(core, false, INTMR2_INTMCIS22); /* interrupt off */
+#endif
+
+ return ret;
+}
+
+static int fimc_is_comp_single_read(struct fimc_is_core *core , u16 addr, u16 *data, size_t size)
+{
+ int ret = 0;
+//#ifdef USE_SPI
+#if 1
+ struct spi_device *spi = core->spi1;
+ ret = fimc_is_comp_spi_read(spi, (void *)data, addr, size);
+ if (ret) {
+ err("spi_single_read() fail");
+ }
+ *data = *data << 8 | *data >> 8;
+#else
+ struct i2c_client *client = core->client0;
+ fimc_is_s_int_comb_isp(core, true, INTMR2_INTMCIS22); /* I2C0 interrupt on */
+ ret = fimc_is_comp_i2c_read(client, addr, data);
+ if (ret) {
+ err("i2c read fail");
+ }
+ fimc_is_s_int_comb_isp(core, false, INTMR2_INTMCIS22); /* I2C0 interrupt off */
+#endif
+
+ return ret;
+}
+
+static int fimc_is_comp_check_crc32(struct fimc_is_core *core, char *name)
+{
+ int ret = 0;
+ int retries = CRC_RETRY_COUNT;
+ u32 checksum, from_checksum = 0;
+ u16 addr1, addr2, read_addr, data_size1, data_size2;
+ u16 result_data, cmd_data, temp_data;
+ struct fimc_is_from_info *sysfs_finfo;
+ char *cal_buf;
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ fimc_is_sec_get_cal_buf(&cal_buf);
+
+ if (!strcmp(name, COMP_LSC)) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_LSC_SIZE;
+ addr1 = 0x2001;
+ addr2 = 0xA000;
+ if (companion_lsc_isvalid)
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->lsc_gain_crc_addr]);
+ else
+ from_checksum = 0x043DC8F8;
+ } else if (!strcmp(name, COMP_PDAF)) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_PDAF_SIZE;
+ addr1 = 0x2000;
+ addr2 = 0xB900;
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->pdaf_crc_addr]);
+ } else if (!strcmp(name, COMP_FW_EVT1) || !strcmp(name, COMP_FW_EVT0)) {
+ concord_fw_size = concord_fw_size - 4;
+ data_size1 = (concord_fw_size >> 16) & 0xFFFF;
+ data_size2 = concord_fw_size & 0xFFFF;
+ addr1 = 0x0000;
+ addr2 = 0x0000;
+ from_checksum = *((u32 *)&companion_crc[0]);
+ } else if (!strcmp(name, COMP_COEF_CAL)) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_COEF_CAL_SIZE;
+ addr1 = 0x2001;
+ addr2 = 0x0000;
+ if (companion_coef_isvalid)
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->coef1_crc_addr]);
+ else
+ from_checksum = 0x98E85DAC;
+ } else if (!strcmp(name, "coef2")) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_COEF_CAL_SIZE;
+ addr1 = 0x2001;
+ addr2 = 0x1000;
+ if (companion_coef_isvalid)
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->coef2_crc_addr]);
+ else
+ from_checksum = 0x88358F49;
+ } else if (!strcmp(name, "coef3")) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_COEF_CAL_SIZE;
+ addr1 = 0x2001;
+ addr2 = 0x2000;
+ if (companion_coef_isvalid)
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->coef3_crc_addr]);
+ else
+ from_checksum = 0x138AF2AB;
+ } else if (!strcmp(name, "coef4")) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_COEF_CAL_SIZE;
+ addr1 = 0x2001;
+ addr2 = 0x3000;
+ if (companion_coef_isvalid)
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->coef4_crc_addr]);
+ else
+ from_checksum = 0x4447017A;
+ } else if (!strcmp(name, "coef5")) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_COEF_CAL_SIZE;
+ addr1 = 0x2001;
+ addr2 = 0x4000;
+ if (companion_coef_isvalid)
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->coef5_crc_addr]);
+ else
+ from_checksum = 0xDBB05433;
+ } else if (!strcmp(name, "coef6")) {
+ data_size1 = 0;
+ data_size2 = FIMC_IS_COMPANION_COEF_CAL_SIZE;
+ addr1 = 0x2001;
+ addr2 = 0x5000;
+ if (companion_coef_isvalid)
+ from_checksum = *((u32 *)&cal_buf[sysfs_finfo->coef6_crc_addr]);
+ else
+ from_checksum = 0x66064DFA;
+ } else {
+ err("wrong companion cal data name\n");
+ return -EINVAL;
+ }
+
+ ret = fimc_is_comp_single_write(core, 0x0024, 0x0000);
+ ret |= fimc_is_comp_single_write(core, 0x0026, 0x0000);//clear result register
+ ret |= fimc_is_comp_single_write(core, 0x0014, addr1);
+ ret |= fimc_is_comp_single_write(core, 0x0016, addr2);// source address
+ ret |= fimc_is_comp_single_write(core, 0x0018, data_size1);
+ ret |= fimc_is_comp_single_write(core, 0x001A, data_size2);//source size
+ ret |= fimc_is_comp_single_write(core, 0x000C, 0x000C);
+ ret |= fimc_is_comp_single_write(core, 0x6806, 0x0001);//interrupt on
+ if (ret) {
+ err("fimc_is_comp_check_crc32() i2c write fail");
+ return -EIO;
+ }
+
+ read_addr = 0x000C;
+ do {
+ fimc_is_comp_single_read(core, read_addr, &cmd_data, 2);
+ usleep_range(500, 500);
+ if (--retries < 0) {
+ err("Read register failed!!!!, data = 0x%04x\n", cmd_data);
+ break;
+ }
+ } while (cmd_data);
+ read_addr = 0x0024;
+ fimc_is_comp_single_read(core, read_addr, &result_data, 2);
+ read_addr = 0x0026;
+ fimc_is_comp_single_read(core, read_addr, &temp_data, 2);
+
+ checksum = result_data << 16 | temp_data;
+ if (checksum != from_checksum) {
+ err("[%s] CRC check is failed. Checksum = 0x%08x, FROM checksum = 0x%08x\n",
+ name, checksum, from_checksum);
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static int fimc_is_comp_load_binary(struct fimc_is_core *core, char *name)
+{
+ int ret = 0;
+ u32 size = 0;
+ const struct firmware *fw_blob = NULL;
+ static char fw_name[100];
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long nread;
+ int fw_requested = 1;
+ u32 i;
+ u8 *buf = NULL;
+ u32 data, cal_addr;
+ char version_str[60];
+ u16 addr1, addr2;
+ char companion_ver[12] = {0, };
+ struct fimc_is_from_info *sysfs_finfo;
+#ifdef USE_ION_ALLOC
+ struct ion_handle *handle = NULL;
+#endif
+ int retry_count = 0;
+
+ BUG_ON(!core);
+ BUG_ON(!core->pdev);
+ BUG_ON(!core->companion);
+ BUG_ON(!core->companion->pdev);
+ BUG_ON(!name);
+#ifdef USE_ION_ALLOC
+ BUG_ON(!core->fimc_ion_client);
+#endif
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ snprintf(fw_name, sizeof(fw_name), "%s%s",FIMC_IS_SETFILE_SDCARD_PATH, name);
+ fp = filp_open(fw_name, O_RDONLY, 0);
+ if (IS_ERR_OR_NULL(fp)) {
+ goto request_fw;
+ }
+
+ fw_requested = 0;
+ size = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start read sdcard, file path %s, size %d Bytes\n", fw_name, size);
+
+#ifdef USE_ION_ALLOC
+ handle = ion_alloc(core->fimc_ion_client, (size_t)size, 0,
+ EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ err("fimc_is_comp_load_binary:failed to ioc_alloc\n");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ buf = (u8 *)ion_map_kernel(core->fimc_ion_client, handle);
+ if (IS_ERR_OR_NULL(buf)) {
+ err("fimc_is_comp_load_binary:fail to ion_map_kernle\n");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+#else
+ buf = vmalloc(size);
+ if (!buf) {
+ err("failed to allocate memory");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+#endif
+
+ nread = vfs_read(fp, (char __user *)buf, size, &fp->f_pos);
+ if (nread != size) {
+ err("failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto p_err;
+ }
+ if ((!strcmp(name, COMP_FW_EVT0)) || (!strcmp(name, sysfs_finfo->load_c1_fw_name))) {
+ strncpy(companion_crc, buf+nread-4, 4);
+ strncpy(companion_ver, buf+nread - 16, 11);
+ }
+
+request_fw:
+ if (fw_requested) {
+ snprintf(fw_name, sizeof(fw_name), "%s", name);
+ set_fs(old_fs);
+ retry_count = 3;
+ ret = request_firmware(&fw_blob, fw_name, &core->companion->pdev->dev);
+ while (--retry_count && ret == -EAGAIN) {
+ err("request_firmware retry(count:%d)", retry_count);
+ ret = request_firmware(&fw_blob, fw_name, &core->companion->pdev->dev);
+ }
+
+ if (ret) {
+ err("request_firmware is fail(ret:%d)", ret);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!fw_blob) {
+ err("fw_blob is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!fw_blob->data) {
+ err("fw_blob->data is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ size = fw_blob->size;
+#ifdef USE_ION_ALLOC
+ handle = ion_alloc(core->fimc_ion_client, (size_t)size, 0,
+ EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ err("fimc_is_comp_load_binary:failed to ioc_alloc\n");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ buf = (u8 *)ion_map_kernel(core->fimc_ion_client, handle);
+ if (IS_ERR_OR_NULL(buf)) {
+ err("fimc_is_comp_load_binary:fail to ion_map_kernle\n");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+#else
+ buf = vmalloc(size);
+ if (!buf) {
+ err("failed to allocate memory");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+#endif
+ memcpy((void *)buf, fw_blob->data, size);
+ if ((!strcmp(name, COMP_FW_EVT0)) || (!strcmp(name, sysfs_finfo->load_c1_fw_name))) {
+ memcpy((void *)companion_crc, fw_blob->data + size - 4, 4);
+ memcpy((void *)companion_ver, fw_blob->data + size - 16, 11);
+ }
+ }
+
+ if (!strcmp(name, COMP_FW_EVT0)) {
+ ret = fimc_is_comp_spi_burst_write(core->spi1, buf, size, 256, LITTLE_ENDIAN);
+ if (ret) {
+ err("fimc_is_comp_spi_write() fail");
+ goto p_err;
+ }
+ concord_fw_size = size;
+ info("%s version : %s\n", name, companion_ver);
+ } else if (!strcmp(name, sysfs_finfo->load_c1_fw_name)) {
+ ret = fimc_is_comp_spi_burst_write(core->spi1, buf, size, 256, LITTLE_ENDIAN);
+ if (ret) {
+ err("fimc_is_comp_spi_write() fail");
+ goto p_err;
+ }
+ concord_fw_size = size;
+ info("%s version : %s\n", name, companion_ver);
+ } else if (!strcmp(name, COMP_DEFAULT_LSC)) {
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ cal_addr = MEM_GRAS_B_IMX240;
+ } else {
+ cal_addr = MEM_GRAS_B_2P2;
+ }
+ addr1 = (cal_addr >> 16) & 0xFFFF;
+ addr2 = cal_addr & 0xFFFF;
+ ret = fimc_is_comp_single_write(core, 0x6428, addr1);
+ if (ret) {
+ err("fimc_is_comp_load_cal() write fail");
+ }
+ ret = fimc_is_comp_single_write(core, 0x642A, addr2);
+ if (ret) {
+ err("fimc_is_comp_load_cal() write fail");
+ }
+ ret = fimc_is_comp_spi_burst_write(core->spi1, buf, size, 256, BIG_ENDIAN);
+ if (ret) {
+ err("fimc_is_comp_spi_write() fail");
+ goto p_err;
+ }
+ } else if (!strcmp(name, COMP_DEFAULT_COEF)) {
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ cal_addr = MEM_XTALK_10_IMX240;
+ } else {
+ cal_addr = MEM_XTALK_10_2P2;
+ }
+ addr1 = (cal_addr >> 16) & 0xFFFF;
+ addr2 = cal_addr & 0xFFFF;
+ ret = fimc_is_comp_single_write(core, 0x6428, addr1);
+ if (ret) {
+ err("fimc_is_comp_load_cal() write fail");
+ }
+ ret = fimc_is_comp_single_write(core, 0x642A, addr2);
+ if (ret) {
+ err("fimc_is_comp_load_cal() write fail");
+ }
+ ret = fimc_is_comp_spi_burst_write(core->spi1, buf, size, 256, LITTLE_ENDIAN);
+ if (ret) {
+ err("fimc_is_comp_spi_write() fail");
+ goto p_err;
+ }
+ } else {
+ u32 offset = size - COMP_SETFILE_VIRSION_SIZE;
+ for (i = 0; i < offset; i += 4) {
+ data = *(buf + i + 0) << 24 |
+ *(buf + i + 1) << 16 |
+ *(buf + i + 2) << 8 |
+ *(buf + i + 3) << 0;
+ if(!strcmp(name, sysfs_finfo->load_c1_mastersetf_name)) {
+ ret = fimc_is_comp_spi_single_write(core->spi1, (data >> 16), (u16)data);
+ if (ret) {
+ err("fimc_is_comp_spi_setf_write() fail");
+ break;
+ }
+ } else {
+ ret = fimc_is_comp_single_write(core, (data >> 16), (u16)data);
+ if (ret) {
+ err("fimc_is_comp_write() fail");
+ break;
+ }
+ }
+ }
+
+ memcpy(version_str, buf + offset, COMP_SETFILE_VIRSION_SIZE);
+ version_str[COMP_SETFILE_VIRSION_SIZE] = '\0';
+
+ info("%s version : %s\n", name, version_str);
+ }
+
+p_err:
+#ifdef USE_ION_ALLOC
+ if (!IS_ERR_OR_NULL(buf)) {
+ ion_unmap_kernel(core->fimc_ion_client, handle);
+ }
+
+ if (!IS_ERR_OR_NULL(handle)) {
+ ion_free(core->fimc_ion_client, handle);
+ }
+#else
+ if (buf) {
+ vfree(buf);
+ }
+#endif
+ if (!fw_requested) {
+ if (!IS_ERR_OR_NULL(fp)) {
+ filp_close(fp, current->files);
+ }
+ set_fs(old_fs);
+ } else {
+ if (!IS_ERR_OR_NULL(fw_blob)) {
+ release_firmware(fw_blob);
+ }
+ }
+ return ret;
+}
+
+static int fimc_is_comp_load_cal(struct fimc_is_core *core, char *name)
+{
+
+ int ret = 0, endian;
+ u32 data_size = 0, offset;
+ struct fimc_is_from_info *sysfs_finfo;
+ char *cal_buf;
+ u16 data1, data2;
+ u32 comp_addr = 0;
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ fimc_is_sec_get_cal_buf(&cal_buf);
+ pr_info("Camera: SPI write cal data, name = %s\n", name);
+
+ if (!strcmp(name, COMP_LSC)) {
+ data_size = FIMC_IS_COMPANION_LSC_SIZE;
+ offset = sysfs_finfo->lsc_gain_start_addr;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = MEM_GRAS_B_IMX240;
+ } else {
+ comp_addr = MEM_GRAS_B_2P2;
+ }
+ endian = BIG_ENDIAN;
+ } else if (!strcmp(name, COMP_PDAF)) {
+ data_size = FIMC_IS_COMPANION_PDAF_SIZE;
+ offset = sysfs_finfo->pdaf_start_addr;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = MEM_AF_10_1_IMX240;
+ } else {
+ comp_addr = MEM_AF_10_1_2P2;
+ }
+ endian = LITTLE_ENDIAN;
+ } else if (!strcmp(name, COMP_COEF_CAL)) {
+ data_size = FIMC_IS_COMPANION_COEF_TOTAL_SIZE;
+ offset = sysfs_finfo->coef1_start;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = MEM_XTALK_10_IMX240;
+ } else {
+ comp_addr = MEM_XTALK_10_2P2;
+ }
+ endian = LITTLE_ENDIAN;
+ } else {
+ err("wrong companion cal data name\n");
+ return -EINVAL;
+ }
+ data1 = comp_addr >> 16;
+ data2 = (u16)comp_addr;
+ ret = fimc_is_comp_single_write(core, 0x6428, data1);
+ if (ret) {
+ err("fimc_is_comp_load_cal() i2c write fail");
+ }
+ ret = fimc_is_comp_single_write(core, 0x642A, data2);
+ if (ret) {
+ err("fimc_is_comp_load_cal() i2c write fail");
+ }
+
+ ret = fimc_is_comp_spi_burst_write(core->spi1, cal_buf + offset, data_size, 256, endian);
+ if (ret) {
+ err("fimc_is_comp_spi_write_cal() fail\n");
+ }
+ return ret;
+}
+
+#if 0
+static int fimc_is_comp_read_i2c_cal(struct fimc_is_core *core, u32 addr)
+{
+ int ret = 0;
+ u32 i,data_size = 0;
+ u16 data1, data2;
+ u8 read_data[2];
+
+ struct fimc_is_from_info *sysfs_finfo;
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+
+ fimc_is_s_int_comb_isp(core, true, INTMR2_INTMCIS22); /* interrupt on */
+ if (addr == sysfs_finfo->lsc_i0_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_I0_SIZE;
+ data1 = 0x0EF8;
+ } else if (addr == sysfs_finfo->lsc_j0_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_J0_SIZE;
+ data1 = 0x0EFA;
+ } else if (addr == sysfs_finfo->lsc_a_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_A_SIZE;
+ data1 = 0x0F00;
+ } else if (addr == sysfs_finfo->lsc_k4_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_K4_SIZE;
+ data1 = 0x0F04;
+ } else if (addr == sysfs_finfo->lsc_scale_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_SCALE_SIZE;
+ data1 = 0x0F08;
+ } else if (addr == sysfs_finfo->wcoefficient1_addr) {
+ data_size = FIMC_IS_COMPANION_WCOEF1_SIZE;
+ data1 = 0x1420;
+ } else {
+ err("wrong companion cal data addr\n");
+ return -EINVAL;
+ }
+ pr_info("===Camera: I2C read cal data, addr [0x%04x], size(%d)\n", addr,data_size);
+ ret = fimc_is_comp_i2c_write(core->client0, 0x642C, 0x4000);
+ if (ret) {
+ err("fimc_is_comp_load_i2c_cal() i2c write fail");
+ }
+ ret = fimc_is_comp_i2c_write(core->client0, 0x642E, data1);
+ if (ret) {
+ err("fimc_is_comp_load_i2c_cal() i2c write fail");
+ }
+
+ for (i = 0; i < data_size; i += 2) {
+ fimc_is_comp_spi_read(core->spi1, (void *)read_data, data1, 2);
+ data2 = read_data[0] << 8 | read_data[1] << 0;
+// pr_info("===Camera: I2C read addr[0x%04x],data[0x%04x]\n", data1,data2);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ break;
+ }
+ data1 += 2;
+ }
+
+ fimc_is_s_int_comb_isp(core, false, INTMR2_INTMCIS22); /* interrupt off */
+
+ return ret;
+}
+#endif
+
+static int fimc_is_comp_load_i2c_cal(struct fimc_is_core *core, u32 addr)
+{
+ int ret = 0;
+ u8 *buf = NULL;
+ u32 i, j, data_size = 0;
+ u16 data1, data2, data3 = 0, data4 = 0xFFFF;
+ u32 comp_addr = 0;
+
+ struct fimc_is_from_info *sysfs_finfo;
+ char *cal_buf;
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ fimc_is_sec_get_cal_buf(&cal_buf);
+
+ if (addr == sysfs_finfo->lsc_i0_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_I0_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = grasTuning_uParabolicCenterX_IMX240;
+ } else {
+ comp_addr = grasTuning_uParabolicCenterX_2P2;
+ }
+ if (!companion_lsc_isvalid)
+ data3 = 0x780A;
+ } else if (addr == sysfs_finfo->lsc_j0_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_J0_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = grasTuning_uParabolicCenterY_IMX240;
+ } else {
+ comp_addr = grasTuning_uParabolicCenterY_2P2;
+ }
+ if (!companion_lsc_isvalid)
+ data3 = 0xEC05;
+ } else if (addr == sysfs_finfo->lsc_a_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_A_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = grasTuning_uBiQuadFactorA_IMX240;
+ } else {
+ comp_addr = grasTuning_uBiQuadFactorA_2P2;
+ }
+ if (!companion_lsc_isvalid) {
+ data3 = 0x6A2A;
+ data4 = 0x0100;
+ }
+ } else if (addr == sysfs_finfo->lsc_k4_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_K4_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = grasTuning_uBiQuadFactorB_IMX240;
+ } else {
+ comp_addr = grasTuning_uBiQuadFactorB_2P2;
+ }
+ if (!companion_lsc_isvalid) {
+ data3 = 0x0040;
+ data4 = 0x0000;
+ }
+ } else if (addr == sysfs_finfo->lsc_scale_gain_addr) {
+ data_size = FIMC_IS_COMPANION_LSC_SCALE_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = grasTuning_uBiQuadScaleShiftAdder_IMX240;
+ } else {
+ comp_addr = grasTuning_uBiQuadScaleShiftAdder_2P2;
+ }
+ if (!companion_lsc_isvalid)
+ data3 = 0x0600;
+ } else if (addr == sysfs_finfo->wcoefficient1_addr) {
+ data_size = FIMC_IS_COMPANION_WCOEF1_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = xtalkTuningParams_wcr_IMX240;
+ } else {
+ comp_addr = xtalkTuningParams_wcr_2P2;
+ }
+ } else if (addr == sysfs_finfo->af_inf_addr) {
+ data_size = FIMC_IS_COMPANION_AF_INF_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = grasTuning_actuatorPositionToShadingPowerLut_0_IMX240;
+ } else {
+ comp_addr = grasTuning_actuatorPositionToShadingPowerLut_0_2P2;
+ }
+ } else if (addr == sysfs_finfo->af_macro_addr) {
+ data_size = FIMC_IS_COMPANION_AF_MACRO_SIZE;
+ if (sysfs_finfo->sensor_id == COMPANION_SENSOR_IMX240) {
+ comp_addr = grasTuning_actuatorPositionToShadingPowerLut_9_IMX240;
+ } else {
+ comp_addr = grasTuning_actuatorPositionToShadingPowerLut_9_2P2;
+ }
+ } else {
+ err("wrong companion cal data name\n");
+ return -EINVAL;
+ }
+ data1 = comp_addr >> 16;
+ data2 = (u16)comp_addr;
+
+ ret = fimc_is_comp_single_write(core, 0x6028, data1);
+ if (ret) {
+ err("fimc_is_comp_load_i2c_cal() i2c write fail");
+ }
+ ret = fimc_is_comp_single_write(core, 0x602A, data2);
+ if (ret) {
+ err("fimc_is_comp_load_i2c_cal() i2c write fail");
+ }
+
+ buf = cal_buf + addr;
+ if (addr == sysfs_finfo->af_inf_addr || addr == sysfs_finfo->af_macro_addr) {
+ data3 = *((u16 *)buf) / 2;
+ ret = fimc_is_comp_single_write(core, data2, data3);
+ } else {
+ if (addr == sysfs_finfo->wcoefficient1_addr) {
+ if (companion_coef_isvalid) {
+ for (i = 0; i < data_size; i += 2) {
+ data3 = (*(buf + i + 1) << 8) | (*(buf + i));
+ ret = fimc_is_comp_single_write(core, data2, data3);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ break;
+ }
+ data2 += 2;
+ }
+ } else {
+ ret = fimc_is_comp_single_write(core, data2, 0x0203);
+ ret |= fimc_is_comp_single_write(core, data2 + 2, 0xB902);
+ ret |= fimc_is_comp_single_write(core, data2 + 4, 0xA903);
+ ret |= fimc_is_comp_single_write(core, data2 + 6, 0x2900);
+ ret |= fimc_is_comp_single_write(core, data2 + 8, 0x4900);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+ }
+ } else {
+ if (companion_lsc_isvalid) {
+ j = data_size - 1;
+ for (i = 0; i < data_size; i += 2) {
+ data3 = (*(buf + j) << 8) | (*(buf + j - 1));
+ ret = fimc_is_comp_single_write(core, data2, data3);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ break;
+ }
+ data2 += 2;
+ j -= 2;
+ }
+ } else {
+ ret = fimc_is_comp_single_write(core, data2, data3);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+ if (data4 != 0xFFFF) {
+ data2 += 2;
+ ret = fimc_is_comp_single_write(core, data2, data4);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+ }
+ }
+ }
+ }
+// ret = fimc_is_comp_read_i2c_cal(core, addr);
+ return ret;
+}
+
+int fimc_is_power_binning(struct fimc_is_core *core)
+{
+ int ret = 0;
+ int err_check = 0, vout_sel = 0;
+ u16 read_value = 0x80;
+ int vout = 0;
+ char buf[2]={0,};
+ loff_t pos = 0;
+ char *dcdc_name;
+ struct dcdc_power *dcdc = &core->companion_dcdc;
+
+ if (DCDC_VENDOR_NONE == dcdc->type) {
+ pr_err("%s: warning, DCDC power not exist\n", __func__);
+ return -ENODEV;
+ } else {
+ dcdc_name = (DCDC_VENDOR_FAN53555 == dcdc->type) ? "FAN" :
+ (DCDC_VENDOR_NCP6335B == dcdc->type) ? "NCP" : "Unkknown";
+ }
+
+ /*read BIN_INFO 0x5000 500C*/
+#if 0
+ ret = fimc_is_comp_single_write(core, 0x602C, 0x5000);
+ if (ret)
+ err("fimc_is_comp_i2c_setf_write() fail");
+ ret = fimc_is_comp_single_write(core, 0x602E, 0x500C);
+ if (ret)
+ err("fimc_is_comp_i2c_setf_write() fail");
+#endif
+
+ ret = read_data_from_file(FIMC_IS_ISP_CV, buf, 1, &pos);
+ if(ret > 0) {
+ if (kstrtoint(buf, 10, &vout_sel))
+ pr_err("%s: error, convert fail\n", __func__);
+
+ vout = dcdc->get_vout_val(vout_sel);
+ ret = dcdc->set_vout(dcdc->client, vout);
+ if (ret < 0 )
+ pr_err("%s: error, dcdc set_vout(%d). sel %d\n", __func__, ret, vout_sel);
+
+ pr_info("[%s::%d][BIN_INFO::%s, sel %d] read path(%s), DCDC %s\n",
+ __FUNCTION__, __LINE__, buf, vout_sel, FIMC_IS_ISP_CV, dcdc_name);
+ return vout_sel;
+ }
+
+ ret = fimc_is_comp_spi_single_write(core->spi1, 0x642C, 0x5000);
+ if (ret) {
+ err_check = 1;
+ err("spi_single_write() fail");
+ }
+
+ ret = fimc_is_comp_spi_single_write(core->spi1, 0x642E, 0x500C);
+ if (ret) {
+ err_check = 1;
+ err("spi_single_write() fail");
+ }
+
+ ret = fimc_is_comp_single_read(core, 0x6F12, &read_value, 2);
+ if (ret) {
+ err_check = 1;
+ err("fimc_is_comp_single_read() fail");
+ }
+
+ pr_info("[%s::%d][BIN_INFO::0x%04x]\n", __FUNCTION__, __LINE__, read_value);
+
+ if (read_value & 0x3F) {
+ if (read_value & (1<<CC_BIN6)) {
+ buf[0]='6';
+ } else if (read_value & (1<<CC_BIN5)) {
+ buf[0]='5';
+ } else if (read_value & (1<<CC_BIN4)) {
+ buf[0]='4';
+ } else if (read_value & (1<<CC_BIN3)) {
+ buf[0]='3';
+ } else if (read_value & (1<<CC_BIN2)) {
+ buf[0]='2';
+ } else if (read_value & (1<<CC_BIN1)) {
+ buf[0]='1';
+ } else {
+ buf[0]='6';
+ }
+ } else {
+ buf[0]='6';
+ err_check = 1;
+ }
+ if (kstrtoint(buf, 10, &vout_sel))
+ pr_err("%s: error, convert fail\n", __func__);
+
+ vout = dcdc->get_vout_val(vout_sel);
+ ret = dcdc->set_vout(dcdc->client, vout);
+ if (ret < 0)
+ pr_err("%s: error, dcdc set_vout(%d), sel %d\n", __func__, ret, vout_sel);
+
+ if (err_check == 0) {
+ ret = write_data_to_file(FIMC_IS_ISP_CV, buf, 1, &pos);
+ if (ret < 0)
+ pr_err("bin_info_file_write() fail(%s)",buf);
+ }
+
+ pr_info("[%s::%d][BIN_INFO::0x%04x] buf(%s) write. sel %d, DCDC %s\n",
+ __FUNCTION__, __LINE__, read_value,buf, vout_sel, dcdc_name);
+
+ return vout_sel;
+}
+
+int fimc_is_comp_is_valid(struct fimc_is_core *core)
+{
+ int ret = 0;
+ u16 companion_id = 0, read_addr = 0;
+
+ if (!core->spi1) {
+ pr_info("spi1 device is not available");
+ goto exit;
+ }
+
+ /* check validation(Read data must be 0x73C1) */
+ read_addr = 0x0;
+ fimc_is_comp_single_read(core, read_addr, &companion_id, 2);
+ pr_info("Companion vaildation: 0x%04x\n", companion_id);
+#if 0
+#if defined(CONFIG_SOC_EXYNOS5430)
+ if (companion_id != COMP_MAGIC_NUMBER)
+ ret = -EINVAL;
+#endif
+#endif
+exit:
+ return ret;
+}
+
+int fimc_is_comp_read_ver(struct fimc_is_core *core)
+{
+ int ret = 0;
+#if 0
+ u16 read_addr;
+#endif
+
+ if (!core->spi1) {
+ pr_info("spi1 device is not available");
+ goto exit;
+ }
+
+ /* check validation(Read data must be 0x73C1) */
+#if 0
+ read_addr = 0x02;
+ fimc_is_comp_single_read(core, read_addr, &companion_ver, 2);
+#else
+ companion_ver = 0x00B0;
+ pr_info("Default Companion Version is 0x00B0(EVT1)\n");
+#endif
+
+ if (companion_ver == 0x00A0) {
+ pr_info("Companion version: 0x%04x\n", companion_ver);
+ ret = fimc_is_comp_single_write(core, 0x0256, 0x0001);
+ } else if (companion_ver == 0x00B0) {
+ pr_info("Companion version: 0x%04x\n", companion_ver);
+ ret = fimc_is_comp_single_write(core, 0x0122, 0x0001);
+ }
+ if (ret)
+ err("fimc_is_comp_read_ver() fail");
+
+exit:
+ return ret;
+}
+
+u8 fimc_is_comp_is_compare_ver(struct fimc_is_core *core)
+{
+ u8 ret = 0;
+ u32 from_ver = 0, def_ver = 0;
+ char *cal_buf;
+ char ver[3] = {'V', '0', '0'};
+
+ fimc_is_sec_get_cal_buf(&cal_buf);
+
+ if (!core->spi1) {
+ pr_info("spi1 device is not available");
+ goto exit;
+ }
+
+ def_ver = ver[0] << 16 | ver[1] << 8 | ver[2];
+ from_ver = cal_buf[96] << 16 | cal_buf[97] << 8 | cal_buf[98];
+ if (from_ver == def_ver) {
+ return cal_buf[99];
+ } else {
+ pr_err("FROM core version is invalid. version is %c%c%c%c\n", cal_buf[96], cal_buf[97], cal_buf[98], cal_buf[99]);
+ return 0;
+ }
+exit:
+ return ret;
+}
+
+int fimc_is_comp_loadcal(struct fimc_is_core *core)
+{
+ int ret = 0;
+ struct fimc_is_from_info *sysfs_finfo;
+ bool pdaf_valid = false;
+ int retry_count = 3;
+
+ if (!crc32_c1_check) {
+ pr_debug("CRC check fail.Do not apply cal data.");
+ return 0;
+ }
+
+ if (!core->spi1) {
+ pr_debug("spi1 device is not available");
+ goto p_err;
+ }
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+retry:
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->lsc_i0_gain_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail", sysfs_finfo->lsc_i0_gain_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->lsc_j0_gain_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail",sysfs_finfo->lsc_j0_gain_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->lsc_a_gain_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail", sysfs_finfo->lsc_a_gain_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->lsc_k4_gain_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail", sysfs_finfo->lsc_k4_gain_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->lsc_scale_gain_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail", sysfs_finfo->lsc_scale_gain_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->wcoefficient1_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail", sysfs_finfo->wcoefficient1_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ }
+#if 0
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->af_inf_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail", sysfs_finfo->af_inf_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ ret = fimc_is_comp_load_i2c_cal(core, sysfs_finfo->af_macro_addr);
+ if (ret) {
+ err("fimc_is_comp_load_binary(0x%04x) fail", sysfs_finfo->af_macro_addr);
+ goto p_err;
+ }
+ usleep_range(1000, 1000);
+ }
+#endif
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ if (companion_lsc_isvalid) {
+ ret = fimc_is_comp_load_cal(core, COMP_LSC);
+ if (ret) {
+ err("fimc_is_comp_load_binary(%s) fail", COMP_LSC);
+ goto p_err;
+ }
+ pr_info("LSC from FROM loaded");
+ }
+#ifdef USE_DEFAULT_CAL
+ else {
+ ret = fimc_is_comp_load_binary(core, COMP_DEFAULT_LSC);
+ if (ret) {
+ err("fimc_is_comp_load_binary(%s) fail", COMP_DEFAULT_LSC);
+ goto p_err;
+ }
+ pr_info("Default LSC loaded");
+ }
+#endif
+ usleep_range(1000, 1000);
+ } else {
+ pr_info("Did not load LSC cal data");
+ }
+ /*Workaround : If FROM has ver.V003, Skip PDAF Cal loading to companion.*/
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ ret = fimc_is_comp_load_cal(core, COMP_PDAF);
+ if (ret) {
+ err("fimc_is_comp_load_binary(%s) fail", COMP_PDAF);
+ goto p_err;
+ }
+ pdaf_valid = true;
+ usleep_range(1000, 1000);
+ }
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ if (companion_coef_isvalid) {
+ ret = fimc_is_comp_load_cal(core, COMP_COEF_CAL);
+ if (ret) {
+ err("fimc_is_comp_load_binary(%s) fail", COMP_COEF_CAL);
+ goto p_err;
+ }
+ pr_info("COEF from FROM loaded");
+ }
+#ifdef USE_DEFAULT_CAL
+ else {
+ ret = fimc_is_comp_load_binary(core, COMP_DEFAULT_COEF);
+ if (ret) {
+ err("fimc_is_comp_load_binary(%s) fail", COMP_DEFAULT_COEF);
+ goto p_err;
+ }
+ pr_info("Default COEF loaded");
+ }
+#endif
+ usleep_range(1000, 1000);
+ } else {
+ pr_info("Did not load COEF cal data");
+ }
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ ret = fimc_is_comp_check_crc32(core, COMP_LSC);
+ if (pdaf_valid)
+ ret |= fimc_is_comp_check_crc32(core, COMP_PDAF);
+ ret |= fimc_is_comp_check_crc32(core, COMP_COEF_CAL);
+ ret |= fimc_is_comp_check_crc32(core, "coef2");
+ ret |= fimc_is_comp_check_crc32(core, "coef3");
+ ret |= fimc_is_comp_check_crc32(core, "coef4");
+ ret |= fimc_is_comp_check_crc32(core, "coef5");
+ ret |= fimc_is_comp_check_crc32(core, "coef6");
+ if ((ret < 0) && (retry_count > 0)) {
+ retry_count--;
+ goto retry;
+ }
+ }
+ usleep_range(5000, 5000);
+p_err:
+ return 0;
+}
+
+int fimc_is_comp_loadfirm(struct fimc_is_core *core)
+{
+ int ret = 0;
+ int retry_count = 3;
+ struct fimc_is_from_info *sysfs_finfo;
+
+ if (!core->spi1) {
+ err("spi1 device is not available");
+ goto p_err;
+ }
+
+ ret = fimc_is_comp_read_ver(core);
+ if (ret) {
+ err("fimc_is_comp_read_ver fail");
+ goto p_err;
+ }
+ msleep(1);
+
+retry:
+ ret = fimc_is_comp_single_write(core, 0x6042, 0x0001);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+
+ ret = fimc_is_comp_single_write(core, 0x6428, 0x0000);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+
+ ret = fimc_is_comp_single_write(core, 0x642A, 0x0000);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ if (companion_ver == 0x00A0)
+ ret = fimc_is_comp_load_binary(core, COMP_FW_EVT0);
+ else if (companion_ver == 0x00B0)
+ ret = fimc_is_comp_load_binary(core, sysfs_finfo->load_c1_fw_name);
+ if (ret) {
+ err("fimc_is_comp_load_firmware fail");
+ goto p_err;
+ }
+
+ ret = fimc_is_comp_single_write(core, 0x6014, 0x0001);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ if (companion_ver == 0x00A0)
+ ret = fimc_is_comp_check_crc32(core, COMP_FW_EVT0);
+ else if (companion_ver == 0x00B0)
+ ret = fimc_is_comp_check_crc32(core, COMP_FW_EVT1);
+ if ((ret < 0) && (retry_count > 0)) {
+ retry_count--;
+ goto retry;
+ }
+ }
+ usleep_range(5000, 5000);
+p_err:
+ return ret;
+}
+
+int fimc_is_comp_loadsetf(struct fimc_is_core *core)
+{
+ int ret = 0;
+ struct fimc_is_from_info *sysfs_finfo;
+
+ if (!core->spi1) {
+ pr_debug("spi1 device is not available");
+ goto p_err;
+ }
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ ret = fimc_is_comp_load_binary(core, sysfs_finfo->load_c1_mastersetf_name);
+ if (ret) {
+ err("fimc_is_comp_load_binary(%s) fail", sysfs_finfo->load_c1_mastersetf_name);
+ goto p_err;
+ }
+
+ ret = fimc_is_comp_load_binary(core, sysfs_finfo->load_c1_modesetf_name);
+ if (ret) {
+ err("fimc_is_comp_load_binary(%s) fail", sysfs_finfo->load_c1_modesetf_name);
+ goto p_err;
+ }
+ usleep_range(5000, 5000);
+ /*Stream on concord*/
+ ret = fimc_is_comp_single_write(core, 0x6800, 0x0001);
+ if (ret) {
+ err("fimc_is_comp_i2c_setf_write() fail");
+ }
+p_err:
+ return ret;
+}
+
+void fimc_is_s_int_comb_isp(struct fimc_is_core *core,bool on, u32 ch)
+{
+ u32 cfg = ~0x0;
+
+ if(on) {
+ cfg &= ~ch;
+ writel(cfg, core->regs + INTMR2);
+ } else {
+ cfg = 0xFFFFFFFF;
+ writel(cfg, core->regs + INTMR2);
+ }
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_COMPANION_H
+#define FIMC_IS_COMPANION_H
+
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-companion_address.h"
+#include "fimc-is-interface.h"
+
+#define CRC_RETRY_COUNT 40
+
+#define FIMC_IS_ISP_CV "/data/ISP_CV"
+
+enum dcdc_vendor{
+ DCDC_VENDOR_NONE = 0,
+ DCDC_VENDOR_FAN53555,
+ DCDC_VENDOR_NCP6335B,
+ DCDC_VENDOR_MAX,
+};
+
+struct dcdc_power {
+ enum dcdc_vendor type;
+ struct i2c_client *client;
+
+ /* Get i2c register value to set vout of dcdc regulator */
+ int (*get_vout_val)(int);
+
+ /* Get voltage name of vout as string */
+ const char *(*get_vout_str)(int);
+
+ /* Set dcdc vout with i2c register value */
+ int (*set_vout)(struct i2c_client *client, int vout);
+};
+
+int fimc_is_comp_is_valid(struct fimc_is_core *core);
+int fimc_is_comp_loadfirm(struct fimc_is_core *core);
+int fimc_is_comp_loadsetf(struct fimc_is_core *core);
+int fimc_is_comp_loadcal(struct fimc_is_core *core);
+u8 fimc_is_comp_is_compare_ver(struct fimc_is_core *core);
+int fimc_is_power_binning(struct fimc_is_core *core);
+void fimc_is_s_int_comb_isp(struct fimc_is_core *core,bool on, u32 ch);
+
+#endif /* FIMC_IS_COMPANION_H */
--- /dev/null
+/*2P2 Address*/
+#define MEM_GRAS_B_2P2 0x2001A000 // 0x00000000 0x1A00 0x2001A000 0x0020
+#define MEM_AF_10_1_2P2 0x2000B900 // 0x00000000 0x0200 0x2000B900 0x0020
+#define MEM_XTALK_10_2P2 0x20010000 // 0x00000000 0x0FC0 0x20010000 0x0020
+#define grasTuning_uParabolicCenterX_2P2 0x400008A8 // 0x0A68 0x0002 0x200008A8 0x0002
+#define grasTuning_uParabolicCenterY_2P2 0x400008AA // 0x05DC 0x0002 0x200008AA 0x0002
+#define grasTuning_uBiQuadFactorA_2P2 0x400008B4 // 0x00008000 0x0004 0x200008B4 0x0003
+#define grasTuning_uBiQuadFactorB_2P2 0x400008B8 // 0x00004000 0x0004 0x200008B8 0x0003
+#define grasTuning_uBiQuadScaleShiftAdder_2P2 0x400008BC // 0x0000 0x0002 0x200008BC 0x0002
+#define xtalkTuningParams_wcr_2P2 0x40000EA0 // 0xFFF7 0x0002 0x20000EA0 0x0002
+#define grasTuning_actuatorPositionToShadingPowerLut_0_2P2 0x40000984 // 0x0032 0x0002 0x2000097C 0x0002
+#define grasTuning_actuatorPositionToShadingPowerLut_9_2P2 0x40000996 // 0x00CF 0x0002 0x2000098E 0x0002
+
+/*IMX240 Address*/
+#define MEM_GRAS_B_IMX240 0x2001A000 // 0x00000000 0x1A00 0x2001A000 0x0020
+#define MEM_AF_10_1_IMX240 0x2000B900 // 0x00000000 0x0200 0x2000B900 0x0020
+#define MEM_XTALK_10_IMX240 0x20010000 // 0x00000000 0x0FC0 0x20010000 0x0020
+#define grasTuning_uParabolicCenterX_IMX240 0x400008A8 // 0x0A68 0x0002 0x200008A8 0x0002
+#define grasTuning_uParabolicCenterY_IMX240 0x400008AA // 0x05DC 0x0002 0x200008AA 0x0002
+#define grasTuning_uBiQuadFactorA_IMX240 0x400008B4 // 0x00008000 0x0004 0x200008B4 0x0003
+#define grasTuning_uBiQuadFactorB_IMX240 0x400008B8 // 0x00004000 0x0004 0x200008B8 0x0003
+#define grasTuning_uBiQuadScaleShiftAdder_IMX240 0x400008BC // 0x0000 0x0002 0x200008BC 0x0002
+#define xtalkTuningParams_wcr_IMX240 0x40000EC0 // 0xFFF7 0x0002 0x20000EC0 0x0002
+#define grasTuning_actuatorPositionToShadingPowerLut_0_IMX240 0x40000984 // 0x0032 0x0002 0x2000097C 0x0002
+#define grasTuning_actuatorPositionToShadingPowerLut_9_IMX240 0x40000996 // 0x00CF 0x0002 0x2000098E 0x0002
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_CONFIG_H
+#define FIMC_IS_CONFIG_H
+
+/* configuration - default post processing */
+#define ENABLE_SETFILE
+#define ENABLE_DRC
+/* #define ENABLE_ODC */
+/* #define ENABLE_VDIS */
+/* #define ENABLE_TDNR */
+#define ENABLE_FD
+#define ENABLE_CLOCK_GATE
+/* #define HAS_FW_CLOCK_GATE */
+/* #define ENABLE_CACHE */
+#define ENABLE_FULL_BYPASS
+#define ENABLE_FAST_SHOT
+#define USE_OWN_FAULT_HANDLER
+/* #define ENABLE_MIF_400 */
+#define ENABLE_DTP
+#define USE_ION_ALLOC
+
+#define CSI_VERSION_0000_0000 0x0
+#define CSI_VERSION_0310_0100 0x03100100
+
+#define FIMC_IS_VERSION_000 0x0
+#define FIMC_IS_VERSION_250 0x250
+
+#if defined(CONFIG_PM_DEVFREQ)
+#define ENABLE_DVFS
+#define START_DVFS_LEVEL FIMC_IS_SN_MAX
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5430)
+#undef ENABLE_SETFILE
+#define SUPPORTED_IS_CMD_VER 132
+#define TARGET_SPI_CH_FOR_PERI 0
+#define FIMC_IS_CSI_VERSION CSI_VERSION_0000_0000
+#define FIMC_IS_VERSION FIMC_IS_VERSION_000
+#define HAS_FW_CLOCK_GATE
+
+#elif defined(CONFIG_SOC_EXYNOS5433)
+#define SUPPORTED_IS_CMD_VER 132
+#define TARGET_SPI_CH_FOR_PERI 0
+#define FIMC_IS_CSI_VERSION CSI_VERSION_0000_0000
+#define FIMC_IS_VERSION FIMC_IS_VERSION_000
+#define HAS_FW_CLOCK_GATE
+#define MAX_ZOOM_LEVEL 8
+
+#elif defined(CONFIG_SOC_EXYNOS5422)
+#undef ENABLE_SETFILE
+#define SUPPORTED_IS_CMD_VER 132
+#define TARGET_SPI_CH_FOR_PERI 0
+#define FIMC_IS_CSI_VERSION CSI_VERSION_0000_0000
+#define FIMC_IS_VERSION FIMC_IS_VERSION_000
+
+#elif defined(CONFIG_SOC_EXYNOS5260)
+#undef ENABLE_SETFILE
+#undef ENABLE_DRC
+#undef ENABLE_FULL_BYPASS
+#define SUPPORTED_EARLY_BUF_DONE
+#define SUPPORTED_IS_CMD_VER 131
+#define TARGET_SPI_CH_FOR_PERI 1
+#define FIMC_IS_CSI_VERSION CSI_VERSION_0310_0100
+#define FIMC_IS_VERSION FIMC_IS_VERSION_000
+#define SCALER_PARALLEL_MODE
+
+#elif defined(CONFIG_SOC_EXYNOS4415)
+#undef ENABLE_SETFILE
+#undef ENABLE_DRC
+#define SUPPORTED_IS_CMD_VER 132
+#define TARGET_SPI_CH_FOR_PERI 1
+#define FIMC_IS_CSI_VERSION CSI_VERSION_0310_0100
+#define FIMC_IS_VERSION FIMC_IS_VERSION_250
+
+#elif defined(CONFIG_SOC_EXYNOS3470)
+#undef ENABLE_SETFILE
+#undef ENABLE_DRC
+#undef ENABLE_FULL_BYPASS
+#define SUPPORTED_EARLY_BUF_DONE
+#define ENABLE_IFLAG
+#define SUPPORTED_IS_CMD_VER 131
+#define TARGET_SPI_CH_FOR_PERI 1
+#define FIMC_IS_CSI_VERSION CSI_VERSION_0000_0000
+#define FIMC_IS_VERSION FIMC_IS_VERSION_000
+#define SCALER_PARALLEL_MODE
+
+#elif defined(CONFIG_SOC_EXYNOS3472)
+#undef ENABLE_SETFILE
+#undef ENABLE_DRC
+#undef ENABLE_DVFS
+#undef ENABLE_FULL_BYPASS
+#define ENABLE_IFLAG
+#define SUPPORTED_IS_CMD_VER 131
+#define TARGET_SPI_CH_FOR_PERI 1
+#define FIMC_IS_CSI_VERSION CSI_VERSION_0310_0100
+#define FIMC_IS_VERSION FIMC_IS_VERSION_000
+
+#else
+#error fimc-is driver can NOT support this platform
+
+#endif
+
+#if !defined(MAX_ZOOM_LEVEL)
+/* default max zoom lv is 4 */
+#define MAX_ZOOM_LEVEL 4
+#endif
+
+/* notifier for MIF throttling */
+#if defined(CONFIG_ARM_EXYNOS5433_BUS_DEVFREQ) && defined(CONFIG_CPU_THERMAL_IPA)
+#define EXYNOS_MIF_ADD_NOTIFIER(nb) \
+ exynos_mif_add_notifier(nb)
+#else
+#define EXYNOS_MIF_ADD_NOTIFIER(nb)
+#endif
+
+#if defined(CONFIG_ARM_EXYNOS4415_BUS_DEVFREQ)
+#define CONFIG_FIMC_IS_BUS_DEVFREQ
+#endif
+#if defined(CONFIG_ARM_EXYNOS5260_BUS_DEVFREQ)
+#define CONFIG_FIMC_IS_BUS_DEVFREQ
+#endif
+#if defined(CONFIG_ARM_EXYNOS3470_BUS_DEVFREQ)
+#define CONFIG_FIMC_IS_BUS_DEVFREQ
+#endif
+#if defined(CONFIG_ARM_EXYNOS5422_BUS_DEVFREQ)
+#define CONFIG_FIMC_IS_BUS_DEVFREQ
+#endif
+#if defined(CONFIG_ARM_EXYNOS5430_BUS_DEVFREQ)
+#define CONFIG_FIMC_IS_BUS_DEVFREQ
+#endif
+#if defined(CONFIG_ARM_EXYNOS5433_BUS_DEVFREQ)
+#define CONFIG_FIMC_IS_BUS_DEVFREQ
+#endif
+
+/*
+ * -----------------------------------------------------------------------------
+ * Debug Message Configuration
+ * -----------------------------------------------------------------------------
+ */
+
+/* #define DEBUG */
+#define DBG_VIDEO
+#define DBG_DEVICE
+#define DBG_PER_FRAME
+/* #define DBG_STREAMING */
+#define DEBUG_INSTANCE 0xF
+#define BUG_ON_ENABLE
+/* #define FIXED_FPS_DEBUG */
+#define FIXED_FPS_VALUE 10
+/* #define DBG_CSIISR */
+/* #define DBG_FLITEISR */
+#define FW_DEBUG
+#define RESERVED_MEM
+/* #define SCALER_CROP_DZOOM */
+/* #define USE_ADVANCED_DZOOM */
+/* #define TASKLET_MSG */
+/* #define PRINT_CAPABILITY */
+/* #define PRINT_BUFADDR */
+/* #define PRINT_DZOOM */
+/* #define PRINT_PARAM */
+/* #define PRINT_I2CCMD */
+#define ISDRV_VERSION 244
+
+#if (defined(BAYER_CROP_DZOOM) && defined(SCALER_CROP_DZOOM))
+#error BAYER_CROP_DZOOM and SCALER_CROP_DZOOM can''t be enable together
+#endif
+
+/*
+ * driver version extension
+ */
+#ifdef ENABLE_CLOCK_GATE
+#define get_drv_clock_gate() 0x1
+#else
+#define get_drv_clock_gate() 0x0
+#endif
+#ifdef ENABLE_DVFS
+#define get_drv_dvfs() 0x2
+#else
+#define get_drv_dvfs() 0x0
+#endif
+
+#define GET_3AA_ID(video) ((video->id < 14) ? 0 : 1)
+#define GET_3AAC_ID(video) ((video->id < FIMC_IS_VIDEO_3A1_NUM) ? 0 : 1)
+
+/* sync log with HAL, FW */
+#define log_sync(sync_id) \
+ pr_info("[@]FIMC_IS_SYNC %d\n", sync_id)
+
+#ifdef err
+#undef err
+#endif
+#define err(fmt, args...) \
+ pr_err("[@][ERR]%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+
+/* multi-stream */
+#define merr(fmt, object, args...) \
+ pr_err("[@][%d][ERR]%s:%d: " fmt "\n", object->instance, __func__, __LINE__, ##args)
+
+/* multi-stream & runtime error */
+#define mrerr(fmt, object, frame, args...) \
+ pr_err("[@][%d:F%d][ERR]%s:%d: " fmt "\n", object->instance, frame->fcount, __func__, __LINE__, ##args)
+
+/* multi-stream & group error */
+#define mgerr(fmt, object, group, args...) \
+ pr_err("[@][%d][GP%d][ERR]%s:%d:" fmt "\n", object->instance, group->id, __func__, __LINE__, ##args)
+
+#ifdef warn
+#undef warn
+#endif
+#define warn(fmt, args...) \
+ pr_warning("[@][WRN] " fmt "\n", ##args)
+
+#define mwarn(fmt, this, args...) \
+ pr_warning("[@][%d][WRN] " fmt "\n", this->instance, ##args)
+
+#define mgwarn(fmt, object, group, args...) \
+ pr_warning("[@][%d][GP%d][WRN]" fmt "\n", object->instance, group->id, ##args)
+
+#define info(fmt, args...) \
+ pr_info("[@]" fmt, ##args)
+
+#define minfo(fmt, object, args...) \
+ pr_info("[@][%d]" fmt, object->instance, ##args)
+
+#define mrinfo(fmt, object, frame, args...) \
+ pr_info("[@][%d:F%d]" fmt, object->instance, frame->fcount, ##args)
+
+#define mrdbg(fmt, object, frame, args...) \
+ printk(KERN_DEBUG "[@][%d:F%d]" fmt, object->instance, frame->fcount, ##args)
+
+#define mdbg_common(prefix, fmt, instance, args...) \
+ do { \
+ if ((1<<(instance)) & DEBUG_INSTANCE) \
+ pr_info("[@]" prefix fmt, instance, ##args); \
+ } while (0)
+
+#if (defined(DEBUG) && defined(DBG_VIDEO))
+#define dbg(fmt, args...)
+
+#define dbg_warning(fmt, args...) \
+ printk(KERN_INFO "%s[WAR] Warning! " fmt, __func__, ##args)
+
+/* debug message for video node */
+#define mdbgv_vid(fmt, args...) \
+ pr_info("[@][VID:V] " fmt, ##args)
+
+#define mdbgv_sensor(fmt, this, args...) \
+ mdbg_common("[%d][SS%d:V] ", fmt, this->video->id, this->instance, ##args)
+
+#define mdbgv_3aa(fmt, this, args...) \
+ mdbg_common("[%d][3A%d:V] ", fmt, GET_3AA_ID(this->video), this->instance, ##args)
+
+#define mdbgv_3aac(fmt, this, args...) \
+ mdbg_common("[%d][3A%dC:V] ", fmt, GET_3AAC_ID(this->video), this->instance, ##args)
+
+#define dbg_isp(fmt, args...) \
+ printk(KERN_INFO "[ISP] " fmt, ##args)
+
+#define mdbgv_isp(fmt, this, args...) \
+ mdbg_common("[%d][ISP:V] ", fmt, this->instance, ##args)
+
+#define dbg_scp(fmt, args...) \
+ printk(KERN_INFO "[SCP] " fmt, ##args)
+
+#define mdbgv_scp(fmt, this, args...) \
+ mdbg_common("[%d][SCP:V] ", fmt, this->instance, ##args)
+
+#define dbg_scc(fmt, args...) \
+ printk(KERN_INFO "[SCC] " fmt, ##args)
+
+#define mdbgv_scc(fmt, this, args...) \
+ mdbg_common("[%d][SCC:V] ", fmt, this->instance, ##args)
+
+#define dbg_vdisc(fmt, args...) \
+ printk(KERN_INFO "[VDC] " fmt, ##args)
+
+#define mdbgv_vdc(fmt, this, args...) \
+ mdbg_common("[%d][VDC:V] ", fmt, this->instance, ##args)
+
+#define dbg_vdiso(fmt, args...) \
+ printk(KERN_INFO "[VDO] " fmt, ##args)
+
+#define mdbgv_vdo(fmt, this, args...) \
+ mdbg_common("[%d][VDO:V] ", fmt, this->instance, ##args)
+#else
+#define dbg(fmt, args...)
+
+/* debug message for video node */
+#define mdbgv_vid(fmt, this, args...)
+#define dbg_sensor(fmt, args...)
+#define mdbgv_sensor(fmt, this, args...)
+#define mdbgv_3aa(fmt, this, args...)
+#define mdbgv_3aac(fmt, this, args...)
+#define dbg_isp(fmt, args...)
+#define mdbgv_isp(fmt, this, args...)
+#define dbg_scp(fmt, args...)
+#define mdbgv_scp(fmt, this, args...)
+#define dbg_scc(fmt, args...)
+#define mdbgv_scc(fmt, this, args...)
+#define dbg_vdisc(fmt, args...)
+#define mdbgv_vdc(fmt, this, args...)
+#define dbg_vdiso(fmt, args...)
+#define mdbgv_vdo(fmt, this, args...)
+#endif
+
+#if (defined(DEBUG) && defined(DBG_DEVICE))
+/* debug message for device */
+#define mdbgd_sensor(fmt, this, args...) \
+ mdbg_common("[%d][SEN:D] ", fmt, this->instance, ##args)
+
+#define mdbgd_front(fmt, this, args...) \
+ mdbg_common("[%d][FRT:D] ", fmt, this->instance, ##args)
+
+#define mdbgd_back(fmt, this, args...) \
+ mdbg_common("[%d][BAK:D] ", fmt, this->instance, ##args)
+
+#define mdbgd_3a0(fmt, this, args...) \
+ mdbg_common("[%d][3A0:D] ", fmt, this->instance, ##args)
+
+#define mdbgd_3a1(fmt, this, args...) \
+ mdbg_common("[%d][3A1:D] ", fmt, this->instance, ##args)
+
+#define mdbgd_isp(fmt, this, args...) \
+ mdbg_common("[%d][ISP:D] ", fmt, this->instance, ##args)
+
+#define mdbgd_ischain(fmt, this, args...) \
+ mdbg_common("[%d][ISC:D] ", fmt, this->instance, ##args)
+
+#define mdbgd_group(fmt, group, args...) \
+ mdbg_common("[%d][GP%d:D] ", fmt, group->device->instance, group->id, ##args)
+
+#define dbg_core(fmt, args...) \
+ pr_info("[@][COR] " fmt, ##args)
+#else
+/* debug message for device */
+#define mdbgd_sensor(fmt, this, args...)
+#define mdbgd_front(fmt, this, args...)
+#define mdbgd_back(fmt, this, args...)
+#define mdbgd_isp(fmt, this, args...)
+#define dbg_ischain(fmt, args...)
+#define mdbgd_ischain(fmt, this, args...)
+#define dbg_core(fmt, args...)
+#define dbg_interface(fmt, args...)
+#define dbg_frame(fmt, args...)
+#define mdbgd_group(fmt, group, args...)
+#endif
+
+#if (defined(DEBUG) && defined(DBG_STREAMING))
+#define dbg_interface(fmt, args...) \
+ pr_info("[@][ITF] " fmt, ##args)
+#define dbg_frame(fmt, args...) \
+ pr_info("[@][FRM] " fmt, ##args)
+#else
+#define dbg_interface(fmt, args...)
+#define dbg_frame(fmt, args...)
+#endif
+
+#if (defined(DEBUG) && defined(DBG_PER_FRAME))
+#define mdbg_pframe(fmt, object, frame, args...) \
+ pr_info("[@][%d:F%d]" fmt, object->instance, frame->fcount, ##args)
+#else
+#define mdbg_pframe(fmt, object, frame, args...)
+#endif
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <mach/regs-clock.h>
+#include <linux/pm_qos.h>
+#include <linux/bug.h>
+#include <linux/v4l2-mediabus.h>
+#include <mach/devfreq.h>
+#include <mach/bts.h>
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#endif
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-framemgr.h"
+#include "fimc-is-dt.h"
+#include "fimc-is-resourcemgr.h"
+#include "fimc-is-clk-gate.h"
+#include "fimc-is-dvfs.h"
+#include "fimc-is-fan53555.h"
+#include "fimc-is-ncp6335b.h"
+
+#include "sensor/fimc-is-device-2p2.h"
+#include "sensor/fimc-is-device-3h5.h"
+#include "sensor/fimc-is-device-3h7.h"
+#include "sensor/fimc-is-device-3h7_sunny.h"
+#include "sensor/fimc-is-device-3l2.h"
+#include "sensor/fimc-is-device-4e5.h"
+#include "sensor/fimc-is-device-6a3.h"
+#include "sensor/fimc-is-device-6b2.h"
+#include "sensor/fimc-is-device-8b1.h"
+#include "sensor/fimc-is-device-6d1.h"
+#include "sensor/fimc-is-device-imx134.h"
+#include "sensor/fimc-is-device-imx135.h"
+#include "sensor/fimc-is-device-imx175.h"
+#include "sensor/fimc-is-device-imx240.h"
+#include "sensor/fimc-is-device-imx219.h"
+#include "sensor/fimc-is-device-4h5.h"
+#include "sensor/fimc-is-device-3l2.h"
+#include "sensor/fimc-is-device-2p2.h"
+#include "sensor/fimc-is-device-2p2_12m.h"
+#include "sensor/fimc-is-device-2p3.h"
+#ifdef CONFIG_USE_VENDER_FEATURE
+#include "fimc-is-sec-define.h"
+#ifdef CONFIG_OIS_USE
+#include "fimc-is-device-ois.h"
+#endif
+#endif
+#ifdef CONFIG_AF_HOST_CONTROL
+#include "fimc-is-device-af.h"
+#endif
+
+#ifdef USE_OWN_FAULT_HANDLER
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#include <linux/exynos_iovmm.h>
+#else
+#include <plat/sysmmu.h>
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+#define PM_QOS_CAM_THROUGHPUT PM_QOS_RESERVED
+#endif
+
+struct fimc_is_from_info *sysfs_finfo = NULL;
+struct fimc_is_from_info *sysfs_pinfo = NULL;
+
+#ifdef CONFIG_USE_VENDER_FEATURE
+struct class *camera_class = NULL;
+struct device *camera_front_dev;
+struct device *camera_rear_dev;
+#ifdef CONFIG_OIS_USE
+struct device *camera_ois_dev;
+#endif
+#endif
+
+struct device *fimc_is_dev = NULL;
+struct fimc_is_core *sysfs_core;
+
+#ifdef CONFIG_USE_VENDER_FEATURE
+extern bool crc32_fw_check;
+extern bool crc32_check;
+extern bool crc32_check_factory;
+extern bool fw_version_crc_check;
+extern bool is_latest_cam_module;
+extern bool is_final_cam_module;
+#if defined(CONFIG_SOC_EXYNOS5433)
+extern bool is_right_prj_name;
+#endif
+#ifdef CONFIG_COMPANION_USE
+extern bool crc32_c1_fw_check;
+extern bool crc32_c1_check;
+extern bool crc32_c1_check_factory;
+#endif /* CONFIG_COMPANION_USE */
+#endif
+
+extern struct pm_qos_request exynos_isp_qos_int;
+extern struct pm_qos_request exynos_isp_qos_mem;
+extern struct pm_qos_request exynos_isp_qos_cam;
+extern struct pm_qos_request exynos_isp_qos_disp;
+
+extern int fimc_is_3a0_video_probe(void *data);
+extern int fimc_is_3a1_video_probe(void *data);
+extern int fimc_is_isp_video_probe(void *data);
+extern int fimc_is_scc_video_probe(void *data);
+extern int fimc_is_scp_video_probe(void *data);
+extern int fimc_is_vdc_video_probe(void *data);
+extern int fimc_is_vdo_video_probe(void *data);
+extern int fimc_is_3a0c_video_probe(void *data);
+extern int fimc_is_3a1c_video_probe(void *data);
+
+/* sysfs global variable for debug */
+struct fimc_is_sysfs_debug sysfs_debug;
+
+static int fimc_is_ischain_allocmem(struct fimc_is_core *this)
+{
+ int ret = 0;
+ void *fw_cookie;
+ size_t fw_size =
+#ifdef ENABLE_ODC
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+#endif
+#ifdef ENABLE_VDIS
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF +
+#endif
+#ifdef ENABLE_TDNR
+ SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF +
+#endif
+ FIMC_IS_A5_MEM_SIZE;
+
+ fw_size = PAGE_ALIGN(fw_size);
+ dbg_core("Allocating memory for FIMC-IS firmware.\n");
+
+ fw_cookie = vb2_ion_private_alloc(this->mem.alloc_ctx, fw_size, 1, 0);
+
+ if (IS_ERR(fw_cookie)) {
+ err("Allocating bitprocessor buffer failed");
+ fw_cookie = NULL;
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ret = vb2_ion_dma_address(fw_cookie, &this->minfo.dvaddr);
+ if ((ret < 0) || (this->minfo.dvaddr & FIMC_IS_FW_BASE_MASK)) {
+ err("The base memory is not aligned to 64MB.");
+ vb2_ion_private_free(fw_cookie);
+ this->minfo.dvaddr = 0;
+ fw_cookie = NULL;
+ ret = -EIO;
+ goto exit;
+ }
+ dbg_core("Device vaddr = %08x , size = %08x\n",
+ this->minfo.dvaddr, FIMC_IS_A5_MEM_SIZE);
+
+ this->minfo.kvaddr = (u32)vb2_ion_private_vaddr(fw_cookie);
+ if (IS_ERR((void *)this->minfo.kvaddr)) {
+ err("Bitprocessor memory remap failed");
+ vb2_ion_private_free(fw_cookie);
+ this->minfo.kvaddr = 0;
+ fw_cookie = NULL;
+ ret = -EIO;
+ goto exit;
+ }
+
+ vb2_ion_sync_for_device(fw_cookie, 0, fw_size, DMA_BIDIRECTIONAL);
+
+exit:
+ info("[COR] Device virtual for internal: %08x\n", this->minfo.kvaddr);
+ this->minfo.fw_cookie = fw_cookie;
+
+ return ret;
+}
+
+static int fimc_is_ishcain_initmem(struct fimc_is_core *this)
+{
+ int ret = 0;
+ u32 offset;
+
+ dbg_core("fimc_is_init_mem - ION\n");
+
+ ret = fimc_is_ischain_allocmem(this);
+ if (ret) {
+ err("Couldn't alloc for FIMC-IS firmware\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ offset = FW_SHARED_OFFSET;
+ this->minfo.dvaddr_fshared = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_fshared = this->minfo.kvaddr + offset;
+
+ offset = FIMC_IS_A5_MEM_SIZE - FIMC_IS_REGION_SIZE;
+ this->minfo.dvaddr_region = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_region = this->minfo.kvaddr + offset;
+
+ offset = FIMC_IS_A5_MEM_SIZE;
+#ifdef ENABLE_ODC
+ this->minfo.dvaddr_odc = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_odc = this->minfo.kvaddr + offset;
+ offset += (SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF);
+#else
+ this->minfo.dvaddr_odc = 0;
+ this->minfo.kvaddr_odc = 0;
+#endif
+
+#ifdef ENABLE_VDIS
+ this->minfo.dvaddr_dis = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_dis = this->minfo.kvaddr + offset;
+ offset += (SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF);
+#else
+ this->minfo.dvaddr_dis = 0;
+ this->minfo.kvaddr_dis = 0;
+#endif
+
+#ifdef ENABLE_TDNR
+ this->minfo.dvaddr_3dnr = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_3dnr = this->minfo.kvaddr + offset;
+ offset += (SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF);
+#else
+ this->minfo.dvaddr_3dnr = 0;
+ this->minfo.kvaddr_3dnr = 0;
+#endif
+
+ dbg_core("fimc_is_init_mem done\n");
+
+exit:
+ return ret;
+}
+
+#if defined(CONFIG_ARM_EXYNOS5433_BUS_DEVFREQ) && defined(CONFIG_CPU_THERMAL_IPA)
+static int fimc_is_mif_throttling_notifier(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct fimc_is_core *core = NULL;
+ struct fimc_is_device_sensor *device = NULL;
+ int i;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is null");
+ goto exit;
+ }
+
+ for (i = 0; i < FIMC_IS_MAX_NODES; i++) {
+ if (test_bit(FIMC_IS_SENSOR_OPEN, &core->sensor[i].state)) {
+ device = &core->sensor[i];
+ break;
+ }
+ }
+
+ if (device && !test_bit(FIMC_IS_SENSOR_FRONT_DTP_STOP, &device->state))
+ /* Set DTP */
+ set_bit(FIMC_IS_MIF_THROTTLING_STOP, &device->force_stop);
+ else
+ err("any sensor is not opened");
+
+exit:
+ err("MIF: cause of mif_throttling, mif_qos is [%lu]!!!\n", val);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block exynos_fimc_is_mif_throttling_nb = {
+ .notifier_call = fimc_is_mif_throttling_notifier,
+};
+#endif
+
+#ifdef CONFIG_USE_VENDER_FEATURE
+static ssize_t camera_front_sensorid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct exynos_platform_fimc_is_sensor *sensor = dev_get_drvdata(dev);
+
+ dev_info(dev, "%s: E", __func__);
+
+ if (unlikely(!sensor)) {
+ dev_err(dev, "%s: sensor null\n", __func__);
+ return -EFAULT;
+ }
+
+ return sprintf(buf, "%d\n", sensor->sensor_id);
+}
+
+static ssize_t camera_rear_sensorid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct exynos_platform_fimc_is_sensor *sensor = dev_get_drvdata(dev);
+
+ dev_info(dev, "%s: E", __func__);
+
+ if (unlikely(!sensor)) {
+ dev_err(dev, "%s: sensor null\n", __func__);
+ return -EFAULT;
+ }
+
+ return sprintf(buf, "%d\n", sensor->sensor_id);
+}
+
+static DEVICE_ATTR(front_sensorid, S_IRUGO, camera_front_sensorid_show, NULL);
+static DEVICE_ATTR(rear_sensorid, S_IRUGO, camera_rear_sensorid_show, NULL);
+
+int fimc_is_get_sensor_data(struct device *dev, char *maker, char *name, int position)
+{
+ struct exynos_platform_fimc_is_sensor *sensor = dev_get_drvdata(dev);
+ struct fimc_is_core *core;
+ struct fimc_is_device_sensor *device;
+ int i;
+
+ if (unlikely(!sensor)) {
+ dev_err(dev, "%s: sensor null\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!fimc_is_dev) {
+ dev_err(dev, "%s: fimc_is_dev is not yet probed", __func__);
+ return -ENODEV;
+ }
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ dev_err(dev, "%s: core is NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (position == SENSOR_POSITION_FRONT || position == SENSOR_POSITION_REAR) {
+ device = &core->sensor[position];
+ } else {
+ dev_err(dev, "%s: position value is wrong", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < atomic_read(&core->resourcemgr.rsccount_module); i++) {
+ if (sensor->sensor_id == device->module_enum[i].id) {
+ if (maker != NULL)
+ sprintf(maker, "%s", device->module_enum[i].sensor_maker ?
+ device->module_enum[i].sensor_maker : "UNKNOWN");
+ if (name != NULL)
+ sprintf(name, "%s", device->module_enum[i].sensor_name ?
+ device->module_enum[i].sensor_name : "UNKNOWN");
+ return 0;
+ }
+ }
+
+ dev_err(dev, "%s: there's no matched sensor id", __func__);
+
+ return -ENODEV;
+}
+
+static ssize_t camera_front_camtype_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char sensor_maker[50];
+ char sensor_name[50];
+ int ret;
+
+ ret = fimc_is_get_sensor_data(dev, sensor_maker, sensor_name, SENSOR_POSITION_FRONT);
+
+ if (ret < 0)
+ return sprintf(buf, "UNKNOWN_UNKNOWN_FIMC_IS\n");
+ else
+ return sprintf(buf, "%s_%s_FIMC_IS\n", sensor_maker, sensor_name);
+}
+
+static ssize_t camera_front_camfw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char sensor_name[50];
+ int ret;
+
+ ret = fimc_is_get_sensor_data(dev, NULL, sensor_name, SENSOR_POSITION_FRONT);
+
+ if (ret < 0)
+ return sprintf(buf, "UNKNOWN UNKNOWN\n");
+ else
+ return sprintf(buf, "%s N\n", sensor_name);
+}
+
+static DEVICE_ATTR(front_camtype, S_IRUGO,
+ camera_front_camtype_show, NULL);
+static DEVICE_ATTR(front_camfw, S_IRUGO, camera_front_camfw_show, NULL);
+
+static struct fimc_is_from_info *pinfo = NULL;
+static struct fimc_is_from_info *finfo = NULL;
+
+int read_from_firmware_version(void)
+{
+ char fw_name[100];
+ char setf_name[100];
+#ifdef CONFIG_COMPANION_USE
+ char master_setf_name[100];
+ char mode_setf_name[100];
+#endif
+ struct device *is_dev = &sysfs_core->ischain[0].pdev->dev;
+
+ fimc_is_sec_get_sysfs_pinfo(&pinfo);
+ fimc_is_sec_get_sysfs_finfo(&finfo);
+
+ if (!finfo->is_caldata_read) {
+ if (finfo->bin_start_addr != 0x80000) {
+ //fimc_is_sec_set_camid(CAMERA_DUAL_FRONT);
+#if defined(CONFIG_PM_RUNTIME)
+ pr_debug("pm_runtime_suspended = %d\n",
+ pm_runtime_suspended(is_dev));
+ pm_runtime_get_sync(is_dev);
+#else
+ fimc_is_runtime_resume(is_dev);
+ printk(KERN_INFO "%s - fimc_is runtime resume complete\n", __func__);
+#endif
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ fimc_is_sec_fw_sel_eeprom(is_dev, fw_name, setf_name, SENSOR_POSITION_REAR, false);
+#else
+ fimc_is_sec_fw_sel(sysfs_core, is_dev, fw_name, setf_name, false);
+#endif
+#ifdef CONFIG_COMPANION_USE
+ fimc_is_sec_concord_fw_sel(sysfs_core, is_dev, fw_name, master_setf_name, mode_setf_name);
+#endif
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(is_dev);
+ pr_debug("pm_runtime_suspended = %d\n",
+ pm_runtime_suspended(is_dev));
+#else
+ fimc_is_runtime_suspend(is_dev);
+#endif
+ }
+ }
+ return 0;
+}
+
+static ssize_t camera_rear_camtype_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char sensor_maker[50];
+ char sensor_name[50];
+ int ret;
+
+ ret = fimc_is_get_sensor_data(dev, sensor_maker, sensor_name, SENSOR_POSITION_REAR);
+
+ if (ret < 0)
+ return sprintf(buf, "UNKNOWN_UNKNOWN_FIMC_IS\n");
+ else
+ return sprintf(buf, "%s_%s_FIMC_IS\n", sensor_maker, sensor_name);
+}
+
+static ssize_t camera_rear_camfw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char command_ack[20] = {0, };
+ char *loaded_fw;
+
+ read_from_firmware_version();
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ loaded_fw = pinfo->header_ver;
+#else
+ fimc_is_sec_get_loaded_fw(&loaded_fw);
+#endif
+
+ if(fw_version_crc_check) {
+ if (crc32_fw_check && crc32_check_factory
+#ifdef CONFIG_COMPANION_USE
+ && crc32_c1_fw_check && crc32_c1_check_factory
+#endif
+ ) {
+ return sprintf(buf, "%s %s\n", finfo->header_ver, loaded_fw);
+ } else {
+ strcpy(command_ack, "NG_");
+ if (!crc32_fw_check)
+ strcat(command_ack, "FW");
+ if (!crc32_check_factory)
+ strcat(command_ack, "CD");
+#ifdef CONFIG_COMPANION_USE
+ if (!crc32_c1_fw_check)
+ strcat(command_ack, "FW1");
+ if (!crc32_c1_check_factory)
+ strcat(command_ack, "CD1");
+#endif
+ if (finfo->header_ver[3] != 'L')
+ strcat(command_ack, "_Q");
+ return sprintf(buf, "%s %s\n", finfo->header_ver, command_ack);
+ }
+ } else {
+ strcpy(command_ack, "NG_");
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ strcat(command_ack, "CD");
+#else
+ strcat(command_ack, "FWCD");
+#endif
+#ifdef CONFIG_COMPANION_USE
+ strcat(command_ack, "FW1CD1");
+#endif
+ return sprintf(buf, "%s %s\n", finfo->header_ver, command_ack);
+ }
+}
+
+static ssize_t camera_rear_camfw_full_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char command_ack[20] = {0, };
+ char *loaded_fw;
+
+ read_from_firmware_version();
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ loaded_fw = pinfo->header_ver;
+#else
+ fimc_is_sec_get_loaded_fw(&loaded_fw);
+#endif
+
+ if(fw_version_crc_check) {
+ if (crc32_fw_check && crc32_check_factory
+#ifdef CONFIG_COMPANION_USE
+ && crc32_c1_fw_check && crc32_c1_check_factory
+#endif
+ ) {
+ return sprintf(buf, "%s %s %s\n", finfo->header_ver, pinfo->header_ver, loaded_fw);
+ } else {
+ strcpy(command_ack, "NG_");
+ if (!crc32_fw_check)
+ strcat(command_ack, "FW");
+ if (!crc32_check_factory)
+ strcat(command_ack, "CD");
+#ifdef CONFIG_COMPANION_USE
+ if (!crc32_c1_fw_check)
+ strcat(command_ack, "FW1");
+ if (!crc32_c1_check_factory)
+ strcat(command_ack, "CD1");
+#endif
+ if (finfo->header_ver[3] != 'L')
+ strcat(command_ack, "_Q");
+ return sprintf(buf, "%s %s %s\n", finfo->header_ver, pinfo->header_ver, command_ack);
+ }
+ } else {
+ strcpy(command_ack, "NG_");
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ strcat(command_ack, "CD");
+#else
+ strcat(command_ack, "FWCD");
+#endif
+#ifdef CONFIG_COMPANION_USE
+ strcat(command_ack, "FW1CD1");
+#endif
+ return sprintf(buf, "%s %s %s\n", finfo->header_ver, pinfo->header_ver, command_ack);
+ }
+}
+
+static ssize_t camera_rear_checkfw_user_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ read_from_firmware_version();
+
+ if(fw_version_crc_check) {
+ if (crc32_fw_check && crc32_check_factory
+#ifdef CONFIG_COMPANION_USE
+ && crc32_c1_fw_check && crc32_c1_check_factory
+#endif
+ ) {
+ if (!is_latest_cam_module
+#if defined(CONFIG_SOC_EXYNOS5433)
+ || !is_right_prj_name
+#endif
+ ) {
+ return sprintf(buf, "%s\n", "NG");
+ } else {
+ return sprintf(buf, "%s\n", "OK");
+ }
+ } else {
+ return sprintf(buf, "%s\n", "NG");
+ }
+ } else {
+ return sprintf(buf, "%s\n", "NG");
+ }
+}
+
+static ssize_t camera_rear_checkfw_factory_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ read_from_firmware_version();
+
+ if(fw_version_crc_check) {
+ if (crc32_fw_check && crc32_check_factory
+#ifdef CONFIG_COMPANION_USE
+ && crc32_c1_fw_check && crc32_c1_check_factory
+#endif
+ ) {
+ if (!is_final_cam_module
+#if defined(CONFIG_SOC_EXYNOS5433)
+ || !is_right_prj_name
+#endif
+ ) {
+ return sprintf(buf, "%s\n", "NG");
+ } else {
+ return sprintf(buf, "%s\n", "OK");
+ }
+ } else {
+ return sprintf(buf, "%s\n", "NG");
+ }
+ } else {
+ return sprintf(buf, "%s\n", "NG");
+ }
+}
+
+#ifdef CONFIG_COMPANION_USE
+static ssize_t camera_rear_companionfw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char *loaded_c1_fw;
+
+ read_from_firmware_version();
+ fimc_is_sec_get_loaded_c1_fw(&loaded_c1_fw);
+
+ return sprintf(buf, "%s %s\n",
+ finfo->concord_header_ver, loaded_c1_fw);
+}
+
+static ssize_t camera_rear_companionfw_full_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char *loaded_c1_fw;
+
+ read_from_firmware_version();
+ fimc_is_sec_get_loaded_c1_fw(&loaded_c1_fw);
+
+ return sprintf(buf, "%s %s %s\n",
+ finfo->concord_header_ver, pinfo->concord_header_ver, loaded_c1_fw);
+}
+#endif
+
+static ssize_t camera_rear_camfw_write(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t ret = -EINVAL;
+
+ if ((size == 1 || size == 2) && (buf[0] == 'F' || buf[0] == 'f')) {
+ fimc_is_sec_set_force_caldata_dump(true);
+ ret = size;
+ } else {
+ fimc_is_sec_set_force_caldata_dump(false);
+ }
+ return ret;
+}
+
+static ssize_t camera_rear_calcheck_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char rear_sensor[10] = {0, };
+#ifdef CONFIG_COMPANION_USE
+ char rear_companion[10] = {0, };
+#endif
+
+ read_from_firmware_version();
+
+ if (crc32_check_factory)
+ strcpy(rear_sensor, "Normal");
+ else
+ strcpy(rear_sensor, "Abnormal");
+
+#ifdef CONFIG_COMPANION_USE
+ if (crc32_c1_check_factory)
+ strcpy(rear_companion, "Normal");
+ else
+ strcpy(rear_companion, "Abnormal");
+
+ return sprintf(buf, "%s %s %s\n", rear_sensor, rear_companion, "Null");
+#else
+ return sprintf(buf, "%s %s\n", rear_sensor, "Null");
+#endif
+}
+
+#ifdef CONFIG_COMPANION_USE
+static ssize_t camera_isp_core_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int sel;
+
+ if (DCDC_VENDOR_NONE == sysfs_core->companion_dcdc.type)
+ return sprintf(buf, "none\n");
+
+ sel = fimc_is_power_binning(sysfs_core);
+ return sprintf(buf, "%s\n", sysfs_core->companion_dcdc.get_vout_str(sel));
+}
+#endif
+
+#ifdef CONFIG_OIS_USE
+static ssize_t camera_ois_power_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+
+{
+ switch (buf[0]) {
+ case '0':
+ fimc_is_ois_gpio_off(sysfs_core->companion);
+ break;
+ case '1':
+ fimc_is_ois_gpio_on(sysfs_core->companion);
+ msleep(150);
+ break;
+ default:
+ pr_debug("%s: %c\n", __func__, buf[0]);
+ break;
+ }
+
+ return count;
+}
+
+static ssize_t camera_ois_selftest_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int result_total = 0;
+ bool result_offset = 0, result_selftest = 0;
+ int selftest_ret = 0;
+ long raw_data_x = 0, raw_data_y = 0;
+
+ fimc_is_ois_offset_test(sysfs_core, &raw_data_x, &raw_data_y);
+ msleep(50);
+ selftest_ret = fimc_is_ois_self_test(sysfs_core);
+
+ if (selftest_ret == 0x0) {
+ result_selftest = true;
+ } else {
+ result_selftest = false;
+ }
+
+ if (abs(raw_data_x) > 35000 || abs(raw_data_y) > 35000) {
+ result_offset = false;
+ } else {
+ result_offset = true;
+ }
+
+ if (result_offset && result_selftest) {
+ result_total = 0;
+ } else if (!result_offset && !result_selftest) {
+ result_total = 3;
+ } else if (!result_offset) {
+ result_total = 1;
+ } else if (!result_selftest) {
+ result_total = 2;
+ }
+
+ if (raw_data_x < 0 && raw_data_y < 0) {
+ return sprintf(buf, "%d,-%ld.%03ld,-%ld.%03ld\n", result_total, abs(raw_data_x /1000), abs(raw_data_x % 1000),
+ abs(raw_data_y /1000), abs(raw_data_y % 1000));
+ } else if (raw_data_x < 0) {
+ return sprintf(buf, "%d,-%ld.%03ld,%ld.%03ld\n", result_total, abs(raw_data_x /1000), abs(raw_data_x % 1000),
+ raw_data_y /1000, raw_data_y % 1000);
+ } else if (raw_data_y < 0) {
+ return sprintf(buf, "%d,%ld.%03ld,-%ld.%03ld\n", result_total, raw_data_x /1000, raw_data_x % 1000,
+ abs(raw_data_y /1000), abs(raw_data_y % 1000));
+ } else {
+ return sprintf(buf, "%d,%ld.%03ld,%ld.%03ld\n", result_total, raw_data_x /1000, raw_data_x % 1000,
+ raw_data_y /1000, raw_data_y % 1000);
+ }
+}
+
+static ssize_t camera_ois_rawdata_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ long raw_data_x = 0, raw_data_y = 0;
+
+ fimc_is_ois_get_offset_data(sysfs_core, &raw_data_x, &raw_data_y);
+
+ if (raw_data_x < 0 && raw_data_y < 0) {
+ return sprintf(buf, "-%ld.%03ld,-%ld.%03ld\n", abs(raw_data_x /1000), abs(raw_data_x % 1000),
+ abs(raw_data_y /1000), abs(raw_data_y % 1000));
+ } else if (raw_data_x < 0) {
+ return sprintf(buf, "-%ld.%03ld,%ld.%03ld\n", abs(raw_data_x /1000), abs(raw_data_x % 1000),
+ raw_data_y /1000, raw_data_y % 1000);
+ } else if (raw_data_y < 0) {
+ return sprintf(buf, "%ld.%03ld,-%ld.%03ld\n", raw_data_x /1000, raw_data_x % 1000,
+ abs(raw_data_y /1000), abs(raw_data_y % 1000));
+ } else {
+ return sprintf(buf, "%ld.%03ld,%ld.%03ld\n", raw_data_x /1000, raw_data_x % 1000,
+ raw_data_y /1000, raw_data_y % 1000);
+ }
+}
+
+static ssize_t camera_ois_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fimc_is_ois_info *ois_minfo = NULL;
+ struct fimc_is_ois_info *ois_pinfo = NULL;
+ u8 checksum = 0, caldata = 0;
+
+ if (!sysfs_core->running_rear_camera) {
+ fimc_is_ois_gpio_on(sysfs_core->companion);
+ msleep(150);
+ if (!sysfs_core->ois_ver_read) {
+ fimc_is_ois_check_fw(sysfs_core);
+ }
+
+ fimc_is_ois_fw_status(sysfs_core, &checksum, &caldata);
+
+ if (!sysfs_core->running_rear_camera) {
+ fimc_is_ois_gpio_off(sysfs_core->companion);
+ }
+ }
+
+ fimc_is_ois_get_module_version(&ois_minfo);
+ fimc_is_ois_get_phone_version(&ois_pinfo);
+
+ if (checksum != 0x00) {
+ return sprintf(buf, "%s %s\n", "NG_FW2", "NULL");
+ } else if (caldata != 0x00) {
+ return sprintf(buf, "%s %s\n", "NG_CD2", ois_pinfo->header_ver);
+ } else {
+ return sprintf(buf, "%s %s\n", ois_minfo->header_ver, ois_pinfo->header_ver);
+ }
+}
+
+static ssize_t camera_ois_diff_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int result = 0;
+ int x_diff = 0, y_diff = 0;
+
+ result = fimc_is_ois_diff_test(sysfs_core, &x_diff, &y_diff);
+
+ return sprintf(buf, "%d,%d,%d\n", result == true ? 0 : 1, x_diff, y_diff);
+}
+
+static ssize_t camera_ois_fw_update_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+#ifdef CONFIG_OIS_FW_UPDATE_THREAD_USE
+ fimc_is_ois_init_thread(sysfs_core);
+#else
+ fimc_is_ois_gpio_on(sysfs_core->companion);
+ msleep(150);
+
+ fimc_is_ois_fw_update(sysfs_core);
+ fimc_is_ois_gpio_off(sysfs_core->companion);
+#endif
+
+ return sprintf(buf, "%s\n", "Ois update done.");
+}
+
+static ssize_t camera_ois_exif_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fimc_is_ois_info *ois_minfo = NULL;
+ struct fimc_is_ois_info *ois_pinfo = NULL;
+ struct fimc_is_ois_info *ois_uinfo = NULL;
+ struct fimc_is_ois_exif *ois_exif = NULL;
+
+ fimc_is_ois_get_module_version(&ois_minfo);
+ fimc_is_ois_get_phone_version(&ois_pinfo);
+ fimc_is_ois_get_user_version(&ois_uinfo);
+ fimc_is_ois_get_exif_data(&ois_exif);
+
+ return sprintf(buf, "%s %s %s %d %d", ois_minfo->header_ver, ois_pinfo->header_ver,
+ ois_uinfo->header_ver, ois_exif->error_data, ois_exif->status_data);
+}
+#endif
+
+static DEVICE_ATTR(rear_camtype, S_IRUGO,
+ camera_rear_camtype_show, NULL);
+static DEVICE_ATTR(rear_camfw, S_IRUGO,
+ camera_rear_camfw_show, camera_rear_camfw_write);
+static DEVICE_ATTR(rear_camfw_full, S_IRUGO,
+ camera_rear_camfw_full_show, NULL);
+#ifdef CONFIG_COMPANION_USE
+static DEVICE_ATTR(rear_companionfw, S_IRUGO,
+ camera_rear_companionfw_show, NULL);
+static DEVICE_ATTR(rear_companionfw_full, S_IRUGO,
+ camera_rear_companionfw_full_show, NULL);
+#endif
+static DEVICE_ATTR(rear_calcheck, S_IRUGO,
+ camera_rear_calcheck_show, NULL);
+static DEVICE_ATTR(rear_checkfw_user, S_IRUGO,
+ camera_rear_checkfw_user_show, NULL);
+static DEVICE_ATTR(rear_checkfw_factory, S_IRUGO,
+ camera_rear_checkfw_factory_show, NULL);
+#ifdef CONFIG_COMPANION_USE
+static DEVICE_ATTR(isp_core, S_IRUGO,
+ camera_isp_core_show, NULL);
+#endif
+#ifdef CONFIG_OIS_USE
+static DEVICE_ATTR(selftest, S_IRUGO,
+ camera_ois_selftest_show, NULL);
+static DEVICE_ATTR(ois_power, S_IWUSR,
+ NULL, camera_ois_power_store);
+static DEVICE_ATTR(ois_rawdata, S_IRUGO,
+ camera_ois_rawdata_show, NULL);
+static DEVICE_ATTR(oisfw, S_IRUGO,
+ camera_ois_version_show, NULL);
+static DEVICE_ATTR(ois_diff, S_IRUGO,
+ camera_ois_diff_show, NULL);
+static DEVICE_ATTR(fw_update, S_IRUGO,
+ camera_ois_fw_update_show, NULL);
+static DEVICE_ATTR(ois_exif, S_IRUGO,
+ camera_ois_exif_show, NULL);
+#endif
+#endif /* CONFIG_USE_VENDER_FEATURE */
+
+static int fimc_is_suspend(struct device *dev)
+{
+ pr_debug("FIMC_IS Suspend\n");
+ return 0;
+}
+
+static int fimc_is_resume(struct device *dev)
+{
+ pr_debug("FIMC_IS Resume\n");
+ return 0;
+}
+
+#ifdef USE_OWN_FAULT_HANDLER
+static void fimc_is_print_minfo(struct fimc_is_minfo *minfo)
+{
+ if (minfo) {
+ err("dvaddr : 0x%08x, size : %d", minfo->dvaddr, minfo->size);
+ err("dvaddr_debug : 0x%08x, dvaddr_region : 0x%08x", minfo->dvaddr_debug, minfo->dvaddr_region);
+ err("dvaddr_shared : 0x%08x, dvaddr_odc : 0x%08x", minfo->dvaddr_shared, minfo->dvaddr_odc);
+ err("dvaddr_dis : 0x%08x, dvaddr_3dnr : 0x%08x", minfo->dvaddr_dis, minfo->dvaddr_3dnr);
+ } else {
+ err("core->minfo is NULL");
+ }
+}
+
+static void __fimc_is_fault_handler(struct device *dev)
+{
+ u32 i, j, k;
+ struct fimc_is_core *core;
+ struct fimc_is_device_sensor *sensor;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_framemgr *framemgr;
+
+ core = dev_get_drvdata(dev);
+ if (core) {
+
+ fimc_is_print_minfo(&core->minfo);
+ fimc_is_hw_logdump(&core->interface);
+ /* dump FW page table 1nd(~16KB), 2nd(16KB~32KB) */
+ fimc_is_hw_memdump(&core->interface,
+ core->minfo.kvaddr + 0x010F8000 /* TTB_BASE ~ 32KB */,
+ core->minfo.kvaddr + 0x010F8000 + 0x8000);
+
+ /* REAR SENSOR */
+ sensor = &core->sensor[0];
+ if (test_bit(FIMC_IS_SENSOR_OPEN, &sensor->state)) {
+ framemgr = &sensor->vctx->q_dst->framemgr;
+ for (i = 0; i < FRAMEMGR_MAX_REQUEST; ++i) {
+ pr_err("LITE0 BUF[%d][0] = %X, 0x%08X, 0x%08X\n", i,
+ (u32)framemgr->frame[i].memory,
+ framemgr->frame[i].dvaddr_buffer[0],
+ framemgr->frame[i].kvaddr_buffer[0]);
+ }
+ }
+
+ /* FRONT SENSOR */
+ sensor = &core->sensor[1];
+ if (test_bit(FIMC_IS_SENSOR_OPEN, &sensor->state)) {
+ framemgr = &sensor->vctx->q_dst->framemgr;
+ for (i = 0; i < FRAMEMGR_MAX_REQUEST; ++i) {
+ pr_err("LITE1 BUF[%d][0] = %X, 0x%08X. 0x%08X\n", i,
+ (u32)framemgr->frame[i].memory,
+ framemgr->frame[i].dvaddr_buffer[0],
+ framemgr->frame[i].kvaddr_buffer[0]);
+ }
+ }
+
+ /* ISCHAIN */
+ for (i = 0; i < FIMC_IS_MAX_NODES; i++) {
+ if (test_bit(FIMC_IS_ISCHAIN_OPEN, &(core->ischain[i].state))) {
+ ischain = &core->ischain[i];
+ /* 3AA */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->group_3aa.leader.state)) {
+ framemgr = &ischain->group_3aa.leader.vctx->q_src->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[3AA:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ /* 3AAC */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->taac.state)) {
+ framemgr = &ischain->taac.leader->vctx->q_dst->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[3AAC:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ /* 3AAP */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->taap.state)) {
+ framemgr = &ischain->taap.leader->vctx->q_dst->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[3AAP:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ /* ISP */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->group_isp.leader.state)) {
+ framemgr = &ischain->group_isp.leader.vctx->q_src->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[ISP:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ /* SCC */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->scc.state)) {
+ framemgr = &ischain->scc.vctx->q_dst->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[SCC:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ /* VDC */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->dis.state)) {
+ framemgr = &ischain->dis.vctx->q_dst->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[VDC:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ /* VDO */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->group_dis.leader.state)) {
+ framemgr = &ischain->group_dis.leader.vctx->q_src->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[VDO:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ /* SCP */
+ if (test_bit(FIMC_IS_SUBDEV_START, &ischain->scp.state)) {
+ framemgr = &ischain->scp.vctx->q_dst->framemgr;
+ for (j = 0; j < framemgr->frame_cnt; ++j) {
+ for (k = 0; k < framemgr->frame[j].planes; k++) {
+ pr_err("[SCP:%d] BUF[%d][%d] = %X, 0x%08X, 0x%08X\n",
+ i, j, k,
+ (u32)framemgr->frame[j].memory,
+ framemgr->frame[j].dvaddr_buffer[k],
+ framemgr->frame[j].kvaddr_buffer[k]);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ pr_err("failed to get core\n");
+ }
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+#define SECT_ORDER 20
+#define LPAGE_ORDER 16
+#define SPAGE_ORDER 12
+
+#define lv1ent_page(sent) ((*(sent) & 3) == 1)
+
+#define lv1ent_offset(iova) ((iova) >> SECT_ORDER)
+#define lv2ent_offset(iova) (((iova) & 0xFF000) >> SPAGE_ORDER)
+#define lv2table_base(sent) (*(sent) & 0xFFFFFC00)
+
+static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
+{
+ return pgtable + lv1ent_offset(iova);
+}
+
+static unsigned long *page_entry(unsigned long *sent, unsigned long iova)
+{
+ return (unsigned long *)__va(lv2table_base(sent)) + lv2ent_offset(iova);
+}
+
+static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
+ "PAGE FAULT",
+ "AR MULTI-HIT FAULT",
+ "AW MULTI-HIT FAULT",
+ "BUS ERROR",
+ "AR SECURITY PROTECTION FAULT",
+ "AR ACCESS PROTECTION FAULT",
+ "AW SECURITY PROTECTION FAULT",
+ "AW ACCESS PROTECTION FAULT",
+ "UNKNOWN FAULT"
+};
+
+static int fimc_is_fault_handler(struct device *dev, const char *mmuname,
+ enum exynos_sysmmu_inttype itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr)
+{
+ unsigned long *ent;
+
+ if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT))
+ itype = SYSMMU_FAULT_UNKNOWN;
+
+ pr_err("%s occured at 0x%lx by '%s'(Page table base: 0x%lx)\n",
+ sysmmu_fault_name[itype], fault_addr, mmuname, pgtable_base);
+
+ ent = section_entry(__va(pgtable_base), fault_addr);
+ pr_err("\tLv1 entry: 0x%lx\n", *ent);
+
+ if (lv1ent_page(ent)) {
+ ent = page_entry(ent, fault_addr);
+ pr_err("\t Lv2 entry: 0x%lx\n", *ent);
+ }
+
+ __fimc_is_fault_handler(dev);
+
+ pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
+
+ BUG();
+
+ return 0;
+}
+#else
+static int fimc_is_fault_handler(struct iommu_domain *domain,
+ struct device *dev,
+ unsigned long fault_addr,
+ int fault_flag,
+ void *token)
+{
+ pr_err("<FIMC-IS FAULT HANDLER>\n");
+ pr_err("Device virtual(0x%X) is invalid access\n", (u32)fault_addr);
+
+ __fimc_is_fault_handler(dev);
+
+ return -EINVAL;
+}
+#endif
+#endif /* USE_OWN_FAULT_HANDLER */
+
+static ssize_t show_clk_gate_mode(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", sysfs_debug.clk_gate_mode);
+}
+
+static ssize_t store_clk_gate_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef HAS_FW_CLOCK_GATE
+ switch (buf[0]) {
+ case '0':
+ sysfs_debug.clk_gate_mode = CLOCK_GATE_MODE_HOST;
+ break;
+ case '1':
+ sysfs_debug.clk_gate_mode = CLOCK_GATE_MODE_FW;
+ break;
+ default:
+ pr_debug("%s: %c\n", __func__, buf[0]);
+ break;
+ }
+#endif
+ return count;
+}
+
+static ssize_t show_en_clk_gate(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", sysfs_debug.en_clk_gate);
+}
+
+static ssize_t store_en_clk_gate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef ENABLE_CLOCK_GATE
+ switch (buf[0]) {
+ case '0':
+ sysfs_debug.en_clk_gate = false;
+ sysfs_debug.clk_gate_mode = CLOCK_GATE_MODE_HOST;
+ break;
+ case '1':
+ sysfs_debug.en_clk_gate = true;
+ sysfs_debug.clk_gate_mode = CLOCK_GATE_MODE_HOST;
+ break;
+ default:
+ pr_debug("%s: %c\n", __func__, buf[0]);
+ break;
+ }
+#endif
+ return count;
+}
+
+static ssize_t show_en_dvfs(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", sysfs_debug.en_dvfs);
+}
+
+static ssize_t store_en_dvfs(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef ENABLE_DVFS
+ struct fimc_is_core *core =
+ (struct fimc_is_core *)platform_get_drvdata(to_platform_device(dev));
+ struct fimc_is_resourcemgr *resourcemgr;
+ int i;
+
+ BUG_ON(!core);
+
+ resourcemgr = &core->resourcemgr;
+
+ switch (buf[0]) {
+ case '0':
+ sysfs_debug.en_dvfs = false;
+ /* update dvfs lever to max */
+ mutex_lock(&resourcemgr->dvfs_ctrl.lock);
+ for (i = 0; i < FIMC_IS_MAX_NODES; i++) {
+ if (test_bit(FIMC_IS_ISCHAIN_OPEN, &((core->ischain[i]).state)))
+ fimc_is_set_dvfs(&(core->ischain[i]), FIMC_IS_SN_MAX);
+ }
+ fimc_is_dvfs_init(resourcemgr);
+ resourcemgr->dvfs_ctrl.static_ctrl->cur_scenario_id = FIMC_IS_SN_MAX;
+ mutex_unlock(&resourcemgr->dvfs_ctrl.lock);
+ break;
+ case '1':
+ /* It can not re-define static scenario */
+ sysfs_debug.en_dvfs = true;
+ break;
+ default:
+ pr_debug("%s: %c\n", __func__, buf[0]);
+ break;
+ }
+#endif
+ return count;
+}
+
+static DEVICE_ATTR(en_clk_gate, 0644, show_en_clk_gate, store_en_clk_gate);
+static DEVICE_ATTR(clk_gate_mode, 0644, show_clk_gate_mode, store_clk_gate_mode);
+static DEVICE_ATTR(en_dvfs, 0644, show_en_dvfs, store_en_dvfs);
+
+static struct attribute *fimc_is_debug_entries[] = {
+ &dev_attr_en_clk_gate.attr,
+ &dev_attr_clk_gate_mode.attr,
+ &dev_attr_en_dvfs.attr,
+ NULL,
+};
+static struct attribute_group fimc_is_debug_attr_group = {
+ .name = "debug",
+ .attrs = fimc_is_debug_entries,
+};
+
+static int fimc_is_probe(struct platform_device *pdev)
+{
+ struct exynos_platform_fimc_is *pdata;
+ struct resource *mem_res;
+ struct resource *regs_res;
+ struct fimc_is_core *core;
+ int ret = -ENODEV;
+
+ info("%s:start\n", __func__);
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+#ifdef CONFIG_OF
+ pdata = fimc_is_parse_dt(&pdev->dev);
+ if (IS_ERR(pdata))
+#endif
+ return PTR_ERR(pdata);
+ }
+
+ core = kzalloc(sizeof(struct fimc_is_core), GFP_KERNEL);
+ if (!core) {
+ err("core is NULL");
+ return -ENOMEM;
+ }
+
+ fimc_is_dev = &pdev->dev;
+ ret = dev_set_drvdata(fimc_is_dev, core);
+ if (ret) {
+ err("dev_set_drvdata is fail(%d)", ret);
+ kfree(core);
+ return ret;
+ }
+
+#ifdef CONFIG_COMPANION_USE
+ core->companion_spi_channel = pdata->companion_spi_channel;
+ core->use_two_spi_line = pdata->use_two_spi_line;
+#endif
+#ifdef CONFIG_USE_VENDER_FEATURE
+ core->use_sensor_dynamic_voltage_mode = pdata->use_sensor_dynamic_voltage_mode;
+#ifdef CONFIG_OIS_USE
+ core->use_ois = pdata->use_ois;
+#endif /* CONFIG_OIS_USE */
+ core->use_ois_hsi2c = pdata->use_ois_hsi2c;
+ core->use_module_check = pdata->use_module_check;
+#endif
+
+#ifdef USE_ION_ALLOC
+ core->fimc_ion_client = ion_client_create(ion_exynos, "fimc-is");
+#endif
+ core->pdev = pdev;
+ core->pdata = pdata;
+ core->id = pdev->id;
+ core->debug_cnt = 0;
+ core->running_rear_camera = false;
+ core->running_front_camera = false;
+
+ device_init_wakeup(&pdev->dev, true);
+
+ /* init mutex for spi read */
+ mutex_init(&core->spi_lock);
+
+ /* for mideaserver force down */
+ atomic_set(&core->rsccount, 0);
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &core->state);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ goto p_err1;
+ }
+
+ regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+ pdev->name);
+ if (!regs_res) {
+ dev_err(&pdev->dev, "Failed to request io memory region\n");
+ goto p_err1;
+ }
+
+ core->regs_res = regs_res;
+ core->regs = ioremap_nocache(mem_res->start, resource_size(mem_res));
+ if (!core->regs) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ goto p_err2;
+ }
+
+ core->irq = platform_get_irq(pdev, 0);
+ if (core->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ goto p_err3;
+ }
+
+ ret = fimc_is_mem_probe(&core->mem, core->pdev);
+ if (ret) {
+ err("fimc_is_mem_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+
+ fimc_is_interface_probe(&core->interface,
+ (u32)core->regs,
+ core->irq,
+ core);
+
+ fimc_is_resource_probe(&core->resourcemgr, core);
+
+ /* group initialization */
+ fimc_is_groupmgr_probe(&core->groupmgr);
+
+#if defined(CONFIG_CAMERA_SENSOR_6B2_OBJ)
+ ret = sensor_6b2_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_6b2_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_8B1_OBJ)
+ ret = sensor_8b1_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_8b1_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_6D1_OBJ)
+ ret = sensor_6d1_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_6d1_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_6A3_OBJ)
+ ret = sensor_6a3_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_6a3_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_IMX134_OBJ)
+ ret = sensor_imx134_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_imx134_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_IMX135_OBJ)
+ ret = sensor_imx135_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_imx135_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_3L2_OBJ)
+ ret = sensor_3l2_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_3l2_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_2P2_OBJ)
+ ret = sensor_2p2_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_2p2_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_2P2_12M_OBJ)
+ ret = sensor_2p2_12m_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_2p2_12m_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_2P3_OBJ)
+ ret = sensor_2p3_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_2p3_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_3H5_OBJ)
+ ret = sensor_3h5_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_3h5_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_3H7_OBJ)
+ ret = sensor_3h7_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_3h7_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_3H7_SUNNY_OBJ)
+ ret = sensor_3h7_sunny_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_3h7_sunny_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_4E5_OBJ)
+ ret = sensor_4e5_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_4e5_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_IMX175_OBJ)
+ ret = sensor_imx175_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_imx175_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_IMX240_OBJ)
+ ret = sensor_imx240_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_imx175_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_IMX219_OBJ)
+ ret = sensor_imx219_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_imx219_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_SENSOR_4H5_OBJ)
+ ret = sensor_4h5_probe(NULL, NULL);
+ if (ret) {
+ err("sensor_4h5_probe is fail(%d)", ret);
+ goto p_err3;
+ }
+#endif
+
+ /* device entity - ischain0 */
+ fimc_is_ischain_probe(&core->ischain[0],
+ &core->interface,
+ &core->resourcemgr,
+ &core->groupmgr,
+ &core->mem,
+ core->pdev,
+ 0,
+ (u32)core->regs);
+
+ /* device entity - ischain1 */
+ fimc_is_ischain_probe(&core->ischain[1],
+ &core->interface,
+ &core->resourcemgr,
+ &core->groupmgr,
+ &core->mem,
+ core->pdev,
+ 1,
+ (u32)core->regs);
+
+ /* device entity - ischain2 */
+ fimc_is_ischain_probe(&core->ischain[2],
+ &core->interface,
+ &core->resourcemgr,
+ &core->groupmgr,
+ &core->mem,
+ core->pdev,
+ 2,
+ (u32)core->regs);
+
+ ret = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register fimc-is v4l2 device\n");
+ goto p_err4;
+ }
+
+ /* video entity - 3a0 */
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, 3a0))
+ fimc_is_3a0_video_probe(core);
+
+ /* video entity - 3a0 capture */
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, 3a0))
+ fimc_is_3a0c_video_probe(core);
+
+ /* video entity - 3a1 */
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, 3a1))
+ fimc_is_3a1_video_probe(core);
+
+ /* video entity - 3a1 capture */
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, 3a1))
+ fimc_is_3a1c_video_probe(core);
+
+ /* video entity - isp */
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, isp))
+ fimc_is_isp_video_probe(core);
+
+ /*front video entity - scalerC */
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, scc))
+ fimc_is_scc_video_probe(core);
+
+ /* back video entity - scalerP*/
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, scp))
+ fimc_is_scp_video_probe(core);
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, dis)) {
+ /* vdis video entity - vdis capture*/
+ fimc_is_vdc_video_probe(core);
+ /* vdis video entity - vdis output*/
+ fimc_is_vdo_video_probe(core);
+ }
+
+ platform_set_drvdata(pdev, core);
+
+ ret = fimc_is_ishcain_initmem(core);
+ if (ret) {
+ err("fimc_is_ishcain_initmem is fail(%d)", ret);
+ goto p_err4;
+ }
+
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (core->mem.alloc_ctx)
+ vb2_ion_attach_iommu(core->mem.alloc_ctx);
+#endif
+#endif
+ EXYNOS_MIF_ADD_NOTIFIER(&exynos_fimc_is_mif_throttling_nb);
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_enable(&pdev->dev);
+#endif
+
+#ifdef CONFIG_USE_VENDER_FEATURE
+ if (camera_class == NULL) {
+ camera_class = class_create(THIS_MODULE, "camera");
+ if (IS_ERR(camera_class)) {
+ pr_err("Failed to create class(camera)!\n");
+ ret = PTR_ERR(camera_class);
+ goto p_err5;
+ }
+ }
+
+ camera_front_dev = device_create(camera_class, NULL, 0, NULL, "front");
+ if (IS_ERR(camera_front_dev)) {
+ printk(KERN_ERR "failed to create front device!\n");
+ } else {
+ if (device_create_file(camera_front_dev,
+ &dev_attr_front_sensorid) < 0) {
+ printk(KERN_ERR "failed to create front device file, %s\n",
+ dev_attr_front_sensorid.attr.name);
+ }
+
+ if (device_create_file(camera_front_dev,
+ &dev_attr_front_camtype)
+ < 0) {
+ printk(KERN_ERR
+ "failed to create front device file, %s\n",
+ dev_attr_front_camtype.attr.name);
+ }
+ if (device_create_file(camera_front_dev,
+ &dev_attr_front_camfw) < 0) {
+ printk(KERN_ERR
+ "failed to create front device file, %s\n",
+ dev_attr_front_camfw.attr.name);
+ }
+ }
+ camera_rear_dev = device_create(camera_class, NULL, 1, NULL, "rear");
+ if (IS_ERR(camera_rear_dev)) {
+ printk(KERN_ERR "failed to create rear device!\n");
+ } else {
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_sensorid) < 0) {
+ printk(KERN_ERR "failed to create rear device file, %s\n",
+ dev_attr_rear_sensorid.attr.name);
+ }
+
+ if (device_create_file(camera_rear_dev, &dev_attr_rear_camtype)
+ < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_camtype.attr.name);
+ }
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_camfw) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_camfw.attr.name);
+ }
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_camfw_full) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_camfw_full.attr.name);
+ }
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_checkfw_user) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_checkfw_user.attr.name);
+ }
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_checkfw_factory) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_checkfw_factory.attr.name);
+ }
+#ifdef CONFIG_COMPANION_USE
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_companionfw) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_companionfw.attr.name);
+ }
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_companionfw_full) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_companionfw_full.attr.name);
+ }
+#endif
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_rear_calcheck) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_rear_calcheck.attr.name);
+ }
+#ifdef CONFIG_COMPANION_USE
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_isp_core) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_isp_core.attr.name);
+ }
+#endif
+#ifdef CONFIG_OIS_USE
+ if (device_create_file(camera_rear_dev,
+ &dev_attr_fw_update) < 0) {
+ printk(KERN_ERR
+ "failed to create rear device file, %s\n",
+ dev_attr_fw_update.attr.name);
+ }
+#endif
+ }
+
+#ifdef CONFIG_OIS_USE
+ camera_ois_dev = device_create(camera_class, NULL, 2, NULL, "ois");
+ if (IS_ERR(camera_ois_dev)) {
+ printk(KERN_ERR "failed to create ois device!\n");
+ } else {
+ if (device_create_file(camera_ois_dev,
+ &dev_attr_selftest) < 0) {
+ printk(KERN_ERR
+ "failed to create ois device file, %s\n",
+ dev_attr_selftest.attr.name);
+ }
+ if (device_create_file(camera_ois_dev,
+ &dev_attr_ois_power) < 0) {
+ printk(KERN_ERR
+ "failed to create ois device file, %s\n",
+ dev_attr_ois_power.attr.name);
+ }
+ if (device_create_file(camera_ois_dev,
+ &dev_attr_ois_rawdata) < 0) {
+ printk(KERN_ERR
+ "failed to create ois device file, %s\n",
+ dev_attr_ois_rawdata.attr.name);
+ }
+ if (device_create_file(camera_ois_dev,
+ &dev_attr_oisfw) < 0) {
+ printk(KERN_ERR
+ "failed to create ois device file, %s\n",
+ dev_attr_oisfw.attr.name);
+ }
+ if (device_create_file(camera_ois_dev,
+ &dev_attr_ois_diff) < 0) {
+ printk(KERN_ERR
+ "failed to create ois device file, %s\n",
+ dev_attr_ois_diff.attr.name);
+ }
+ if (device_create_file(camera_ois_dev,
+ &dev_attr_ois_exif) < 0) {
+ printk(KERN_ERR
+ "failed to create ois device file, %s\n",
+ dev_attr_ois_exif.attr.name);
+ }
+ }
+#endif
+
+ sysfs_core = core;
+#endif
+
+#ifdef USE_OWN_FAULT_HANDLER
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ exynos_sysmmu_set_fault_handler(fimc_is_dev, fimc_is_fault_handler);
+#else
+ iovmm_set_fault_handler(fimc_is_dev, fimc_is_fault_handler, NULL);
+#endif
+#endif
+
+ dbg("%s : fimc_is_front_%d probe success\n", __func__, pdev->id);
+
+ /* set sysfs for debuging */
+ sysfs_debug.en_clk_gate = 0;
+ sysfs_debug.en_dvfs = 1;
+#ifdef ENABLE_CLOCK_GATE
+ sysfs_debug.en_clk_gate = 1;
+#ifdef HAS_FW_CLOCK_GATE
+ sysfs_debug.clk_gate_mode = CLOCK_GATE_MODE_FW;
+#else
+ sysfs_debug.clk_gate_mode = CLOCK_GATE_MODE_HOST;
+#endif
+#endif
+ ret = sysfs_create_group(&core->pdev->dev.kobj, &fimc_is_debug_attr_group);
+
+#ifdef ENABLE_DVFS
+ {
+ struct fimc_is_resourcemgr *resourcemgr;
+ resourcemgr = &core->resourcemgr;
+ /* dvfs controller init */
+ ret = fimc_is_dvfs_init(resourcemgr);
+ if (ret)
+ err("%s: fimc_is_dvfs_init failed!\n", __func__);
+ }
+#endif
+
+ info("%s:end\n", __func__);
+ return 0;
+
+#ifdef CONFIG_USE_VENDER_FEATURE
+p_err5:
+#if defined(CONFIG_PM_RUNTIME)
+ __pm_runtime_disable(&pdev->dev, false);
+#endif
+#endif /* CONFIG_USE_VENDER_FEATURE */
+p_err4:
+ v4l2_device_unregister(&core->v4l2_dev);
+p_err3:
+ iounmap(core->regs);
+p_err2:
+ release_mem_region(regs_res->start, resource_size(regs_res));
+p_err1:
+ kfree(core);
+ return ret;
+}
+
+static int fimc_is_remove(struct platform_device *pdev)
+{
+ dbg("%s\n", __func__);
+
+ if (camera_front_dev) {
+ device_remove_file(camera_front_dev, &dev_attr_front_sensorid);
+ device_remove_file(camera_front_dev, &dev_attr_front_camtype);
+ device_remove_file(camera_front_dev, &dev_attr_front_camfw);
+ }
+
+ if (camera_rear_dev) {
+ device_remove_file(camera_rear_dev, &dev_attr_rear_sensorid);
+ device_remove_file(camera_rear_dev, &dev_attr_rear_camtype);
+ device_remove_file(camera_rear_dev, &dev_attr_rear_camfw);
+ device_remove_file(camera_rear_dev, &dev_attr_rear_camfw_full);
+ device_remove_file(camera_rear_dev, &dev_attr_rear_checkfw_user);
+ device_remove_file(camera_rear_dev, &dev_attr_rear_checkfw_factory);
+#ifdef CONFIG_COMPANION_USE
+ device_remove_file(camera_rear_dev, &dev_attr_rear_companionfw);
+ device_remove_file(camera_rear_dev, &dev_attr_rear_companionfw_full);
+#endif
+ device_remove_file(camera_rear_dev, &dev_attr_rear_calcheck);
+#ifdef CONFIG_COMPANION_USE
+ device_remove_file(camera_rear_dev, &dev_attr_isp_core);
+#endif
+#ifdef CONFIG_OIS_USE
+ device_remove_file(camera_ois_dev, &dev_attr_fw_update);
+#endif
+ }
+
+#ifdef CONFIG_OIS_USE
+ if (camera_ois_dev) {
+ device_remove_file(camera_ois_dev, &dev_attr_selftest);
+ device_remove_file(camera_ois_dev, &dev_attr_ois_power);
+ device_remove_file(camera_ois_dev, &dev_attr_ois_rawdata);
+ device_remove_file(camera_ois_dev, &dev_attr_oisfw);
+ device_remove_file(camera_ois_dev, &dev_attr_ois_diff);
+ device_remove_file(camera_ois_dev, &dev_attr_ois_exif);
+ }
+#endif
+
+ if (camera_class) {
+ if (camera_front_dev)
+ device_destroy(camera_class, camera_front_dev->devt);
+
+ if (camera_rear_dev)
+ device_destroy(camera_class, camera_rear_dev->devt);
+
+#ifdef CONFIG_OIS_USE
+ if (camera_ois_dev)
+ device_destroy(camera_class, camera_ois_dev->devt);
+#endif
+ }
+
+ class_destroy(camera_class);
+
+ return 0;
+}
+
+static const struct dev_pm_ops fimc_is_pm_ops = {
+ .suspend = fimc_is_suspend,
+ .resume = fimc_is_resume,
+ .runtime_suspend = fimc_is_runtime_suspend,
+ .runtime_resume = fimc_is_runtime_resume,
+};
+
+#ifdef CONFIG_USE_VENDER_FEATURE
+#if defined(CONFIG_COMPANION_USE)
+static int fimc_is_i2c0_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fimc_is_core *core;
+ static bool probe_retried = false;
+
+ if (!fimc_is_dev)
+ goto probe_defer;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core)
+ goto probe_defer;
+
+ core->client0 = client;
+
+ pr_info("%s %s: fimc_is_i2c0 driver probed!\n",
+ dev_driver_string(&client->dev), dev_name(&client->dev));
+
+ return 0;
+
+probe_defer:
+ if (probe_retried) {
+ err("probe has already been retried!!");
+ BUG();
+ }
+
+ probe_retried = true;
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+}
+
+static int fimc_is_i2c0_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id fimc_is_i2c0_dt_ids[] = {
+ { .compatible = "samsung,fimc_is_i2c0",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, fimc_is_i2c0_dt_ids);
+#endif
+
+static const struct i2c_device_id fimc_is_i2c0_id[] = {
+ {"fimc_is_i2c0", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, fimc_is_i2c0_id);
+
+static struct i2c_driver fimc_is_i2c0_driver = {
+ .driver = {
+ .name = "fimc_is_i2c0",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = fimc_is_i2c0_dt_ids,
+#endif
+ },
+ .probe = fimc_is_i2c0_probe,
+ .remove = fimc_is_i2c0_remove,
+ .id_table = fimc_is_i2c0_id,
+};
+module_i2c_driver(fimc_is_i2c0_driver);
+#endif
+
+#if defined(CONFIG_OF) && defined(CONFIG_COMPANION_USE)
+static int of_fimc_is_spi_dt(struct device *dev, struct fimc_is_spi_gpio *spi_gpio, struct fimc_is_core *core)
+{
+ struct device_node *np;
+ int ret;
+
+ np = of_find_compatible_node(NULL,NULL,"samsung,fimc_is_spi1");
+ if(np == NULL) {
+ pr_err("compatible: fail to read, spi_parse_dt\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_string(np, "fimc_is_spi_sclk", (const char **) &spi_gpio->spi_sclk);
+ if (ret) {
+ pr_err("spi gpio: fail to read, spi_parse_dt\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_string(np, "fimc_is_spi_ssn",(const char **) &spi_gpio->spi_ssn);
+ if (ret) {
+ pr_err("spi gpio: fail to read, spi_parse_dt\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_string(np, "fimc_is_spi_miso",(const char **) &spi_gpio->spi_miso);
+ if (ret) {
+ pr_err("spi gpio: fail to read, spi_parse_dt\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_string(np, "fimc_is_spi_mois",(const char **) &spi_gpio->spi_mois);
+ if (ret) {
+ pr_err("spi gpio: fail to read, spi_parse_dt\n");
+ return -ENODEV;
+ }
+
+ pr_info("sclk = %s, ssn = %s, miso = %s, mois = %s spi_channel:(%d)\n", spi_gpio->spi_sclk, spi_gpio->spi_ssn, spi_gpio->spi_miso, spi_gpio->spi_mois,core->companion_spi_channel);
+
+ return 0;
+}
+#endif
+#endif
+
+#ifdef CONFIG_OF
+static int fimc_is_spi_probe(struct spi_device *spi)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+
+ BUG_ON(!fimc_is_dev);
+
+ dbg_core("%s\n", __func__);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+ spi->mode = SPI_MODE_0;
+
+ /* spi->bits_per_word = 16; */
+ if (spi_setup(spi)) {
+ pr_err("failed to setup spi for fimc_is_spi\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (!strncmp(spi->modalias, "fimc_is_spi0", 12))
+ core->spi0 = spi;
+
+ if (!strncmp(spi->modalias, "fimc_is_spi1", 12)) {
+ core->spi1 = spi;
+#ifdef CONFIG_COMPANION_USE
+ ret = of_fimc_is_spi_dt(&spi->dev,&core->spi_gpio, core);
+ if (ret) {
+ pr_err("[%s] of_fimc_is_spi_dt parse dt failed\n", __func__);
+ return ret;
+ }
+#endif
+ }
+
+exit:
+ return ret;
+}
+
+static int fimc_is_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+#if defined(CONFIG_USE_VENDER_FEATURE) && defined(CONFIG_COMPANION_USE)
+static int fimc_is_fan53555_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fimc_is_core *core;
+ int ret = 0;
+#ifdef CONFIG_SOC_EXYNOS5422
+ struct regulator *regulator = NULL;
+ const char power_name[] = "CAM_IO_1.8V_AP";
+#endif
+ struct device_node *np;
+ int gpio_comp_en;
+
+ BUG_ON(!fimc_is_dev);
+
+ pr_info("%s start\n",__func__);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "samsung,fimc_is_fan53555");
+ if(np == NULL) {
+ pr_err("compatible: fail to read, fan_parse_dt\n");
+ return -ENODEV;
+ }
+
+ gpio_comp_en = of_get_named_gpio(np, "comp_en", 0);
+ if (!gpio_is_valid(gpio_comp_en))
+ pr_err("failed to get comp en gpio\n");
+
+ ret = gpio_request(gpio_comp_en,"COMP_EN");
+ if (ret < 0 )
+ pr_err("gpio_request_error(%d)\n",ret);
+
+ gpio_direction_output(gpio_comp_en,1);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ pr_err("%s: SMBUS Byte Data not Supported\n", __func__);
+ ret = -EIO;
+ goto err;
+ }
+
+ core->companion_dcdc.client = client;
+ core->companion_dcdc.type = DCDC_VENDOR_FAN53555;
+ core->companion_dcdc.get_vout_val = fan53555_get_vout_val;
+ core->companion_dcdc.get_vout_str = fan53555_get_vout_str;
+ core->companion_dcdc.set_vout = fan53555_set_vsel0_vout;
+
+#ifdef CONFIG_SOC_EXYNOS5422
+ regulator = regulator_get(NULL, power_name);
+ if (IS_ERR(regulator)) {
+ pr_err("%s : regulator_get(%s) fail\n", __func__, power_name);
+ return PTR_ERR(regulator);
+ }
+
+ if (regulator_is_enabled(regulator)) {
+ pr_info("%s regulator is already enabled\n", power_name);
+ } else {
+ ret = regulator_enable(regulator);
+ if (unlikely(ret)) {
+ pr_err("%s : regulator_enable(%s) fail\n", __func__, power_name);
+ goto err;
+ }
+ }
+ usleep_range(1000, 1000);
+#endif
+
+ ret = i2c_smbus_write_byte_data(client, REG_VSEL0, VSEL0_INIT_VAL);
+ if (ret < 0) {
+ pr_err("%s: write error = %d , try again\n", __func__, ret);
+ ret = i2c_smbus_write_byte_data(client, REG_VSEL0, VSEL0_INIT_VAL);
+ if (ret < 0)
+ pr_err("%s: write 2nd error = %d\n", __func__, ret);
+ }
+
+ ret = i2c_smbus_read_byte_data(client, REG_VSEL0);
+ if (ret < 0) {
+ pr_err("%s: read error = %d , try again\n", __func__, ret);
+ ret = i2c_smbus_read_byte_data(client, REG_VSEL0);
+ if (ret < 0)
+ pr_err("%s: read 2nd error = %d\n", __func__, ret);
+ }
+ pr_err("[%s::%d]fan53555 [Read :: %x ,%x]\n\n", __func__, __LINE__, ret,VSEL0_INIT_VAL);
+
+#ifdef CONFIG_SOC_EXYNOS5422
+ ret = regulator_disable(regulator);
+ if (unlikely(ret)) {
+ pr_err("%s: regulator_disable(%s) fail\n", __func__, power_name);
+ goto err;
+ }
+ regulator_put(regulator);
+#endif
+ gpio_direction_output(gpio_comp_en,0);
+ gpio_free(gpio_comp_en);
+
+ pr_info(" %s end\n",__func__);
+
+ return 0;
+
+err:
+ gpio_direction_output(gpio_comp_en, 0);
+ gpio_free(gpio_comp_en);
+
+#ifdef CONFIG_SOC_EXYNOS5422
+ if (!IS_ERR_OR_NULL(regulator)) {
+ ret = regulator_disable(regulator);
+ if (unlikely(ret)) {
+ pr_err("%s: regulator_disable(%s) fail\n", __func__, power_name);
+ }
+ regulator_put(regulator);
+ }
+#endif
+ return ret;
+}
+
+static int fimc_is_fan53555_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int fimc_is_ncp6335b_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fimc_is_core *core;
+ int ret = 0;
+
+ struct device_node *np;
+ int gpio_comp_en;
+
+ BUG_ON(!fimc_is_dev);
+
+ pr_info("%s start\n",__func__);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ pr_err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "samsung,fimc_is_ncp6335b");
+ if(np == NULL) {
+ pr_err("compatible: fail to read, fan_parse_dt\n");
+ return -ENODEV;
+ }
+
+ gpio_comp_en = of_get_named_gpio(np, "comp_en", 0);
+ if (!gpio_is_valid(gpio_comp_en))
+ pr_err("failed to get comp en gpio\n");
+
+ ret = gpio_request(gpio_comp_en,"COMP_EN");
+ if (ret < 0 )
+ pr_err("gpio_request_error(%d)\n",ret);
+
+ gpio_direction_output(gpio_comp_en,1);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ pr_err("%s: SMBUS Byte Data not Supported\n", __func__);
+ ret = -EIO;
+ goto err;
+ }
+
+ core->companion_dcdc.client = client;
+ core->companion_dcdc.type = DCDC_VENDOR_NCP6335B;
+ core->companion_dcdc.get_vout_val = ncp6335b_get_vout_val;
+ core->companion_dcdc.get_vout_str = ncp6335b_get_vout_str;
+ core->companion_dcdc.set_vout = ncp6335b_set_voltage;
+
+ ret = ncp6335b_set_voltage(client, 0xC0);
+ if (ret < 0) {
+ pr_err("%s: error, fail to set voltage\n", __func__);
+ goto err;
+ }
+
+ ret = ncp6335b_read_voltage(client);
+ if (ret < 0) {
+ pr_err("%s: error, fail to read voltage\n", __func__);
+ goto err;
+ }
+
+ pr_info("%s %s: ncp6335b probed\n",
+ dev_driver_string(&client->dev), dev_name(&client->dev));
+
+err:
+ gpio_direction_output(gpio_comp_en,0);
+ gpio_free(gpio_comp_en);
+
+ return ret;
+}
+
+static int fimc_is_ncp6335b_remove(struct i2c_client *client)
+{
+ return 0;
+}
+#endif
+
+static const struct of_device_id exynos_fimc_is_match[] = {
+ {
+ .compatible = "samsung,exynos5-fimc-is",
+ },
+ {
+ .compatible = "samsung,fimc_is_spi0",
+ },
+ {
+ .compatible = "samsung,fimc_is_spi1",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_fimc_is_match);
+
+static struct spi_driver fimc_is_spi0_driver = {
+ .driver = {
+ .name = "fimc_is_spi0",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ .of_match_table = exynos_fimc_is_match,
+ },
+ .probe = fimc_is_spi_probe,
+ .remove = fimc_is_spi_remove,
+};
+
+module_spi_driver(fimc_is_spi0_driver);
+
+static struct spi_driver fimc_is_spi1_driver = {
+ .driver = {
+ .name = "fimc_is_spi1",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ .of_match_table = exynos_fimc_is_match,
+ },
+ .probe = fimc_is_spi_probe,
+ .remove = fimc_is_spi_remove,
+};
+
+module_spi_driver(fimc_is_spi1_driver);
+
+#ifdef CONFIG_COMPANION_USE
+static struct of_device_id fan53555_dt_ids[] = {
+ { .compatible = "samsung,fimc_is_fan53555",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, fan53555_dt_ids);
+
+static const struct i2c_device_id fan53555_id[] = {
+ {"fimc_is_fan53555", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, fan53555_id);
+
+static struct i2c_driver fan53555_driver = {
+ .driver = {
+ .name = "fimc_is_fan53555",
+ .owner = THIS_MODULE,
+ .of_match_table = fan53555_dt_ids,
+ },
+ .probe = fimc_is_fan53555_probe,
+ .remove = fimc_is_fan53555_remove,
+ .id_table = fan53555_id,
+};
+module_i2c_driver(fan53555_driver);
+
+static struct of_device_id ncp6335b_dt_ids[] = {
+ { .compatible = "samsung,fimc_is_ncp6335b",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ncp6335b_dt_ids);
+
+static const struct i2c_device_id ncp6335b_id[] = {
+ {"fimc_is_ncp6335b", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ncp6335b_id);
+
+static struct i2c_driver ncp6335b_driver = {
+ .driver = {
+ .name = "fimc_is_ncp6335b",
+ .owner = THIS_MODULE,
+ .of_match_table = ncp6335b_dt_ids,
+ },
+ .probe = fimc_is_ncp6335b_probe,
+ .remove = fimc_is_ncp6335b_remove,
+ .id_table = ncp6335b_id,
+};
+module_i2c_driver(ncp6335b_driver);
+#endif
+
+static struct platform_driver fimc_is_driver = {
+ .probe = fimc_is_probe,
+ .remove = fimc_is_remove,
+ .driver = {
+ .name = FIMC_IS_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_pm_ops,
+ .of_match_table = exynos_fimc_is_match,
+ }
+};
+
+module_platform_driver(fimc_is_driver);
+#else
+static struct platform_driver fimc_is_driver = {
+ .probe = fimc_is_probe,
+ .remove = __devexit_p(fimc_is_remove),
+ .driver = {
+ .name = FIMC_IS_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_pm_ops,
+ }
+};
+
+static int __init fimc_is_init(void)
+{
+ int ret = platform_driver_register(&fimc_is_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+ return ret;
+}
+
+static void __exit fimc_is_exit(void)
+{
+ platform_driver_unregister(&fimc_is_driver);
+}
+module_init(fimc_is_init);
+module_exit(fimc_is_exit);
+#endif
+
+MODULE_AUTHOR("Jiyoung Shin<idon.shin@samsung.com>");
+MODULE_DESCRIPTION("Exynos FIMC_IS2 driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_CORE_H
+#define FIMC_IS_CORE_H
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#include <linux/sched/rt.h>
+#endif
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <mach/exynos-fimc-is.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+#ifdef CONFIG_COMPANION_USE
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "fimc-is-companion.h"
+#ifdef CONFIG_SOC_EXYNOS5422
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#endif
+#endif
+
+#include "fimc-is-param.h"
+#include "fimc-is-interface.h"
+#include "fimc-is-framemgr.h"
+#include "fimc-is-resourcemgr.h"
+#include "fimc-is-device-sensor.h"
+#include "fimc-is-device-ischain.h"
+#include "fimc-is-device-companion.h"
+
+#include "fimc-is-video.h"
+#include "fimc-is-mem.h"
+
+#define FIMC_IS_DRV_NAME "exynos-fimc-is"
+
+#define FIMC_IS_COMMAND_TIMEOUT (3*HZ)
+#define FIMC_IS_STARTUP_TIMEOUT (3*HZ)
+#define FIMC_IS_COMPANION_TIMEOUT (1*HZ)
+
+#define FIMC_IS_SHUTDOWN_TIMEOUT (10*HZ)
+#define FIMC_IS_FLITE_STOP_TIMEOUT (3*HZ)
+
+#define FIMC_IS_SENSOR_MAX_ENTITIES (1)
+#define FIMC_IS_SENSOR_PAD_SOURCE_FRONT (0)
+#define FIMC_IS_SENSOR_PADS_NUM (1)
+
+#define FIMC_IS_FRONT_MAX_ENTITIES (1)
+#define FIMC_IS_FRONT_PAD_SINK (0)
+#define FIMC_IS_FRONT_PAD_SOURCE_BACK (1)
+#define FIMC_IS_FRONT_PAD_SOURCE_BAYER (2)
+#define FIMC_IS_FRONT_PAD_SOURCE_SCALERC (3)
+#define FIMC_IS_FRONT_PADS_NUM (4)
+
+#define FIMC_IS_BACK_MAX_ENTITIES (1)
+#define FIMC_IS_BACK_PAD_SINK (0)
+#define FIMC_IS_BACK_PAD_SOURCE_3DNR (1)
+#define FIMC_IS_BACK_PAD_SOURCE_SCALERP (2)
+#define FIMC_IS_BACK_PADS_NUM (3)
+
+#define FIMC_IS_MAX_SENSOR_NAME_LEN (16)
+
+#define FIMC_IS_A5_MEM_SIZE (0x01400000)
+#define FIMC_IS_REGION_SIZE (0x00005000)
+#define FIMC_IS_SETFILE_SIZE (0x00140000)
+#define FIMC_IS_DEBUG_REGION_ADDR (0x01340000)
+#define FIMC_IS_SHARED_REGION_ADDR (0x013C0000)
+
+#define FIMC_IS_FW_BASE_MASK ((1 << 26) - 1)
+
+#define FW_SHARED_OFFSET FIMC_IS_SHARED_REGION_ADDR
+#define DEBUG_CNT (0x0007D000) /* 500KB */
+#define DEBUG_OFFSET FIMC_IS_DEBUG_REGION_ADDR
+#define DEBUGCTL_OFFSET (DEBUG_OFFSET + DEBUG_CNT)
+
+#define MAX_ODC_INTERNAL_BUF_WIDTH (2560) /* 4808 in HW */
+#define MAX_ODC_INTERNAL_BUF_HEIGHT (1920) /* 3356 in HW */
+#define SIZE_ODC_INTERNAL_BUF \
+ (MAX_ODC_INTERNAL_BUF_WIDTH * MAX_ODC_INTERNAL_BUF_HEIGHT * 3)
+
+#define MAX_DIS_INTERNAL_BUF_WIDTH (2400)
+#define MAX_DIS_INTERNAL_BUF_HEIGHT (1360)
+#define SIZE_DIS_INTERNAL_BUF \
+ (MAX_DIS_INTERNAL_BUF_WIDTH * MAX_DIS_INTERNAL_BUF_HEIGHT * 2)
+
+#define MAX_3DNR_INTERNAL_BUF_WIDTH (1920)
+#define MAX_3DNR_INTERNAL_BUF_HEIGHT (1088)
+#define SIZE_DNR_INTERNAL_BUF \
+ (MAX_3DNR_INTERNAL_BUF_WIDTH * MAX_3DNR_INTERNAL_BUF_HEIGHT * 2)
+
+#define NUM_ODC_INTERNAL_BUF (2)
+#define NUM_DIS_INTERNAL_BUF (1)
+#define NUM_DNR_INTERNAL_BUF (2)
+
+#define GATE_IP_ISP (0)
+#define GATE_IP_DRC (1)
+#define GATE_IP_FD (2)
+#define GATE_IP_SCC (3)
+#define GATE_IP_SCP (4)
+#define GATE_IP_ODC (0)
+#define GATE_IP_DIS (1)
+#define GATE_IP_DNR (2)
+#if defined(CONFIG_SOC_EXYNOS5422)
+#define DVFS_L0 (600000)
+#define DVFS_L1 (500000)
+#define DVFS_L1_1 (480000)
+#define DVFS_L1_2 (460000)
+#define DVFS_L1_3 (440000)
+
+#define DVFS_MIF_L0 (825000)
+#define DVFS_MIF_L1 (728000)
+#define DVFS_MIF_L2 (633000)
+#define DVFS_MIF_L3 (543000)
+#define DVFS_MIF_L4 (413000)
+#define DVFS_MIF_L5 (275000)
+
+#define I2C_L0 (108000000)
+#define I2C_L1 (36000000)
+#define I2C_L1_1 (54000000)
+#define I2C_L2 (21600000)
+#define DVFS_SKIP_FRAME_NUM (5)
+#elif defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+#define DVFS_L0 (600000)
+#define DVFS_L1 (500000)
+#define DVFS_L1_1 (480000)
+#define DVFS_L1_2 (460000)
+#define DVFS_L1_3 (440000)
+
+#define DVFS_MIF_L0 (800000)
+#define DVFS_MIF_L1 (733000)
+#define DVFS_MIF_L2 (667000)
+#define DVFS_MIF_L3 (533000)
+#define DVFS_MIF_L4 (400000)
+#define DVFS_MIF_L5 (266000)
+
+#define I2C_L0 (83000000)
+#define I2C_L1 (36000000)
+#define I2C_L1_1 (54000000)
+#define I2C_L2 (21600000)
+#define DVFS_SKIP_FRAME_NUM (5)
+#elif defined(CONFIG_SOC_EXYNOS3470) || defined(CONFIG_SOC_EXYNOS3472) ||defined(CONFIG_SOC_EXYNOS5260) || defined(CONFIG_SOC_EXYNOS4415)
+#define DVFS_L0 (266000)
+#define DVFS_MIF_L0 (400000)
+#define I2C_L0 (108000000)
+#define I2C_L1 (36000000)
+#define I2C_L1_1 (54000000)
+#define I2C_L2 (21600000)
+#endif
+
+#define I2C_RETRY_COUNT 5
+
+#define GET_FIMC_IS_NUM_OF_SUBIP(core, subip) \
+ (core->pdata->subip_info->_ ## subip.valid)
+#define GET_FIMC_IS_NUM_OF_SUBIP2(device, subip) \
+ (((struct fimc_is_core *)device->interface->core)->pdata->subip_info->_ ## subip.valid)
+#define GET_FIMC_IS_VER_OF_SUBIP(core, subip) \
+ ((core)->pdata->subip_info->_##subip.version)
+#define GET_FIMC_IS_VER_OF_SUBIP2(device, subip) \
+ (((struct fimc_is_core *)device->interface->core)->pdata->subip_info->_ ## subip.version)
+#define GET_FIMC_IS_ADDR_OF_SUBIP(core, subip) \
+ ((core)->pdata->subip_info->_##subip.base_addr)
+#define GET_FIMC_IS_ADDR_OF_SUBIP2(device, subip) \
+ (((struct fimc_is_core *)device->interface->core)->pdata->subip_info->_ ## subip.base_addr)
+
+enum fimc_is_debug_device {
+ FIMC_IS_DEBUG_MAIN = 0,
+ FIMC_IS_DEBUG_EC,
+ FIMC_IS_DEBUG_SENSOR,
+ FIMC_IS_DEBUG_ISP,
+ FIMC_IS_DEBUG_DRC,
+ FIMC_IS_DEBUG_FD,
+ FIMC_IS_DEBUG_SDK,
+ FIMC_IS_DEBUG_SCALERC,
+ FIMC_IS_DEBUG_ODC,
+ FIMC_IS_DEBUG_DIS,
+ FIMC_IS_DEBUG_TDNR,
+ FIMC_IS_DEBUG_SCALERP
+};
+
+enum fimc_is_debug_target {
+ FIMC_IS_DEBUG_UART = 0,
+ FIMC_IS_DEBUG_MEMORY,
+ FIMC_IS_DEBUG_DCC3
+};
+
+enum fimc_is_front_input_entity {
+ FIMC_IS_FRONT_INPUT_NONE = 0,
+ FIMC_IS_FRONT_INPUT_SENSOR,
+};
+
+enum fimc_is_front_output_entity {
+ FIMC_IS_FRONT_OUTPUT_NONE = 0,
+ FIMC_IS_FRONT_OUTPUT_BACK,
+ FIMC_IS_FRONT_OUTPUT_BAYER,
+ FIMC_IS_FRONT_OUTPUT_SCALERC,
+};
+
+enum fimc_is_back_input_entity {
+ FIMC_IS_BACK_INPUT_NONE = 0,
+ FIMC_IS_BACK_INPUT_FRONT,
+};
+
+enum fimc_is_back_output_entity {
+ FIMC_IS_BACK_OUTPUT_NONE = 0,
+ FIMC_IS_BACK_OUTPUT_3DNR,
+ FIMC_IS_BACK_OUTPUT_SCALERP,
+};
+
+enum fimc_is_front_state {
+ FIMC_IS_FRONT_ST_POWERED = 0,
+ FIMC_IS_FRONT_ST_STREAMING,
+ FIMC_IS_FRONT_ST_SUSPENDED,
+};
+
+enum fimc_is_clck_gate_mode {
+ CLOCK_GATE_MODE_HOST = 0,
+ CLOCK_GATE_MODE_FW,
+};
+
+struct fimc_is_sysfs_debug {
+ unsigned int en_dvfs;
+ unsigned int en_clk_gate;
+ unsigned int clk_gate_mode;
+};
+
+#ifdef CONFIG_COMPANION_USE
+struct fimc_is_spi_gpio {
+ char *spi_sclk;
+ char *spi_ssn;
+ char *spi_miso;
+ char *spi_mois;
+};
+#endif
+
+struct fimc_is_core {
+ struct platform_device *pdev;
+ struct resource *regs_res;
+ void __iomem *regs;
+ int irq;
+ u32 id;
+ u32 debug_cnt;
+ atomic_t rsccount;
+ unsigned long state;
+
+ /* depended on isp */
+ struct exynos_platform_fimc_is *pdata;
+
+ struct fimc_is_resourcemgr resourcemgr;
+ struct fimc_is_groupmgr groupmgr;
+
+ struct fimc_is_minfo minfo;
+ struct fimc_is_mem mem;
+ struct fimc_is_interface interface;
+
+ struct fimc_is_device_sensor sensor[FIMC_IS_MAX_NODES];
+ struct fimc_is_device_ischain ischain[FIMC_IS_MAX_NODES];
+ struct fimc_is_device_companion *companion;
+
+ struct v4l2_device v4l2_dev;
+
+ /* 0-bayer, 1-scalerC, 2-3DNR, 3-scalerP */
+ struct fimc_is_video video_3a0;
+ struct fimc_is_video video_3a1;
+ struct fimc_is_video video_isp;
+ struct fimc_is_video video_scc;
+ struct fimc_is_video video_scp;
+ struct fimc_is_video video_vdc;
+ struct fimc_is_video video_vdo;
+ struct fimc_is_video video_3a0c;
+ struct fimc_is_video video_3a1c;
+
+ /* spi */
+ struct spi_device *spi0;
+ struct spi_device *spi1;
+
+#if defined(CONFIG_COMPANION_USE)
+ struct i2c_client *client0;
+#endif
+#if defined(CONFIG_OIS_USE)
+ struct i2c_client *client1;
+#endif
+#ifdef CONFIG_AF_HOST_CONTROL
+ struct i2c_client *client2;
+#endif
+ struct i2c_client *eeprom_client0;
+ struct i2c_client *eeprom_client1;
+
+#ifdef CONFIG_COMPANION_USE
+ struct dcdc_power companion_dcdc;
+ struct fimc_is_spi_gpio spi_gpio;
+ u32 companion_spi_channel;
+ bool use_two_spi_line;
+#endif
+ u32 use_sensor_dynamic_voltage_mode;
+ struct mutex spi_lock;
+#ifdef CONFIG_OIS_USE
+ bool use_ois;
+ int pin_ois_en;
+ bool ois_ver_read;
+#endif /* CONFIG_OIS_USE */
+ bool use_ois_hsi2c;
+ bool use_module_check;
+#ifdef USE_ION_ALLOC
+ struct ion_client *fimc_ion_client;
+#endif
+ bool running_rear_camera;
+ bool running_front_camera;
+};
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct fimc_is_vb2 fimc_is_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+extern const struct fimc_is_vb2 fimc_is_vb2_ion;
+#endif
+
+extern struct device *fimc_is_dev;
+
+void fimc_is_mem_suspend(void *alloc_ctxes);
+void fimc_is_mem_resume(void *alloc_ctxes);
+void fimc_is_mem_cache_clean(const void *start_addr, unsigned long size);
+void fimc_is_mem_cache_inv(const void *start_addr, unsigned long size);
+int fimc_is_init_set(struct fimc_is_core *dev , u32 val);
+int fimc_is_load_fw(struct fimc_is_core *dev);
+int fimc_is_load_setfile(struct fimc_is_core *dev);
+int fimc_is_otf_close(struct fimc_is_device_ischain *ischain);
+int fimc_is_spi_reset(void *buf, u32 rx_addr, size_t size);
+int fimc_is_spi_read(void *buf, u32 rx_addr, size_t size);
+int fimc_is_runtime_suspend(struct device *dev);
+int fimc_is_runtime_resume(struct device *dev);
+
+#define CALL_POPS(s, op, args...) (((s)->pdata->op) ? ((s)->pdata->op(args)) : -EPERM)
+
+#endif /* FIMC_IS_CORE_H_ */
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <mach/pinctrl-samsung.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-interface.h"
+//#include "fimc-is-sec-define.h"
+#include "fimc-is-device-ischain.h"
+#include "fimc-is-dt.h"
+#include "fimc-is-device-af.h"
+
+#define FIMC_IS_AF_DEV_NAME "exynos-fimc-is-af"
+static int af_noise_count;
+
+static struct remove_af_noise af_sensor_interface = {
+ .af_pdata = NULL,
+ .af_func = NULL,
+};
+
+static void fimc_is_af_i2c_config(struct i2c_client *client, bool onoff)
+{
+ struct device *i2c_dev = client->dev.parent->parent;
+ struct pinctrl *pinctrl_i2c = NULL;
+
+ info("(%s):onoff(%d)\n", __func__, onoff);
+ if (onoff) {
+ /* ON */
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 0));
+
+ pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "on_i2c");
+ if (IS_ERR_OR_NULL(pinctrl_i2c)) {
+ printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__);
+ } else {
+ devm_pinctrl_put(pinctrl_i2c);
+ }
+ } else {
+ /* OFF */
+ pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "off_i2c");
+ if (IS_ERR_OR_NULL(pinctrl_i2c)) {
+ printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__);
+ } else {
+ devm_pinctrl_put(pinctrl_i2c);
+ }
+
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+ }
+}
+
+int fimc_is_af_i2c_read(struct i2c_client *client, u16 addr, u16 *data)
+{
+ int err;
+ u8 rxbuf[2], txbuf[2];
+ struct i2c_msg msg[2];
+
+ txbuf[0] = (addr & 0xff00) >> 8;
+ txbuf[1] = (addr & 0xff);
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = txbuf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = rxbuf;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (unlikely(err != 2)) {
+ err("%s: register read fail err = %d\n", __func__, err);
+ return -EIO;
+ }
+
+ *data = ((rxbuf[0] << 8) | rxbuf[1]);
+ return 0;
+}
+
+int fimc_is_af_i2c_write(struct i2c_client *client ,u16 addr, u16 data)
+{
+ int retries = I2C_RETRY_COUNT;
+ int ret = 0, err = 0;
+ u8 buf[4] = {0,};
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 4,
+ .buf = buf,
+ };
+
+ buf[0] = addr >> 8;
+ buf[1] = addr;
+ buf[2] = data >> 8;
+ buf[3] = data & 0xff;
+
+#if 0
+ pr_info("%s : W(0x%02X%02X%02X%02X)\n",__func__, buf[0], buf[1], buf[2], buf[3]);
+#endif
+
+ do {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (likely(ret == 1))
+ break;
+
+ usleep_range(10000,11000);
+ err = ret;
+ } while (--retries > 0);
+
+ /* Retry occured */
+ if (unlikely(retries < I2C_RETRY_COUNT)) {
+ err("i2c_write: error %d, write (%04X, %04X), retry %d\n",
+ err, addr, data, I2C_RETRY_COUNT - retries);
+ }
+
+ if (unlikely(ret != 1)) {
+ err("I2C does not work\n\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int fimc_is_af_ldo_enable(char *name, bool on)
+{
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ struct regulator *regulator = NULL;
+ struct platform_device *pdev = NULL;
+ int ret = 0;
+
+ BUG_ON(!core);
+ BUG_ON(!core->pdev);
+
+ pdev = core->pdev;
+
+ regulator = regulator_get(&pdev->dev, name);
+ if (IS_ERR_OR_NULL(regulator)) {
+ err("%s : regulator_get(%s) fail\n", __func__, name);
+ return -EINVAL;
+ }
+
+ if (on) {
+ if (regulator_is_enabled(regulator)) {
+ pr_info("%s: regulator is already enabled\n", name);
+ ret = 0;
+ } else {
+ ret = regulator_enable(regulator);
+ if (ret) {
+ err("%s : regulator_enable(%s) fail\n", __func__, name);
+ ret = -EINVAL;
+ }
+ }
+ } else {
+ if (!regulator_is_enabled(regulator)) {
+ pr_info("%s: regulator is already disabled\n", name);
+ ret = 0;
+ } else {
+ ret = regulator_disable(regulator);
+ if (ret) {
+ err("%s : regulator_disable(%s) fail\n", __func__, name);
+ ret = -EINVAL;
+ }
+ }
+ }
+
+ regulator_put(regulator);
+
+ return ret;
+}
+
+int fimc_is_af_power(struct fimc_is_device_af *af_device, bool onoff)
+{
+ int ret = 0;
+#ifdef CONFIG_OIS_USE
+ int pin_ois_en = af_device->core->pin_ois_en;
+#endif
+
+ /*CAM_AF_2.8V_AP*/
+ ret = fimc_is_af_ldo_enable("CAM_AF_2.8V_AP", onoff);
+ if (ret) {
+ err("failed to power control CAM_AF_2.8V_AP, onoff = %d", onoff);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_OIS_USE
+ /* OIS_VDD_2.8V */
+ if (gpio_is_valid(pin_ois_en)) {
+ if (onoff) {
+ gpio_request_one(pin_ois_en, GPIOF_OUT_INIT_HIGH, "CAM_GPIO_OUTPUT_HIGH");
+ } else {
+ gpio_request_one(pin_ois_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ }
+ gpio_free(pin_ois_en);
+ }
+
+ /* OIS_VM_2.8V */
+ ret = fimc_is_af_ldo_enable("OIS_VM_2.8V", onoff);
+ if (ret) {
+ err("failed to power control OIS_VM_2.8V, onoff = %d", onoff);
+ return -EINVAL;
+ }
+#endif
+
+ /*CAM_IO_1.8V_AP*/
+ ret = fimc_is_af_ldo_enable("CAM_IO_1.8V_AP", onoff);
+ if (ret) {
+ err("failed to power control CAM_IO_1.8V_AP, onoff = %d", onoff);
+ return -EINVAL;
+ }
+
+ usleep_range(5000,5000);
+ return ret;
+}
+
+bool fimc_is_check_regulator_status(char *name)
+{
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ struct regulator *regulator = NULL;
+ struct platform_device *pdev = NULL;
+ int ret = 0;
+
+ BUG_ON(!core);
+ BUG_ON(!core->pdev);
+
+ pdev = core->pdev;
+
+ regulator = regulator_get(&pdev->dev, name);
+ if (IS_ERR_OR_NULL(regulator)) {
+ err("%s : regulator_get(%s) fail\n", __func__, name);
+ return false;
+ }
+ if (regulator_is_enabled(regulator)) {
+ ret = true;
+ } else {
+ ret = false;
+ }
+
+ regulator_put(regulator);
+ return ret;
+}
+
+int16_t fimc_is_af_enable(void *device, bool onoff)
+{
+ int ret = 0;
+ struct fimc_is_device_af *af_device = (struct fimc_is_device_af *)device;
+ struct fimc_is_core *core;
+ bool af_regulator = false, io_regulator = false;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is NULL");
+ return -ENODEV;
+ }
+
+ pr_info("af_noise : running_rear_camera = %d, onoff = %d\n", core->running_rear_camera, onoff);
+ if (!core->running_rear_camera) {
+ if (core->use_ois_hsi2c) {
+ fimc_is_af_i2c_config(af_device->client, true);
+ }
+
+ if (onoff) {
+ fimc_is_af_power(af_device, true);
+ ret = fimc_is_af_i2c_write(af_device->client, 0x02, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ goto power_off;
+ }
+
+ ret = fimc_is_af_i2c_write(af_device->client, 0x00, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ goto power_off;
+ }
+
+ ret = fimc_is_af_i2c_write(af_device->client, 0x01, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ goto power_off;
+ }
+ af_noise_count++;
+ pr_info("af_noise : count = %d\n", af_noise_count);
+ } else {
+ /* Check the Power Pins */
+ af_regulator = fimc_is_check_regulator_status("CAM_AF_2.8V_AP");
+ io_regulator = fimc_is_check_regulator_status("CAM_IO_1.8V_AP");
+
+ if (af_regulator && io_regulator) {
+ ret = fimc_is_af_i2c_write(af_device->client, 0x02, 0x40);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+ fimc_is_af_power(af_device, false);
+ } else {
+ pr_info("already power off.(%d)\n", __LINE__);
+ }
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_af_i2c_config(af_device->client, false);
+ }
+ }
+
+ return ret;
+
+power_off:
+ if (!core->running_rear_camera) {
+ if (core->use_ois_hsi2c) {
+ fimc_is_af_i2c_config(af_device->client, false);
+ }
+
+ af_regulator = fimc_is_check_regulator_status("CAM_AF_2.8V_AP");
+ io_regulator = fimc_is_check_regulator_status("CAM_IO_1.8V_AP");
+ if (af_regulator && io_regulator) {
+ fimc_is_af_power(af_device, false);
+ } else {
+ pr_info("already power off.(%d)\n", __LINE__);
+ }
+ }
+ return ret;
+}
+
+int16_t fimc_is_af_move_lens(struct fimc_is_core *core)
+{
+ int ret = 0;
+ struct i2c_client *client = core->client2;
+
+ pr_info("fimc_is_af_move_lens : running_rear_camera = %d\n", core->running_rear_camera);
+ if (!core->running_rear_camera) {
+ ret = fimc_is_af_i2c_write(client, 0x00, 0x80);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_af_i2c_write(client, 0x01, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_af_i2c_write(client, 0x02, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_SENSORS_SSP_BBD
+extern int remove_af_noise_register(struct remove_af_noise *af_cam);
+extern void remove_af_noise_unregister(struct remove_af_noise *af_cam);
+#endif
+static int fimc_is_af_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fimc_is_device_af *device;
+ struct fimc_is_core *core;
+#ifdef CONFIG_SENSORS_SSP_BBD
+ int ret;
+#endif
+
+ if (fimc_is_dev == NULL) {
+ warn("fimc_is_dev is not yet probed");
+ client->dev.init_name = FIMC_IS_AF_DEV_NAME;
+ return -EPROBE_DEFER;
+ }
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core)
+ return -EINVAL;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ err("No I2C functionality found\n");
+ return -ENODEV;
+ }
+
+ device = kzalloc(sizeof(struct fimc_is_device_af), GFP_KERNEL);
+ if (!device) {
+ err("fimc_is_device_companion is NULL");
+ return -ENOMEM;
+ }
+
+ core->client2 = client;
+ device->client = client;
+ device->core = core;
+ af_noise_count = 0;
+
+ af_sensor_interface.af_pdata = device;
+ af_sensor_interface.af_func = &fimc_is_af_enable;
+#ifdef CONFIG_SENSORS_SSP_BBD
+ ret = remove_af_noise_register(&af_sensor_interface);
+ if (ret)
+ err("reduce_af_noise_register failed: %d\n", ret);
+#endif
+ i2c_set_clientdata(client, device);
+
+ return 0;
+}
+
+static int fimc_is_af_remove(struct i2c_client *client)
+{
+#ifdef CONFIG_SENSORS_SSP_BBD
+ remove_af_noise_unregister(&af_sensor_interface);
+#endif
+ return 0;
+}
+
+static const struct i2c_device_id af_id[] = {
+ {FIMC_IS_AF_DEV_NAME, 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, af_id);
+
+#ifdef CONFIG_OF
+static struct of_device_id af_dt_ids[] = {
+ { .compatible = "samsung,af",},
+ {},
+};
+#endif
+
+static struct i2c_driver af_i2c_driver = {
+ .driver = {
+ .name = FIMC_IS_AF_DEV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = af_dt_ids,
+#endif
+ },
+ .probe = fimc_is_af_probe,
+ .remove = fimc_is_af_remove,
+ .id_table = af_id,
+};
+
+module_i2c_driver(af_i2c_driver);
+
+MODULE_DESCRIPTION("AF driver for remove noise");
+MODULE_AUTHOR("kyoungho yun <kyoungho.yun@samsung.com>");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS AF driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+struct fimc_is_device_af {
+ struct v4l2_device v4l2_dev;
+ struct platform_device *pdev;
+ unsigned long state;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct i2c_client *client;
+ struct fimc_is_core *core;
+};
+
+struct remove_af_noise {
+ void *af_pdata;
+ int16_t (*af_func)(void *, bool);
+};
+
+int fimc_is_af_i2c_read(struct i2c_client *client, u16 addr, u16 *data);
+int fimc_is_af_i2c_write(struct i2c_client *client ,u16 addr, u16 data);
+int16_t fimc_is_af_enable(void *device, bool onoff);
+int16_t fimc_is_af_move_lens(struct fimc_is_core *core);
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+#include <linux/i2c.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/pinctrl-samsung.h>
+
+#include "fimc-is-video.h"
+#include "fimc-is-dt.h"
+#include "fimc-is-device-companion.h"
+#include "fimc-is-sec-define.h"
+#if defined(CONFIG_OIS_USE)
+#include "fimc-is-device-ois.h"
+#endif
+#ifdef CONFIG_COMPANION_USE
+#include "fimc-is-companion-dt.h"
+#endif
+extern int fimc_is_comp_video_probe(void *data);
+
+int fimc_is_companion_wait(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(device->init_wait_queue,
+ (device->companion_status == FIMC_IS_COMPANION_OPENDONE),
+ FIMC_IS_COMPANION_TIMEOUT);
+ if (ret) {
+ ret = 0;
+ } else {
+ err("timeout");
+ device->companion_status = FIMC_IS_COMPANION_IDLE;
+ ret = -ETIME;
+ }
+
+ return ret;
+}
+
+static void fimc_is_companion_wakeup(struct fimc_is_device_companion *device)
+{
+ wake_up(&device->init_wait_queue);
+}
+
+static int fimc_is_companion_mclk_on(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct platform_device *pdev;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdev = device->pdev;
+ pdata = device->pdata;
+
+ if (test_bit(FIMC_IS_COMPANION_MCLK_ON, &device->state)) {
+ err("%s : already clk on", __func__);
+ goto p_err;
+ }
+
+ if (!pdata->mclk_on) {
+ err("mclk_on is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->mclk_on(pdev, pdata->scenario, pdata->mclk_ch);
+ if (ret) {
+ err("mclk_on is fail(%d)", ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_COMPANION_MCLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_companion_mclk_off(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct platform_device *pdev;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdev = device->pdev;
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_COMPANION_MCLK_ON, &device->state)) {
+ err("%s : already clk off", __func__);
+ goto p_err;
+ }
+
+ if (!pdata->mclk_off) {
+ err("mclk_off is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->mclk_off(pdev, pdata->scenario, pdata->mclk_ch);
+ if (ret) {
+ err("mclk_off is fail(%d)", ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_COMPANION_MCLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_companion_iclk_on(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct platform_device *pdev;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdev = device->pdev;
+ pdata = device->pdata;
+
+ if (test_bit(FIMC_IS_COMPANION_ICLK_ON, &device->state)) {
+ err("%s : already clk on", __func__);
+ goto p_err;
+ }
+
+ if (!pdata->iclk_cfg) {
+ err("iclk_cfg is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!pdata->iclk_on) {
+ err("iclk_on is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->iclk_cfg(pdev, pdata->scenario, 0);
+ if (ret) {
+ err("iclk_cfg is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = pdata->iclk_on(pdev, pdata->scenario, 0);
+ if (ret) {
+ err("iclk_on is fail(%d)", ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_COMPANION_ICLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_companion_iclk_off(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct platform_device *pdev;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdev = device->pdev;
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_COMPANION_ICLK_ON, &device->state)) {
+ err("%s : already clk off", __func__);
+ goto p_err;
+ }
+
+ if (!pdata->iclk_off) {
+ err("iclk_off is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->iclk_off(pdev, pdata->scenario, 0);
+ if (ret) {
+ err("iclk_off is fail(%d)", ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_COMPANION_ICLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_companion_gpio_on(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ struct fimc_is_from_info *sysfs_finfo;
+ struct exynos_sensor_pin (*pin_ctrls)[2][GPIO_CTRL_MAX];
+#endif
+ struct fimc_is_core *core;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ pin_ctrls = pdata->pin_ctrls;
+#endif
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+
+ if (test_bit(FIMC_IS_COMPANION_GPIO_ON, &device->state)) {
+ err("%s : already gpio on", __func__);
+ goto p_err;
+ }
+
+ if (!pdata->gpio_cfg) {
+ err("gpio_cfg is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ core->running_rear_camera = true;
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ if(core->use_sensor_dynamic_voltage_mode) {
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ if (pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][0].name != NULL &&
+ !strcmp(pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][0].name, "CAM_SEN_A2.8V_AP")) {
+ if (sysfs_finfo->header_ver[1] == '1' && sysfs_finfo->header_ver[2] == '6' && sysfs_finfo->header_ver[4] == 'L') {
+ pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][0].voltage = 2950000;
+ info("LSI Sensor EVT2.4 voltage(%d)\n", pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][0].voltage);
+ } else {
+ pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][0].voltage = 2800000;
+ }
+ }
+
+#if defined(CONFIG_SOC_EXYNOS5433)
+ if (pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][1].name != NULL &&
+ !strcmp(pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][1].name, "CAM_SEN_CORE_1.2V_AP")) {
+ if (sysfs_finfo->header_ver[1] == '1' && sysfs_finfo->header_ver[2] == '6' && sysfs_finfo->header_ver[4] == 'S') {
+ pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][1].voltage = 1050000;
+ info("SONY Sensor voltage(%d)\n", pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][1].voltage);
+ } else {
+ pin_ctrls[pdata->scenario][GPIO_SCENARIO_ON][1].voltage = 1200000;
+ }
+ }
+#endif
+ }
+#endif
+
+ ret = pdata->gpio_cfg(device->pdev, pdata->scenario, GPIO_SCENARIO_ON);
+ if (ret) {
+ err("gpio_cfg is fail(%d)", ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_COMPANION_GPIO_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_companion_gpio_off(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_COMPANION_GPIO_ON, &device->state)) {
+ err("%s : already gpio off", __func__);
+ goto p_err;
+ }
+
+ if (!pdata->gpio_cfg) {
+ err("gpio_cfg is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->gpio_cfg(device->pdev, pdata->scenario, GPIO_SCENARIO_OFF);
+ if (ret) {
+ err("gpio_cfg is fail(%d)", ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_COMPANION_GPIO_ON, &device->state);
+
+p_err:
+ core->running_rear_camera = false;
+
+ return ret;
+}
+
+
+int fimc_is_companion_open(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ /* Workaround for Host to use ISP-SPI. Will be removed later.*/
+ struct fimc_is_spi_gpio *spi_gpio;
+ static char companion_fw_name[100];
+ static char master_setf_name[100];
+ static char mode_setf_name[100];
+#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ static char fw_name[100];
+ static char setf_name[100];
+#endif
+
+ BUG_ON(!device);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ spi_gpio = &core->spi_gpio;
+
+ if (test_bit(FIMC_IS_COMPANION_OPEN, &device->state)) {
+ err("already open");
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+ device->companion_status = FIMC_IS_COMPANION_OPENNING;
+ core->running_rear_camera = true;
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_get_sync(&device->pdev->dev);
+#else
+ fimc_is_companion_runtime_resume(&device->pdev->dev);
+#endif
+#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ ret = fimc_is_sec_fw_sel(core, &device->pdev->dev, fw_name, setf_name, false);
+ if (ret < 0) {
+ err("failed to select firmware (%d)", ret);
+ goto p_err_pm;
+ }
+#endif
+ ret = fimc_is_sec_concord_fw_sel(core, &device->pdev->dev, companion_fw_name, master_setf_name, mode_setf_name);
+
+ /* TODO: loading firmware */
+ fimc_is_s_int_comb_isp(core, false, INTMR2_INTMCIS22);
+
+ // Workaround for Host to use ISP-SPI. Will be removed later.
+ /* set pin output for Host to use SPI*/
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_ssn,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, FUNC_OUTPUT));
+
+ fimc_is_set_spi_config(spi_gpio, FIMC_IS_SPI_FUNC, false);
+
+ if (fimc_is_comp_is_valid(core) == 0) {
+ ret = fimc_is_comp_loadfirm(core);
+ if (ret) {
+ err("fimc_is_comp_loadfirm() fail");
+ goto p_err_pm;
+ }
+ ret = fimc_is_comp_loadcal(core);
+ if (ret) {
+ err("fimc_is_comp_loadcal() fail");
+ }
+
+ fimc_is_power_binning(core);
+
+ ret = fimc_is_comp_loadsetf(core);
+ if (ret) {
+ err("fimc_is_comp_loadsetf() fail");
+ goto p_err_pm;
+ }
+ }
+
+ // Workaround for Host to use ISP-SPI. Will be removed later.
+ /* Set SPI pins to low before changing pin function */
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_sclk,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_ssn,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_miso,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_mois,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+
+ /* Set pin function for A5 to use SPI */
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_ssn,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+
+ set_bit(FIMC_IS_COMPANION_OPEN, &device->state);
+ device->companion_status = FIMC_IS_COMPANION_OPENDONE;
+ fimc_is_companion_wakeup(device);
+
+#if defined(CONFIG_OIS_USE)
+ if(core->use_ois) {
+ if (!core->use_ois_hsi2c) {
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 1));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 1));
+ }
+
+ if (!core->ois_ver_read) {
+ fimc_is_ois_check_fw(core);
+ }
+
+ fimc_is_ois_exif_data(core);
+
+ if (!core->use_ois_hsi2c) {
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+ }
+ }
+#endif
+
+ info("[COMP:D] %s(%d)status(%d)\n", __func__, ret, device->companion_status);
+ return ret;
+
+p_err_pm:
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(&device->pdev->dev);
+#else
+ fimc_is_companion_runtime_suspend(&device->pdev->dev);
+#endif
+
+p_err:
+ err("[COMP:D] open fail(%d)status(%d)", ret, device->companion_status);
+ return ret;
+}
+
+int fimc_is_companion_close(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ u32 timeout;
+#endif
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is NULL");
+ return -EINVAL;
+ }
+
+ BUG_ON(!device);
+
+ if (!test_bit(FIMC_IS_COMPANION_OPEN, &device->state)) {
+ err("already close");
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(&device->pdev->dev);
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ if (core != NULL && !test_bit(FIMC_IS_ISCHAIN_POWER_ON, &core->state)) {
+ warn("only companion device closing after open..");
+ timeout = 2000;
+ while ((readl(PMUREG_CAM1_STATUS) & 0x1) && timeout) {
+ timeout--;
+ usleep_range(1000, 1000);
+ if (!(timeout % 100))
+ warn("wait for CAM1 power down..(%d)", timeout);
+ }
+ if (timeout == 0)
+ err("CAM1 power down failed(CAM1:0x%08x, A5:0x%08x)\n",
+ readl(PMUREG_CAM1_STATUS), readl(PMUREG_ISP_ARM_STATUS));
+ }
+#endif
+#else
+ fimc_is_companion_runtime_suspend(&device->pdev->dev);
+#endif /* CONFIG_PM_RUNTIME */
+
+ clear_bit(FIMC_IS_COMPANION_OPEN, &device->state);
+
+p_err:
+ core->running_rear_camera = false;
+ device->companion_status = FIMC_IS_COMPANION_IDLE;
+ info("[COMP:D] %s(%d)\n", __func__, ret);
+ return ret;
+}
+
+static int fimc_is_companion_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_device_companion *device;
+ void *pdata;
+
+ BUG_ON(!pdev);
+
+ if (fimc_is_dev == NULL) {
+ warn("fimc_is_dev is not yet probed");
+ pdev->dev.init_name = FIMC_IS_COMPANION_DEV_NAME;
+ return -EPROBE_DEFER;
+ }
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is NULL");
+ return -EINVAL;
+ }
+
+
+ device = kzalloc(sizeof(struct fimc_is_device_companion), GFP_KERNEL);
+ if (!device) {
+ err("fimc_is_device_companion is NULL");
+ return -ENOMEM;
+ }
+
+ init_waitqueue_head(&device->init_wait_queue);
+
+ device->companion_status = FIMC_IS_COMPANION_IDLE;
+
+#ifdef CONFIG_OF
+ ret = fimc_is_companion_parse_dt(pdev);
+ if (ret) {
+ err("parsing device tree is fail(%d)", ret);
+ goto p_err;
+ }
+#endif
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ err("pdata is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device->pdev = pdev;
+ device->private_data = core;
+ device->regs = core->regs;
+ device->pdata = pdata;
+ platform_set_drvdata(pdev, device);
+ device_init_wakeup(&pdev->dev, true);
+ core->companion = device;
+#ifdef CONFIG_OIS_USE
+ core->pin_ois_en = device->pdata->pin_ois_en;
+#endif
+
+ /* init state */
+ clear_bit(FIMC_IS_COMPANION_OPEN, &device->state);
+ clear_bit(FIMC_IS_COMPANION_MCLK_ON, &device->state);
+ clear_bit(FIMC_IS_COMPANION_ICLK_ON, &device->state);
+ clear_bit(FIMC_IS_COMPANION_GPIO_ON, &device->state);
+
+ ret = v4l2_device_register(&pdev->dev, &device->v4l2_dev);
+ if (ret) {
+ err("v4l2_device_register is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_comp_video_probe(device);
+ if (ret) {
+ err("fimc_is_companion_video_probe is fail(%d)", ret);
+ goto p_err;
+ }
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_enable(&pdev->dev);
+#endif
+
+ info("[COMP:D] %s(%d)\n", __func__, ret);
+
+ return ret;
+
+p_err:
+ kfree(device);
+ return ret;
+}
+
+static int fimc_is_companion_remove(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ info("%s\n", __func__);
+
+ return ret;
+}
+
+static int fimc_is_companion_suspend(struct device *dev)
+{
+ int ret = 0;
+
+ info("%s\n", __func__);
+
+ return ret;
+}
+
+static int fimc_is_companion_resume(struct device *dev)
+{
+ int ret = 0;
+
+ info("%s\n", __func__);
+
+ return ret;
+}
+
+int fimc_is_companion_runtime_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_device_companion *device;
+#ifdef CONFIG_AF_HOST_CONTROL
+ struct fimc_is_core *core;
+#endif
+
+ info("%s\n", __func__);
+
+#ifdef CONFIG_AF_HOST_CONTROL
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is NULL");
+ return -EINVAL;
+ }
+#endif
+ device = (struct fimc_is_device_companion *)platform_get_drvdata(pdev);
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto err_dev_null;
+ }
+
+ /* gpio uninit */
+ ret = fimc_is_companion_gpio_off(device);
+ if (ret) {
+ err("fimc_is_companion_gpio_off is fail(%d)", ret);
+ goto p_err;
+ }
+
+ /* periperal internal clock off */
+ ret = fimc_is_companion_iclk_off(device);
+ if (ret) {
+ err("fimc_is_companion_iclk_off is fail(%d)", ret);
+ goto p_err;
+ }
+
+ /* companion clock off */
+ ret = fimc_is_companion_mclk_off(device);
+ if (ret) {
+ err("fimc_is_companion_mclk_off is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ info("[COMP:D] %s(%d)\n", __func__, ret);
+err_dev_null:
+ return ret;
+}
+
+int fimc_is_companion_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_device_companion *device;
+#ifdef CONFIG_AF_HOST_CONTROL
+ struct fimc_is_core *core;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is NULL");
+ return -EINVAL;
+ }
+#endif
+ device = (struct fimc_is_device_companion *)platform_get_drvdata(pdev);
+ if (!device) {
+ err("device is NULL");
+ return -EINVAL;
+ }
+
+ /* Sensor clock on */
+ ret = fimc_is_companion_mclk_on(device);
+ if (ret) {
+ err("fimc_is_companion_mclk_on is fail(%d)", ret);
+ goto p_err;
+ }
+
+ /* gpio init */
+ ret = fimc_is_companion_gpio_on(device);
+ if (ret) {
+ err("fimc_is_companion_gpio_on is fail(%d)", ret);
+ goto p_err;
+ }
+
+ /* periperal internal clock on */
+ ret = fimc_is_companion_iclk_on(device);
+ if (ret) {
+ err("fimc_is_companion_iclk_on is fail(%d)", ret);
+ goto p_err;
+ }
+p_err:
+ info("[COMP:D] %s(%d)\n", __func__, ret);
+ return ret;
+}
+
+static const struct dev_pm_ops fimc_is_companion_pm_ops = {
+ .suspend = fimc_is_companion_suspend,
+ .resume = fimc_is_companion_resume,
+ .runtime_suspend = fimc_is_companion_runtime_suspend,
+ .runtime_resume = fimc_is_companion_runtime_resume,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_fimc_is_companion_match[] = {
+ {
+ .compatible = "samsung,exynos5-fimc-is-companion",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_fimc_is_companion_match);
+
+static struct platform_driver fimc_is_companion_driver = {
+ .probe = fimc_is_companion_probe,
+ .remove = fimc_is_companion_remove,
+ .driver = {
+ .name = FIMC_IS_COMPANION_DEV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_companion_pm_ops,
+ .of_match_table = exynos_fimc_is_companion_match,
+ }
+};
+
+module_platform_driver(fimc_is_companion_driver);
+#else
+static struct platform_device_id fimc_is_companion_driver_ids[] = {
+ {
+ .name = FIMC_IS_COMPANION_DEV_NAME,
+ .driver_data = 0,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, fimc_is_companion_driver_ids);
+
+static struct platform_driver fimc_is_companion_driver = {
+ .probe = fimc_is_companion_probe,
+ .remove = __devexit_p(fimc_is_companion_remove),
+ .id_table = fimc_is_companion_driver_ids,
+ .driver = {
+ .name = FIMC_IS_COMPANION_DEV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_companion_pm_ops,
+ }
+};
+
+static int __init fimc_is_companion_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_register(&fimc_is_companion_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+
+ return ret;
+}
+
+static void __exit fimc_is_companion_exit(void)
+{
+ platform_driver_unregister(&fimc_is_companion_driver);
+}
+module_init(fimc_is_companion_init);
+module_exit(fimc_is_companion_exit);
+#endif
+
+MODULE_AUTHOR("Wooki Min<wooki.min@samsung.com>");
+MODULE_DESCRIPTION("Exynos FIMC_IS_COMPANION driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * 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 fimc_is_device_companion_H
+#define fimc_is_device_companion_H
+
+#include <mach/exynos-fimc-is-sensor.h>
+#include <linux/interrupt.h>
+#include "fimc-is-video.h"
+
+struct fimc_is_video_ctx;
+
+#define FIMC_IS_COMPANION_DEV_NAME "exynos-fimc-is-companion"
+
+enum fimc_is_companion_state {
+ FIMC_IS_COMPANION_OPEN,
+ FIMC_IS_COMPANION_MCLK_ON,
+ FIMC_IS_COMPANION_ICLK_ON,
+ FIMC_IS_COMPANION_GPIO_ON,
+};
+
+enum fimc_is_companion_status {
+ FIMC_IS_COMPANION_IDLE,
+ FIMC_IS_COMPANION_OPENNING,
+ FIMC_IS_COMPANION_OPENDONE,
+};
+
+struct fimc_is_device_companion {
+ struct v4l2_device v4l2_dev;
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct fimc_is_mem mem;
+
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_video video;
+
+ unsigned long state;
+
+ struct exynos_platform_fimc_is_sensor *pdata;
+ void *private_data;
+ wait_queue_head_t init_wait_queue;
+ int companion_status;
+};
+
+int fimc_is_companion_open(struct fimc_is_device_companion *device);
+int fimc_is_companion_close(struct fimc_is_device_companion *device);
+int fimc_is_companion_wait(struct fimc_is_device_companion *device);
+int fimc_is_companion_runtime_suspend(struct device *dev);
+int fimc_is_companion_runtime_resume(struct device *dev);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is/mipi-csi functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/exynos5-mipiphy.h>
+
+#include "fimc-is-config.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-hw.h"
+#include "fimc-is-device-csi.h"
+#include "fimc-is-device-sensor.h"
+
+#if (FIMC_IS_CSI_VERSION == CSI_VERSION_0000_0000)
+extern void s5pcsis_enable_interrupts(unsigned long __iomem *base_reg, struct fimc_is_image *image, bool on);
+extern void s5pcsis_set_hsync_settle(unsigned long __iomem *base_reg, int settle);
+extern void s5pcsis_set_params(unsigned long __iomem *base_reg, struct fimc_is_image *image, u32 lanes);
+extern void s5pcsis_reset(unsigned long __iomem *base_reg);
+extern void s5pcsis_system_enable(unsigned long __iomem *base_reg, int on, u32 lanes);
+#endif
+
+static u32 get_hsync_settle(struct fimc_is_sensor_cfg *cfg,
+ const u32 cfgs, u32 width, u32 height, u32 framerate)
+{
+ u32 settle;
+ u32 max_settle;
+ u32 proximity_framerate, proximity_settle;
+ u32 i;
+
+ settle = 0;
+ max_settle = 0;
+ proximity_framerate = 0;
+ proximity_settle = 0;
+
+ for (i = 0; i < cfgs; i++) {
+ if ((cfg[i].width == width) &&
+ (cfg[i].height == height) &&
+ (cfg[i].framerate == framerate)) {
+ settle = cfg[i].settle;
+ break;
+ }
+
+ if ((cfg[i].width == width) &&
+ (cfg[i].height == height) &&
+ (cfg[i].framerate > proximity_framerate)) {
+ proximity_settle = cfg[i].settle;
+ proximity_framerate = cfg[i].framerate;
+ }
+
+ if (cfg[i].settle > max_settle)
+ max_settle = cfg[i].settle;
+ }
+
+ if (!settle) {
+ if (proximity_settle) {
+ settle = proximity_settle;
+ } else {
+ /*
+ * return a max settle time value in above table
+ * as a default depending on the channel
+ */
+ settle = max_settle;
+
+ warn("could not find proper settle time: %dx%d@%dfps",
+ width, height, framerate);
+ }
+ }
+
+ return settle;
+}
+
+#if (FIMC_IS_CSI_VERSION == CSI_VERSION_0310_0100)
+static u32 get_vci_channel(struct fimc_is_vci *vci,
+ const u32 vcis, u32 pixelformat)
+{
+ u32 i;
+ u32 index = vcis;
+
+ BUG_ON(!vci);
+
+ for (i = 0; i < vcis; i++) {
+ if (vci[i].pixelformat == pixelformat) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == vcis) {
+ err("invalid vc setting(foramt : %d)", pixelformat);
+ BUG();
+ }
+
+ return index;
+}
+#endif
+
+int fimc_is_csi_open(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_device_csi *csi;
+
+ BUG_ON(!subdev);
+
+ csi = v4l2_get_subdevdata(subdev);
+ if (!csi) {
+ err("csi is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ csi->sensor_cfgs = 0;
+ csi->sensor_cfg = NULL;
+ memset(&csi->image, 0, sizeof(struct fimc_is_image));
+
+p_err:
+ return ret;
+}
+
+int fimc_is_csi_close(struct v4l2_subdev *subdev)
+{
+ return 0;
+}
+
+/* value : module enum */
+static int csi_init(struct v4l2_subdev *subdev, u32 value)
+{
+ int ret = 0;
+ struct fimc_is_device_csi *csi;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+ BUG_ON(!value);
+
+ csi = v4l2_get_subdevdata(subdev);
+ if (!csi) {
+ err("csi is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ module = (struct fimc_is_module_enum *)value;
+ csi->sensor_cfgs = module->cfgs;
+ csi->sensor_cfg = module->cfg;
+ csi->vcis = module->vcis;
+ csi->vci = module->vci;
+ csi->image.framerate = SENSOR_DEFAULT_FRAMERATE; /* default frame rate */
+ csi->mode = module->mode;
+ csi->lanes = module->lanes;
+
+p_err:
+ return ret;
+}
+
+static int csi_s_power(struct v4l2_subdev *subdev,
+ int on)
+{
+ int ret = 0;
+ struct fimc_is_device_csi *csi;
+
+ BUG_ON(!subdev);
+
+ csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(subdev);
+ if (!csi) {
+ err("csi is NULL");
+ return -EINVAL;
+ }
+
+ /* HACK: CSI #1 phy should be enabled when CSI #2 phy is eanbled. */
+ if (csi->instance == CSI_ID_C) {
+ ret = exynos5_csis_phy_enable(CSI_ID_B, on);
+ }
+
+ ret = exynos5_csis_phy_enable(csi->instance, on);
+ if (ret) {
+ err("fail to csi%d power on", csi->instance);
+ goto p_err;
+ }
+
+p_err:
+ mdbgd_front("%s(%d, %d)\n", csi, __func__, on, ret);
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = csi_init,
+ .s_power = csi_s_power
+};
+
+static int csi_stream_on(struct fimc_is_device_csi *csi)
+{
+ int ret = 0;
+ u32 settle;
+ unsigned long __iomem *base_reg;
+
+ BUG_ON(!csi);
+ BUG_ON(!csi->sensor_cfg);
+
+ base_reg = csi->base_reg;
+
+ settle = get_hsync_settle(
+ csi->sensor_cfg,
+ csi->sensor_cfgs,
+ csi->image.window.width,
+ csi->image.window.height,
+ csi->image.framerate);
+
+ minfo("[CSI:D] settle(%dx%d@%d) = %d, lane idx(%d)\n",
+ csi,
+ csi->image.window.width,
+ csi->image.window.height,
+ csi->image.framerate,
+ settle,
+ csi->lanes);
+
+#if (FIMC_IS_CSI_VERSION == CSI_VERSION_0000_0000)
+ s5pcsis_reset(base_reg);
+ s5pcsis_set_hsync_settle(base_reg, settle);
+ s5pcsis_set_params(base_reg, &csi->image, csi->lanes);
+ /* lane total count = csi->lanes + 1 (CSI_DATA_LANES_1 is 0) */
+ s5pcsis_system_enable(base_reg, true, (csi->lanes + 1));
+ s5pcsis_enable_interrupts(base_reg, &csi->image, true);
+#else
+ csi_hw_reset(base_reg);
+ csi_hw_s_settle(base_reg, settle);
+ csi_hw_s_control(base_reg, csi->image.format.pixelformat, csi->mode, csi->lanes);
+ if (csi->mode == CSI_MODE_CH0_ONLY) {
+ csi_hw_s_config(base_reg,
+ CSI_VIRTUAL_CH_0,
+ CSI_VIRTUAL_CH_0,
+ csi->image.format.pixelformat,
+ csi->image.window.width,
+ csi->image.window.height);
+ } else {
+ u32 index = get_vci_channel(csi->vci, csi->vcis, csi->image.format.pixelformat);
+ csi_hw_s_config(base_reg,
+ CSI_VIRTUAL_CH_0,
+ csi->vci[index].vc_map[CSI_VIRTUAL_CH_0],
+ csi->image.format.pixelformat,
+ csi->image.window.width,
+ csi->image.window.height);
+ csi_hw_s_config(base_reg,
+ CSI_VIRTUAL_CH_1,
+ csi->vci[index].vc_map[CSI_VIRTUAL_CH_1],
+ csi->image.format.pixelformat,
+ csi->image.window.width,
+ csi->image.window.height);
+ csi_hw_s_config(base_reg,
+ CSI_VIRTUAL_CH_2,
+ csi->vci[index].vc_map[CSI_VIRTUAL_CH_2],
+ csi->image.format.pixelformat,
+ csi->image.window.width,
+ csi->image.window.height);
+ }
+
+ csi_hw_s_interrupt(base_reg, true);
+ csi_hw_enable(base_reg);
+#endif
+
+ return ret;
+}
+
+static int csi_stream_off(struct fimc_is_device_csi *csi)
+{
+ int ret = 0;
+ unsigned long __iomem *base_reg;
+
+ BUG_ON(!csi);
+
+ base_reg = csi->base_reg;
+
+#if (FIMC_IS_CSI_VERSION == CSI_VERSION_0000_0000)
+ s5pcsis_enable_interrupts(base_reg, &csi->image, false);
+ /* lane total count = csi->lanes + 1 (CSI_DATA_LANES_1 is 0) */
+ s5pcsis_system_enable(base_reg, false, (csi->lanes + 1));
+#else
+ csi_hw_s_interrupt(base_reg, false);
+ csi_hw_disable(base_reg);
+#endif
+
+ return ret;
+}
+
+static int csi_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ int ret = 0;
+ struct fimc_is_device_csi *csi;
+
+ BUG_ON(!subdev);
+
+ csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(subdev);
+ if (!csi) {
+ err("csi is NULL");
+ return -EINVAL;
+ }
+
+ if (enable) {
+ ret = csi_stream_on(csi);
+ if (ret) {
+ err("csi_stream_on is fail(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ ret = csi_stream_off(csi);
+ if (ret) {
+ err("csi_stream_off is fail(%d)", ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ return 0;
+}
+
+static int csi_s_param(struct v4l2_subdev *subdev, struct v4l2_streamparm *param)
+{
+ int ret = 0;
+ struct fimc_is_device_csi *csi;
+ struct v4l2_captureparm *cp;
+ struct v4l2_fract *tpf;
+
+ BUG_ON(!subdev);
+ BUG_ON(!param);
+
+ cp = ¶m->parm.capture;
+ tpf = &cp->timeperframe;
+
+ csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(subdev);
+ if (!csi) {
+ err("csi is NULL");
+ return -EINVAL;
+ }
+
+ csi->image.framerate = tpf->denominator / tpf->numerator;
+
+ mdbgd_front("%s(%d, %d)\n", csi, __func__, csi->image.framerate, ret);
+ return ret;
+}
+
+static int csi_s_format(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *fmt)
+{
+ int ret = 0;
+ struct fimc_is_device_csi *csi;
+
+ BUG_ON(!subdev);
+ BUG_ON(!fmt);
+
+ csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(subdev);
+ if (!csi) {
+ err("csi is NULL");
+ return -EINVAL;
+ }
+
+ csi->image.window.offs_h = 0;
+ csi->image.window.offs_v = 0;
+ csi->image.window.width = fmt->width;
+ csi->image.window.height = fmt->height;
+ csi->image.window.o_width = fmt->width;
+ csi->image.window.o_height = fmt->height;
+ csi->image.format.pixelformat = fmt->code;
+ csi->image.format.field = fmt->field;
+
+ mdbgd_front("%s(%dx%d, %X)\n", csi, __func__, fmt->width, fmt->height, fmt->code);
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops video_ops = {
+ .s_stream = csi_s_stream,
+ .s_parm = csi_s_param,
+ .s_mbus_fmt = csi_s_format
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops,
+ .video = &video_ops
+};
+
+#ifdef DBG_CSIISR
+static irqreturn_t fimc_is_csi_isr(int irq, void *data)
+{
+ u32 status;
+ struct fimc_is_device_csi *csi;
+
+ csi = data;
+
+ status = csi_hw_g_interrupt(csi->base_reg);
+ info("CSI%d : irq%d(%X)\n",csi->instance, irq, status);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+int fimc_is_csi_probe(void *parent, u32 instance)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_csi;
+ struct fimc_is_device_csi *csi;
+ struct fimc_is_device_sensor *device = parent;
+
+ BUG_ON(!device);
+
+ subdev_csi = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_csi) {
+ merr("subdev_csi is NULL", device);
+ ret = -ENOMEM;
+ goto p_err;
+ }
+ device->subdev_csi = subdev_csi;
+
+ csi = kzalloc(sizeof(struct fimc_is_device_csi), GFP_KERNEL);
+ if (!csi) {
+ merr("csi is NULL", device);
+ ret = -ENOMEM;
+ goto p_err_free1;
+ }
+
+ csi->instance = instance;
+ switch(instance) {
+ case CSI_ID_A:
+ csi->base_reg = (unsigned long *)MIPICSI0_REG_BASE;
+#ifdef DBG_CSIISR
+ ret = request_irq(IRQ_MIPICSI0,
+ fimc_is_csi_isr,
+ IRQF_SHARED,
+ "mipi-csi0",
+ csi);
+ if (ret) {
+ err("request_irq(IRQ_MIPICSI0) is fail(%d)", ret);
+ goto p_err_free2;
+ }
+#endif
+ break;
+ case CSI_ID_B:
+ csi->base_reg = (unsigned long *)MIPICSI1_REG_BASE;
+#ifdef DBG_CSIISR
+ ret = request_irq(IRQ_MIPICSI1,
+ fimc_is_csi_isr,
+ IRQF_SHARED,
+ "mipi-csi1",
+ csi);
+ if (ret) {
+ err("request_irq(IRQ_MIPICSI1) is fail(%d)", ret);
+ goto p_err_free2;
+ }
+#endif
+ break;
+ case CSI_ID_C:
+ csi->base_reg = (unsigned long *)MIPICSI2_REG_BASE;
+ break;
+ default:
+ err("instance is invalid(%d)", instance);
+ ret = -EINVAL;
+ goto p_err_free2;
+ }
+
+ v4l2_subdev_init(subdev_csi, &subdev_ops);
+ v4l2_set_subdevdata(subdev_csi, csi);
+ v4l2_set_subdev_hostdata(subdev_csi, device);
+ snprintf(subdev_csi->name, V4L2_SUBDEV_NAME_SIZE, "csi-subdev.%d", instance);
+ ret = v4l2_device_register_subdev(&device->v4l2_dev, subdev_csi);
+ if (ret) {
+ merr("v4l2_device_register_subdev is fail(%d)", device, ret);
+ goto p_err_free2;
+ }
+
+ info("[%d][FRT:D] %s(%d)\n", instance, __func__, ret);
+ return 0;
+
+p_err_free2:
+ kfree(csi);
+
+p_err_free1:
+ kfree(subdev_csi);
+ device->subdev_csi = NULL;
+
+p_err:
+ err("[%d][FRT:D] %s(%d)\n", instance, __func__, ret);
+ return ret;
+}
--- /dev/null
+#ifndef FIMC_IS_DEVICE_CSI_H
+#define FIMC_IS_DEVICE_CSI_H
+
+#include <media/v4l2-device.h>
+#include "fimc-is-type.h"
+
+struct fimc_is_device_csi {
+ /* channel information */
+ u32 instance;
+ unsigned long __iomem *base_reg;
+
+ /* for settle time */
+ u32 sensor_cfgs;
+ struct fimc_is_sensor_cfg *sensor_cfg;
+
+ /* for vci setting */
+ u32 vcis;
+ struct fimc_is_vci *vci;
+
+ /* image configuration */
+ u32 mode;
+ u32 lanes;
+ struct fimc_is_image image;
+};
+
+int __must_check fimc_is_csi_probe(void *parent, u32 instance);
+int __must_check fimc_is_csi_open(struct v4l2_subdev *subdev);
+int __must_check fimc_is_csi_close(struct v4l2_subdev *subdev);
+
+#endif
--- /dev/null
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+#include "fimc-is-core.h"
+#include "fimc-is-device-sensor.h"
+#include "fimc-is-resourcemgr.h"
+#include "fimc-is-hw.h"
+
+#define DRIVER_NAME "fimc_is_eeprom_i2c"
+#define DRIVER_NAME_REAR "rear-eeprom-i2c"
+#define DRIVER_NAME_FRONT "front-eeprom-i2c"
+#define REAR_DATA 0
+#define FRONT_DATA 1
+
+
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+int sensor_eeprom_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fimc_is_core *core;
+ static bool probe_retried = false;
+
+ if (!fimc_is_dev)
+ goto probe_defer;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core)
+ goto probe_defer;
+
+ if (id->driver_data == REAR_DATA) {
+ core->eeprom_client0 = client;
+ } else if (id->driver_data == FRONT_DATA) {
+ core->eeprom_client1 = client;
+ } else {
+ err("rear eeprom device is failed!");
+ }
+
+ pr_info("%s %s[%ld]: fimc_is_sensor_eeprom probed!\n",
+ dev_driver_string(&client->dev), dev_name(&client->dev), id->driver_data);
+
+ return 0;
+
+probe_defer:
+ if (probe_retried) {
+ err("probe has already been retried!!");
+ }
+
+ probe_retried = true;
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+
+}
+
+static int sensor_eeprom_remove(struct i2c_client *client)
+{
+ int ret = 0;
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_fimc_is_sensor_eeprom_match[] = {
+ {
+ .compatible = "samsung,rear-eeprom-i2c", .data = (void *)REAR_DATA
+ },
+ {
+ .compatible = "samsung,front-eeprom-i2c", .data = (void *)FRONT_DATA
+ },
+ {},
+};
+#endif
+
+static const struct i2c_device_id sensor_eeprom_idt[] = {
+ { DRIVER_NAME_REAR, REAR_DATA },
+ { DRIVER_NAME_FRONT, FRONT_DATA },
+};
+
+static struct i2c_driver sensor_eeprom_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = exynos_fimc_is_sensor_eeprom_match
+#endif
+ },
+ .probe = sensor_eeprom_probe,
+ .remove = sensor_eeprom_remove,
+ .id_table = sensor_eeprom_idt
+};
+
+static int __init sensor_eeprom_load(void)
+{
+ return i2c_add_driver(&sensor_eeprom_driver);
+}
+
+static void __exit sensor_eeprom_unload(void)
+{
+ i2c_del_driver(&sensor_eeprom_driver);
+}
+
+module_init(sensor_eeprom_load);
+module_exit(sensor_eeprom_unload);
+
+MODULE_AUTHOR("Kyoungho Yun");
+MODULE_DESCRIPTION("Camera eeprom driver");
+MODULE_LICENSE("GPL v2");
+
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/irqs.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-hw.h"
+#include "fimc-is-interface.h"
+#include "fimc-is-device-flite.h"
+
+#define FLITE_MAX_RESET_READY_TIME (20) /* 100ms */
+#define FLITE_MAX_WIDTH_SIZE (8192)
+#define FLITE_MAX_HEIGHT_SIZE (8192)
+/* #define COLORBAR_MODE */
+
+/*FIMCLite*/
+/* Camera Source size */
+#define FLITE_REG_CISRCSIZE (0x00)
+#define FLITE_REG_CISRCSIZE_SIZE_H(x) ((x) << 16)
+#define FLITE_REG_CISRCSIZE_SIZE_V(x) ((x) << 0)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR (0 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB (1 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY (2 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY (3 << 14)
+
+/* Global control */
+#define FLITE_REG_CIGCTRL 0x04
+#define FLITE_REG_CIGCTRL_YUV422_1P (0x1E << 24)
+#define FLITE_REG_CIGCTRL_RAW8 (0x2A << 24)
+#define FLITE_REG_CIGCTRL_RAW10 (0x2B << 24)
+#define FLITE_REG_CIGCTRL_RAW12 (0x2C << 24)
+#define FLITE_REG_CIGCTRL_RAW14 (0x2D << 24)
+
+/* User defined formats. x = 0...0xF. */
+#define FLITE_REG_CIGCTRL_USER(x) (0x30 + x - 1)
+#define FLITE_REG_CIGCTRL_OLOCAL_DISABLE (1 << 22)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18)
+#define FLITE_REG_CIGCTRL_SWRST (1 << 17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE (0 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_DISABLE (1 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_ENABLE (0 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE (1 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_ENABLE (0 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE (1 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE (0 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE (1 << 5)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
+
+/* Image Capture Enable */
+#define FLITE_REG_CIIMGCPT (0x08)
+#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25)
+#define FLITE_REG_CIIMGCPT_CPT_FRPTR(x) ((x) << 19)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_FRCNT(x) ((x) << 10)
+
+/* Capture Sequence */
+#define FLITE_REG_CICPTSEQ (0x0C)
+#define FLITE_REG_CPT_FRSEQ(x) ((x) << 0)
+
+/* Camera Window Offset */
+#define FLITE_REG_CIWDOFST (0x10)
+#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31)
+#define FLITE_REG_CIWDOFST_WINHOROFST(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST_HOROFF_MASK (0x1fff << 16)
+#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15)
+#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FLITE_REG_CIWDOFST_WINVEROFST(x) ((x) << 0)
+#define FLITE_REG_CIWDOFST_VEROFF_MASK (0x1fff << 0)
+
+/* Cmaera Window Offset2 */
+#define FLITE_REG_CIWDOFST2 (0x14)
+#define FLITE_REG_CIWDOFST2_WINHOROFST2(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST2_WINVEROFST2(x) ((x) << 0)
+
+/* Camera Output DMA Format */
+#define FLITE_REG_CIODMAFMT (0x18)
+#define FLITE_REG_CIODMAFMT_1D_DMA (1 << 15)
+#define FLITE_REG_CIODMAFMT_2D_DMA (0 << 15)
+#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14)
+#define FLITE_REG_CIODMAFMT_NORMAL (0 << 14)
+#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4)
+
+/* Camera Output Canvas */
+#define FLITE_REG_CIOCAN (0x20)
+#define FLITE_REG_CIOCAN_OCAN_V(x) ((x) << 16)
+#define FLITE_REG_CIOCAN_OCAN_H(x) ((x) << 0)
+
+/* Camera Output DMA Offset */
+#define FLITE_REG_CIOOFF (0x24)
+#define FLITE_REG_CIOOFF_OOFF_V(x) ((x) << 16)
+#define FLITE_REG_CIOOFF_OOFF_H(x) ((x) << 0)
+
+/* Camera Output DMA Address */
+#define FLITE_REG_CIOSA (0x30)
+#define FLITE_REG_CIOSA_OSA(x) ((x) << 0)
+
+/* Camera Status */
+#define FLITE_REG_CISTATUS (0x40)
+#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14)
+#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13)
+#define FLITE_REG_CISTATUS_OVFIY (1 << 10)
+#define FLITE_REG_CISTATUS_OVFICB (1 << 9)
+#define FLITE_REG_CISTATUS_OVFICR (1 << 8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4)
+#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0)
+#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4)
+
+/* Camera Status2 */
+#define FLITE_REG_CISTATUS2 (0x44)
+#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1)
+#define FLITE_REG_CISTATUS2_FRMEND (1 << 0)
+
+/* Camera Status3 */
+#define FLITE_REG_CISTATUS3 0x48
+#define FLITE_REG_CISTATUS3_PRESENT_MASK (0x3F)
+
+/* Qos Threshold */
+#define FLITE_REG_CITHOLD (0xF0)
+#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30)
+#define FLITE_REG_CITHOLD_WTH_QOS(x) ((x) << 0)
+
+/* Camera General Purpose */
+#define FLITE_REG_CIGENERAL (0xFC)
+#define FLITE_REG_CIGENERAL_CAM_A (0)
+#define FLITE_REG_CIGENERAL_CAM_B (1)
+#define FLITE_REG_CIGENERAL_CAM_C (2)
+#define FLITE_REG_CIGENERAL_CAM_D (3)
+#define FLITE_REG_CIGENERAL_3AA1_CAM_A (0 << 14)
+#define FLITE_REG_CIGENERAL_3AA1_CAM_B (1 << 14)
+#define FLITE_REG_CIGENERAL_3AA1_CAM_C (2 << 14)
+#define FLITE_REG_CIGENERAL_3AA1_CAM_D (3 << 14)
+
+#define FLITE_REG_CIFCNTSEQ 0x100
+
+/* BNS */
+#define FLITE_REG_BINNINGON (0x120)
+#define FLITE_REG_BINNINGON_CLKGATE_ON(x) (~(x) << 1)
+#define FLITE_REG_BINNINGON_EN(x) ((x) << 0)
+
+#define FLITE_REG_BINNINGCTRL (0x124)
+#define FLITE_REG_BINNINGCTRL_FACTOR_Y(x) ((x) << 22)
+#define FLITE_REG_BINNINGCTRL_FACTOR_X(x) ((x) << 17)
+#define FLITE_REG_BINNINGCTRL_SHIFT_UP_Y(x) ((x) << 15)
+#define FLITE_REG_BINNINGCTRL_SHIFT_UP_X(x) ((x) << 13)
+#define FLITE_REG_BINNINGCTRL_PRECISION_BITS(x) ((x) << 10)
+#define FLITE_REG_BINNINGCTRL_BITTAGE(x) ((x) << 5)
+#define FLITE_REG_BINNINGCTRL_UNITY_SIZE(x) ((x) << 0)
+
+#define FLITE_REG_PEDESTAL (0x128)
+#define FLITE_REG_PEDESTAL_OUT(x) ((x) << 12)
+#define FLITE_REG_PEDESTAL_IN(x) ((x) << 0)
+
+#define FLITE_REG_BINNINGTOTAL (0x12C)
+#define FLITE_REG_BINNINGTOTAL_HEIGHT(x) ((x) << 16)
+#define FLITE_REG_BINNINGTOTAL_WIDTH(x) ((x) << 0)
+
+#define FLITE_REG_BINNINGINPUT (0x130)
+#define FLITE_REG_BINNINGINPUT_HEIGHT(x) ((x) << 16)
+#define FLITE_REG_BINNINGINPUT_WIDTH(x) ((x) << 0)
+
+#define FLITE_REG_BINNINGMARGIN (0x134)
+#define FLITE_REG_BINNINGMARGIN_TOP(x) ((x) << 16)
+#define FLITE_REG_BINNINGMARGIN_LEFT(x) ((x) << 0)
+
+#define FLITE_REG_BINNINGOUTPUT (0x138)
+#define FLITE_REG_BINNINGOUTPUT_HEIGHT(x) ((x) << 16)
+#define FLITE_REG_BINNINGOUTPUT_WIDTH(x) ((x) << 0)
+
+#define FLITE_REG_WEIGHTX01 (0x13C)
+#define FLITE_REG_WEIGHTX01_1(x) ((x) << 16)
+#define FLITE_REG_WEIGHTX01_0(x) ((x) << 0)
+
+#define FLITE_REG_WEIGHTX23 (0x140)
+#define FLITE_REG_WEIGHTX23_1(x) ((x) << 16)
+#define FLITE_REG_WEIGHTX23_0(x) ((x) << 0)
+
+#define FLITE_REG_WEIGHTY01 (0x15C)
+#define FLITE_REG_WEIGHTY01_1(x) ((x) << 16)
+#define FLITE_REG_WEIGHTY01_0(x) ((x) << 0)
+
+#define FLITE_REG_WEIGHTY23 (0x160)
+#define FLITE_REG_WEIGHTY23_1(x) ((x) << 16)
+#define FLITE_REG_WEIGHTY23_0(x) ((x) << 0)
+
+static void flite_hw_enable_bns(unsigned long __iomem *base_reg, bool enable)
+{
+ u32 cfg = 0;
+
+ /* enable */
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGON));
+ cfg |= FLITE_REG_BINNINGON_CLKGATE_ON(enable);
+ cfg |= FLITE_REG_BINNINGON_EN(enable);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGON));
+}
+
+static void flite_hw_s_coeff_bns(unsigned long __iomem *base_reg,
+ u32 factor_x, u32 factor_y)
+{
+ u32 cfg = 0;
+ u32 factor = 0;
+
+ factor = factor_x * factor_y;
+ if (factor_x != factor_y)
+ err("x y factor is not the same (%d, %d)", factor_x, factor_y);
+
+ /* control */
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGCTRL));
+ cfg |= FLITE_REG_BINNINGCTRL_FACTOR_Y(factor_y);
+ cfg |= FLITE_REG_BINNINGCTRL_FACTOR_X(factor_x);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGCTRL));
+
+ switch (factor) {
+ case 9:
+ /* coefficient */
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTX01));
+ cfg |= FLITE_REG_WEIGHTX01_1(0x20);
+ cfg |= FLITE_REG_WEIGHTX01_0(0xE0);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTX01));
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTX23));
+ cfg |= FLITE_REG_WEIGHTX23_1(0xA0);
+ cfg |= FLITE_REG_WEIGHTX23_0(0x60);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTX23));
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTY01));
+ cfg |= FLITE_REG_WEIGHTY01_1(0x20);
+ cfg |= FLITE_REG_WEIGHTY01_0(0xE0);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTY01));
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTY23));
+ cfg |= FLITE_REG_WEIGHTY23_1(0xA0);
+ cfg |= FLITE_REG_WEIGHTY23_0(0x60);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTY23));
+ break;
+ case 16:
+ /* coefficient */
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTX01));
+ cfg |= FLITE_REG_WEIGHTX01_1(0x40);
+ cfg |= FLITE_REG_WEIGHTX01_0(0xC0);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTX01));
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTY01));
+ cfg |= FLITE_REG_WEIGHTY01_1(0x40);
+ cfg |= FLITE_REG_WEIGHTY01_0(0xC0);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_WEIGHTY01));
+ break;
+ default:
+ err("unknown factor!! (%d, %d)", factor_x, factor_y);
+ break;
+ }
+}
+
+static void flite_hw_s_size_bns(unsigned long __iomem *base_reg,
+ u32 width, u32 height, u32 otf_width, u32 otf_height)
+{
+ u32 cfg = 0;
+
+ /* size */
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGTOTAL));
+ cfg |= FLITE_REG_BINNINGTOTAL_HEIGHT(height);
+ cfg |= FLITE_REG_BINNINGTOTAL_WIDTH(width);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGTOTAL));
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGINPUT));
+ cfg |= FLITE_REG_BINNINGINPUT_HEIGHT(height);
+ cfg |= FLITE_REG_BINNINGINPUT_WIDTH(width);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGINPUT));
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGMARGIN));
+ cfg |= FLITE_REG_BINNINGMARGIN_TOP(0);
+ cfg |= FLITE_REG_BINNINGMARGIN_LEFT(0);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGMARGIN));
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGOUTPUT));
+ cfg |= FLITE_REG_BINNINGOUTPUT_HEIGHT(otf_height);
+ cfg |= FLITE_REG_BINNINGOUTPUT_WIDTH(otf_width);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_BINNINGOUTPUT));
+}
+
+static int flite_hw_set_bns(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image)
+{
+ int ret = 0;
+ u32 width, height;
+ u32 otf_width, otf_height;
+ u32 factor_x, factor_y;
+
+ BUG_ON(!image);
+
+ width = image->window.width;
+ height = image->window.height;
+ otf_width = image->window.otf_width;
+ otf_height = image->window.otf_height;
+
+ if (otf_width == width && otf_height == height) {
+ info("input & output sizes are same(%d, %d)\n", otf_width, otf_height);
+ goto exit;
+ }
+
+ if (otf_width == 0 || otf_height == 0) {
+ warn("bns size is zero. s_ctrl(V4L2_CID_IS_S_BNS) first\n");
+ goto exit;
+ }
+
+ factor_x = 2 * width / otf_width;
+ factor_y = 2 * height / otf_height;
+
+ flite_hw_s_size_bns(base_reg, width, height, otf_width, otf_height);
+
+ flite_hw_s_coeff_bns(base_reg, factor_x, factor_y);
+
+ flite_hw_enable_bns(base_reg, true);
+
+ info("BNS in(%d, %d), BNS out(%d, %d), ratio(%d, %d)\n",
+ width, height, otf_width, otf_height, factor_x, factor_y);
+exit:
+ return ret;
+}
+
+static void flite_hw_set_cam_source_size(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image)
+{
+ u32 cfg = 0;
+
+ BUG_ON(!image);
+
+#ifdef COLORBAR_MODE
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_H(640);
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_V(480);
+#else
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_H(image->window.o_width);
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_V(image->window.o_height);
+#endif
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CISRCSIZE));
+}
+
+static void flite_hw_set_dma_offset(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image)
+{
+ u32 cfg = 0;
+
+ BUG_ON(!image);
+
+ /* HACK */
+ if (image->format.pixelformat == V4L2_PIX_FMT_SBGGR10 || image->format.pixelformat == V4L2_PIX_FMT_SBGGR12)
+ cfg |= FLITE_REG_CIOCAN_OCAN_H(roundup(image->window.o_width, 10));
+ else
+ cfg |= FLITE_REG_CIOCAN_OCAN_H(image->window.o_width);
+
+ cfg |= FLITE_REG_CIOCAN_OCAN_V(image->window.o_height);
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIOCAN));
+}
+
+static void flite_hw_set_cam_channel(unsigned long __iomem *base_reg,
+ u32 otf_setting)
+{
+ u32 cfg = 0;
+
+ cfg |= otf_setting;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGENERAL));
+}
+
+static void flite_hw_set_capture_start(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIIMGCPT));
+ cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIIMGCPT));
+}
+
+static void flite_hw_set_capture_stop(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIIMGCPT));
+ cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIIMGCPT));
+}
+
+static int flite_hw_set_source_format(unsigned long __iomem *base_reg, struct fimc_is_image *image)
+{
+ int ret = 0;
+ u32 pixelformat, format, cfg;
+
+ BUG_ON(!image);
+
+ pixelformat = image->format.pixelformat;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ format = HW_FORMAT_RAW8;
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ format = HW_FORMAT_RAW10;
+ break;
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ format = HW_FORMAT_RAW10;
+ /*
+ * HACK : hal send RAW10 for RAW12
+ * formt = HW_FORMAT_RAW12 << 24;
+ */
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ format = HW_FORMAT_YUV422_8BIT;
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ format = HW_FORMAT_USER;
+ break;
+ default:
+ err("unsupported format(%X)", pixelformat);
+ format = HW_FORMAT_RAW10;
+ ret = -EINVAL;
+ break;
+ }
+
+#ifdef COLORBAR_MODE
+ cfg |= (HW_FORMAT_YUV422_8BIT << 24);
+#else
+ cfg |= (format << 24);
+#endif
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ return ret;
+}
+
+static void flite_hw_set_dma_fmt(unsigned long __iomem *base_reg,
+ u32 pixelformat)
+{
+ u32 cfg = 0;
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIODMAFMT));
+
+ if (pixelformat == V4L2_PIX_FMT_SBGGR10 || pixelformat == V4L2_PIX_FMT_SBGGR12)
+ cfg |= FLITE_REG_CIODMAFMT_PACK12;
+ else
+ cfg |= FLITE_REG_CIODMAFMT_NORMAL;
+
+ if (pixelformat == V4L2_PIX_FMT_SGRBG8)
+ cfg |= FLITE_REG_CIODMAFMT_1D_DMA;
+ else
+ cfg |= FLITE_REG_CIODMAFMT_2D_DMA;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIODMAFMT));
+}
+
+static void flite_hw_set_output_dma(unsigned long __iomem *base_reg, bool enable,
+ u32 pixelformat)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ if (enable) {
+ cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
+ flite_hw_set_dma_fmt(base_reg, pixelformat);
+ } else {
+ cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
+ }
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+static void flite_hw_set_output_local(unsigned long __iomem *base_reg, bool enable)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ if (enable)
+ cfg &= ~FLITE_REG_CIGCTRL_OLOCAL_DISABLE;
+ else
+ cfg |= FLITE_REG_CIGCTRL_OLOCAL_DISABLE;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+#ifdef COLORBAR_MODE
+static void flite_hw_set_test_pattern_enable(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+
+ /* will use for pattern generation testing */
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+ cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+#endif
+
+static void flite_hw_set_interrupt_source(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ /* for checking stop complete */
+ cfg &= ~FLITE_REG_CIGCTRL_IRQ_LASTEN0_DISABLE;
+
+ /* for checking frame start */
+ cfg &= ~FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
+
+ /* for checking frame end */
+ cfg &= ~FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE;
+
+ /* for checking overflow */
+ cfg &= ~FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+static void flite_hw_clr_interrupt_source(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ /* for checking stop complete */
+ cfg |= FLITE_REG_CIGCTRL_IRQ_LASTEN0_DISABLE;
+
+ /* for checking frame start */
+ cfg |= FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
+
+ /* for checking frame end */
+ cfg |= FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE;
+
+ /* for checking overflow */
+ cfg |= FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+static void flite_hw_set_ovf_interrupt_source(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ /* for checking overflow */
+ cfg &= ~FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+static void flite_hw_clr_ovf_interrupt_source(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ /* for checking overflow */
+ cfg |= FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+static int flite_hw_check_ovf_interrupt_source(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ /* for checking overflow */
+ if (cfg & FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE)
+ return true;
+
+ return false;
+}
+
+static void flite_hw_force_reset(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0, retry = 100;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ /* request sw reset */
+ cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ /* checking reset ready */
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+ while (retry-- && !(cfg & FLITE_REG_CIGCTRL_SWRST_RDY))
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ if (!(cfg & FLITE_REG_CIGCTRL_SWRST_RDY))
+ warn("[CamIF] sw reset is not read but forcelly");
+
+ /* sw reset */
+ cfg |= FLITE_REG_CIGCTRL_SWRST;
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+ warn("[CamIF] sw reset");
+}
+
+static void flite_hw_set_inverse_polarity(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+ cfg &= ~(FLITE_REG_CIGCTRL_INVPOLPCLK | FLITE_REG_CIGCTRL_INVPOLVSYNC
+ | FLITE_REG_CIGCTRL_INVPOLHREF);
+
+ /* cfg |= (FLITE_REG_CIGCTRL_INVPOLPCLK | FLITE_REG_CIGCTRL_INVPOLVSYNC); */
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+static void flite_hw_set_camera_type(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+
+ cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGCTRL));
+}
+
+static void flite_hw_set_window_offset(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image)
+{
+ u32 cfg = 0;
+ u32 hoff2, voff2;
+
+ BUG_ON(!image);
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIWDOFST));
+ cfg &= ~(FLITE_REG_CIWDOFST_HOROFF_MASK |
+ FLITE_REG_CIWDOFST_VEROFF_MASK);
+ cfg |= FLITE_REG_CIWDOFST_WINOFSEN |
+ FLITE_REG_CIWDOFST_WINHOROFST(image->window.offs_h) |
+ FLITE_REG_CIWDOFST_WINVEROFST(image->window.offs_v);
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIWDOFST));
+
+ hoff2 = image->window.o_width - image->window.width - image->window.offs_h;
+ voff2 = image->window.o_height - image->window.height - image->window.offs_v;
+ cfg = FLITE_REG_CIWDOFST2_WINHOROFST2(hoff2) |
+ FLITE_REG_CIWDOFST2_WINVEROFST2(voff2);
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIWDOFST2));
+}
+
+static void flite_hw_set_last_capture_end_clear(unsigned long __iomem *base_reg)
+{
+ u32 cfg = 0;
+
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS2));
+ cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
+
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS2));
+}
+
+int flite_hw_get_present_frame_buffer(unsigned long __iomem *base_reg)
+{
+ u32 status = 0;
+
+ status = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS3));
+ status &= FLITE_REG_CISTATUS3_PRESENT_MASK;
+
+ return status;
+}
+
+int flite_hw_get_status2(unsigned long __iomem *base_reg)
+{
+ u32 status = 0;
+
+ status = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS2));
+
+ return status;
+}
+
+void flite_hw_set_status1(unsigned long __iomem *base_reg, u32 val)
+{
+ writel(val, base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS));
+}
+
+int flite_hw_get_status1(unsigned long __iomem *base_reg)
+{
+ u32 status = 0;
+
+ status = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS));
+
+ return status;
+}
+
+int flite_hw_getnclr_status1(unsigned long __iomem *base_reg)
+{
+ u32 status = 0;
+
+ status = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS));
+ writel(0, base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS));
+
+ return status;
+}
+
+void flite_hw_set_status2(unsigned long __iomem *base_reg, u32 val)
+{
+ writel(val, base_reg + TO_WORD_OFFSET(FLITE_REG_CISTATUS2));
+}
+
+void flite_hw_set_start_addr(unsigned long __iomem *base_reg, u32 number, u32 addr)
+{
+ unsigned long __iomem *target_reg;
+
+ if (number == 0) {
+ target_reg = base_reg + TO_WORD_OFFSET(0x30);
+ } else {
+ number--;
+ target_reg = base_reg + TO_WORD_OFFSET(0x200 + (0x4*number));
+ }
+
+ writel(addr, target_reg);
+}
+
+void flite_hw_set_use_buffer(unsigned long __iomem *base_reg, u32 number)
+{
+ u32 buffer;
+ buffer = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIFCNTSEQ));
+ buffer |= 1<<number;
+ writel(buffer, base_reg + TO_WORD_OFFSET(FLITE_REG_CIFCNTSEQ));
+}
+
+void flite_hw_set_unuse_buffer(unsigned long __iomem *base_reg, u32 number)
+{
+ u32 buffer;
+ buffer = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIFCNTSEQ));
+ buffer &= ~(1<<number);
+ writel(buffer, base_reg + TO_WORD_OFFSET(FLITE_REG_CIFCNTSEQ));
+}
+
+u32 flite_hw_get_buffer_seq(unsigned long __iomem *base_reg)
+{
+ return readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIFCNTSEQ));
+}
+
+void flite_hw_set_mux(unsigned long __iomem *base_reg, u32 csi_ch, u32 flite_ch)
+{
+ u32 cfg;
+ if ((csi_ch == 0) && (flite_ch == 1)) {
+ info("[CSI:D] mux setting : CSI0 <-> FLITE1\n");
+ cfg = readl(base_reg + TO_WORD_OFFSET(FLITE_REG_CIGENERAL));
+ cfg |= (1 << 12);
+ writel(cfg, base_reg + TO_WORD_OFFSET(FLITE_REG_CIGENERAL));
+ }
+}
+
+int init_fimc_lite(unsigned long __iomem *base_reg)
+{
+ int i;
+
+ writel(0, base_reg + TO_WORD_OFFSET(FLITE_REG_CIFCNTSEQ));
+
+ for (i = 0; i < 32; i++)
+ flite_hw_set_start_addr(base_reg , i, 0xffffffff);
+
+ return 0;
+}
+
+static int start_fimc_lite(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image,
+ u32 otf_setting,
+ u32 bns,
+ u32 csi_ch,
+ u32 flite_ch)
+{
+ flite_hw_set_cam_channel(base_reg, otf_setting);
+ flite_hw_set_cam_source_size(base_reg, image);
+ flite_hw_set_dma_offset(base_reg, image);
+ flite_hw_set_camera_type(base_reg);
+ flite_hw_set_source_format(base_reg, image);
+ flite_hw_set_inverse_polarity(base_reg);
+ flite_hw_set_interrupt_source(base_reg);
+ flite_hw_set_window_offset(base_reg, image);
+ flite_hw_set_mux(base_reg, csi_ch, flite_ch);
+
+#ifdef COLORBAR_MODE
+ flite_hw_set_test_pattern_enable(base_reg);
+#endif
+
+ if (bns)
+ flite_hw_set_bns(base_reg, image);
+
+ flite_hw_set_last_capture_end_clear(base_reg);
+ flite_hw_set_capture_start(base_reg);
+
+ return 0;
+}
+
+static inline void stop_fimc_lite(unsigned long __iomem *base_reg)
+{
+ flite_hw_set_capture_stop(base_reg);
+}
+
+static inline void flite_s_buffer_addr(struct fimc_is_device_flite *device,
+ u32 bindex, u32 baddr)
+{
+ flite_hw_set_start_addr(device->base_reg, bindex, baddr);
+}
+
+static inline int flite_s_use_buffer(struct fimc_is_device_flite *flite,
+ u32 bindex)
+{
+ int ret = 0;
+ unsigned long target_time;
+
+ BUG_ON(!flite);
+
+ if (!atomic_read(&flite->bcount)) {
+ if (flite->buf_done_mode == FLITE_BUF_DONE_EARLY) {
+ target_time = jiffies +
+ msecs_to_jiffies(flite->buf_done_wait_time);
+ while ((target_time > jiffies) &&
+ (flite_hw_get_status1(flite->base_reg) && (7 << 20)))
+ pr_debug("over vblank (early buffer done)");
+ }
+
+ if (flite_hw_get_status1(flite->base_reg) && (7 << 20)) {
+ merr("over vblank (buf-mode : %d)", flite, flite->buf_done_mode);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ flite_hw_set_use_buffer(flite->base_reg, bindex);
+ atomic_inc(&flite->bcount);
+ flite_hw_set_output_dma(flite->base_reg, true, flite->image.format.pixelformat);
+ } else {
+ flite_hw_set_use_buffer(flite->base_reg, bindex);
+ atomic_inc(&flite->bcount);
+ }
+
+p_err:
+ return ret;
+}
+
+static inline int flite_s_unuse_buffer(struct fimc_is_device_flite *flite,
+ u32 bindex)
+{
+ int ret = 0;
+ unsigned long target_time;
+
+ BUG_ON(!flite);
+
+ if (atomic_read(&flite->bcount) == 1) {
+ if (flite->buf_done_mode == FLITE_BUF_DONE_EARLY) {
+ target_time = jiffies +
+ msecs_to_jiffies(flite->buf_done_wait_time);
+ while ((target_time > jiffies) &&
+ (flite_hw_get_status1(flite->base_reg) && (7 << 20)))
+ pr_debug("over vblank (early buffer done)");
+ }
+
+ if (flite_hw_get_status1(flite->base_reg) && (7 << 20)) {
+ merr("over vblank (buf-mode : %d)", flite, flite->buf_done_mode);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ flite_hw_set_output_dma(flite->base_reg, false, flite->image.format.pixelformat);
+ flite_hw_set_unuse_buffer(flite->base_reg, bindex);
+ atomic_dec(&flite->bcount);
+ } else {
+ flite_hw_set_unuse_buffer(flite->base_reg, bindex);
+ atomic_dec(&flite->bcount);
+ }
+
+p_err:
+ return ret;
+}
+
+static inline void flite_set_ovf_stop(struct fimc_is_device_flite *flite)
+{
+ struct fimc_is_device_sensor *device;
+
+ device = container_of(flite->subdev, struct fimc_is_device_sensor, subdev_flite);
+
+ if (test_bit(FIMC_IS_SENSOR_FRONT_DTP_STOP, &device->state))
+ return;
+
+ /* set dtp */
+ set_bit(FIMC_IS_FLITE_OVERFLOW_STOP, &device->force_stop);
+
+ return;
+}
+
+static u32 g_print_cnt;
+#define LOG_INTERVAL_OF_DROPS 30
+static void tasklet_flite_str0(unsigned long data)
+{
+ struct v4l2_subdev *subdev;
+ struct fimc_is_device_flite *flite;
+ struct fimc_is_device_sensor *device;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group_3aa, *group_isp;
+ u32 bstart, fcount, present;
+
+ subdev = (struct v4l2_subdev *)data;
+ flite = v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ BUG();
+ }
+
+ device = v4l2_get_subdev_hostdata(subdev);
+ if (!device) {
+ err("device is NULL");
+ BUG();
+ }
+
+ present = flite_hw_get_present_frame_buffer(flite->base_reg) - 1;
+ bstart = flite->tasklet_param_str;
+ fcount = atomic_read(&flite->fcount);
+ ischain = device->ischain;
+
+#ifdef TASKLET_MSG
+ info("S%d %d\n", bstart, fcount);
+#endif
+
+ /* comparing sw state and hw state */
+ if (atomic_read(&flite->bcount) == 2) {
+ if ((bstart == FLITE_A_SLOT_VALID) &&
+ (present != FLITE_A_SLOT_VALID)) {
+ mwarn("wrong SW buffer slot A(sw:%d != hw:%d)", flite, bstart, present);
+ flite->sw_trigger = bstart = FLITE_B_SLOT_VALID;
+ }
+
+ if ((bstart == FLITE_B_SLOT_VALID) &&
+ (present != FLITE_B_SLOT_VALID)) {
+ mwarn("wrong SW buffer slot B(sw:%d != hw:%d)", flite, bstart, present);
+ flite->sw_trigger = bstart = FLITE_A_SLOT_VALID;
+ }
+ }
+
+ groupmgr = ischain->groupmgr;
+ group_3aa = &ischain->group_3aa;
+ group_isp = &ischain->group_isp;
+ if (unlikely(list_empty(&group_3aa->smp_trigger.wait_list))) {
+ atomic_set(&group_3aa->sensor_fcount, fcount + group_3aa->async_shots);
+
+ /*
+ * pcount : program count
+ * current program count(location) in kthread
+ */
+ if (((g_print_cnt % LOG_INTERVAL_OF_DROPS) == 0) ||
+ (g_print_cnt < LOG_INTERVAL_OF_DROPS)) {
+ info("grp1(res %d, rcnt %d, scnt %d), "
+ "grp2(res %d, rcnt %d, scnt %d), "
+ "fcount %d(%d, %d) pcount %d\n",
+ groupmgr->group_smp_res[group_3aa->id].count,
+ atomic_read(&group_3aa->rcount),
+ atomic_read(&group_3aa->scount),
+ groupmgr->group_smp_res[group_isp->id].count,
+ atomic_read(&group_isp->rcount),
+ atomic_read(&group_isp->scount),
+ fcount + group_3aa->async_shots,
+ *last_fcount0, *last_fcount1, group_3aa->pcount);
+ }
+ g_print_cnt++;
+ } else {
+ g_print_cnt = 0;
+ atomic_set(&group_3aa->sensor_fcount, fcount + group_3aa->async_shots);
+ up(&group_3aa->smp_trigger);
+ }
+
+ v4l2_subdev_notify(subdev, FLITE_NOTIFY_FSTART, &fcount);
+}
+
+static void tasklet_flite_str1(unsigned long data)
+{
+ struct v4l2_subdev *subdev;
+ struct fimc_is_device_flite *flite;
+ u32 bstart, fcount, present;
+
+ subdev = (struct v4l2_subdev *)data;
+ flite = v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ BUG();
+ }
+
+ present = flite_hw_get_present_frame_buffer(flite->base_reg) - 1;
+ bstart = flite->tasklet_param_str;
+ fcount = atomic_read(&flite->fcount);
+
+#ifdef TASKLET_MSG
+ info("S%d %d\n", bstart, fcount);
+#endif
+
+ /* comparing sw state and hw state */
+ if (atomic_read(&flite->bcount) == 2) {
+ if ((bstart == FLITE_A_SLOT_VALID) &&
+ (present != FLITE_A_SLOT_VALID)) {
+ mwarn("wrong SW buffer slot A(sw:%d != hw:%d)", flite, bstart, present);
+ flite->sw_trigger = bstart = FLITE_B_SLOT_VALID;
+ }
+
+ if ((bstart == FLITE_B_SLOT_VALID) &&
+ (present != FLITE_B_SLOT_VALID)) {
+ mwarn("wrong SW buffer slot B(sw:%d != hw:%d)", flite, bstart, present);
+ flite->sw_trigger = bstart = FLITE_A_SLOT_VALID;
+ }
+ }
+
+ if (flite->buf_done_mode == FLITE_BUF_DONE_EARLY) {
+ flite->early_work_called = false;
+ if (flite->early_work_skip == true) {
+ info("flite early work skip");
+ flite->early_work_skip = false;
+ } else {
+ queue_delayed_work(flite->early_workqueue, &flite->early_work_wq,
+ msecs_to_jiffies(flite->buf_done_wait_time));
+ }
+ }
+
+ v4l2_subdev_notify(subdev, FLITE_NOTIFY_FSTART, &fcount);
+}
+
+static void tasklet_flite_end(unsigned long data)
+{
+ struct fimc_is_device_flite *flite;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ struct fimc_is_frame *frame_done;
+ struct v4l2_subdev *subdev;
+ u32 bdone;
+
+ frame_done = NULL;
+ subdev = (struct v4l2_subdev *)data;
+ flite = v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ BUG();
+ }
+
+ if ((flite->buf_done_mode == FLITE_BUF_DONE_EARLY) &&
+ test_bit(FLITE_LAST_CAPTURE, &flite->state)) {
+ info("Skip due to Last Frame Capture\n");
+ return;
+ }
+
+#ifdef ENABLE_FLITE_OVERFLOW_STOP
+ if (unlikely(flite->overflow_cnt)) {
+ flite_set_ovf_stop(flite);
+ goto ovf_exit;
+ }
+#endif
+
+ framemgr = flite->framemgr;
+ bdone = flite->tasklet_param_end;
+
+#ifdef TASKLET_MSG
+ info("E%d %d\n", bdone, atomic_read(&flite->fcount));
+#endif
+
+ if (flite_hw_check_ovf_interrupt_source(flite->base_reg))
+ flite_hw_set_ovf_interrupt_source(flite->base_reg);
+
+ framemgr_e_barrier(framemgr, FMGR_IDX_1 + bdone);
+
+ if (test_bit(bdone, &flite->state)) {
+ fimc_is_frame_process_head(framemgr, &frame);
+ if (frame) {
+#ifdef MEASURE_TIME
+#ifdef EXTERNAL_TIME
+ do_gettimeofday(&frame->tzone[TM_FLITE_END]);
+#endif
+#endif
+ /* 1. current frame transition to completion */
+ frame_done = frame;
+
+ /* 2. next frame ready */
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ flite_s_buffer_addr(flite, bdone,
+ frame->dvaddr_buffer[0]);
+ set_bit(bdone, &flite->state);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ } else {
+ if (!flite_s_unuse_buffer(flite, bdone)) {
+ clear_bit(bdone, &flite->state);
+#ifdef TASKLET_MSG
+ merr("[SEN] request is empty0(%d slot)", flite, bdone);
+#endif
+ } else {
+ frame_done = NULL;
+ }
+ }
+
+ if (frame_done)
+ fimc_is_frame_trans_pro_to_com(framemgr, frame_done);
+
+ } else {
+#ifdef TASKLET_MSG
+ merr("[SEN] process is empty(%d, %ld)", flite, bdone, flite->state);
+ fimc_is_frame_print_all(framemgr);
+#endif
+ }
+ } else {
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ flite_s_buffer_addr(flite, bdone, frame->dvaddr_buffer[0]);
+ if (!flite_s_use_buffer(flite, bdone)) {
+ set_bit(bdone, &flite->state);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+
+ /* swap process queue list */
+ fimc_is_frame_swap_process_head(framemgr);
+ }
+ } else {
+#ifdef TASKLET_MSG
+ merr("request is empty1(%d slot)", flite, bdone);
+ fimc_is_frame_print_all(framemgr);
+#endif
+ }
+ }
+
+ framemgr_x_barrier(framemgr, FMGR_IDX_1 + bdone);
+
+#ifdef ENABLE_FLITE_OVERFLOW_STOP
+ovf_exit:
+#endif
+ v4l2_subdev_notify(subdev, FLITE_NOTIFY_FEND, frame_done);
+ flite->early_work_called = true;
+}
+
+static void tasklet_flite_end_chk(unsigned long data)
+{
+ struct v4l2_subdev *subdev = NULL;
+ struct fimc_is_device_flite *flite = NULL;
+ subdev = (struct v4l2_subdev *)data;
+ flite = v4l2_get_subdevdata(subdev);
+
+ if (flite->early_work_called == false) {
+ u32 fcount = atomic_read(&flite->fcount);
+ info("[CamIF%d][%08d] delayed work queue was slower than end irq",
+ flite->instance, fcount);
+ }
+
+ return;
+}
+
+#ifdef SUPPORTED_EARLY_BUF_DONE
+static void wq_func_flite_early_work(struct work_struct *data)
+{
+ struct fimc_is_device_flite *flite = NULL;
+ struct delayed_work *early_work_wq = NULL;
+
+ early_work_wq = container_of(data, struct delayed_work,
+ work);
+ flite = container_of(early_work_wq, struct fimc_is_device_flite,
+ early_work_wq);
+
+ if (!flite) {
+ err("flite is NULL");
+ BUG();
+ }
+
+ flite->tasklet_param_end = flite->sw_trigger;
+ tasklet_schedule(&flite->tasklet_flite_early_end);
+}
+
+static void chk_early_buf_done(struct fimc_is_device_flite *flite, u32 framerate, u32 position)
+{
+ /* ms */
+ u32 margin = 0;
+ u32 duration = 0;
+
+ /* HACK: applied on 15~30fps forcely */
+ if (framerate > 15 && framerate <= 30) {
+
+ duration = 1000 / framerate;
+
+ if (position == SENSOR_POSITION_REAR)
+ flite->early_buf_done_mode = FLITE_BUF_EARLY_30P;
+ else
+ flite->early_buf_done_mode = FLITE_BUF_EARLY_20P;
+
+ margin = FLITE_VVALID_TIME_BASE * (flite->early_buf_done_mode * 0.1f);
+
+ if (margin >= duration) {
+ /* normal buffer done mode */
+ flite->buf_done_mode = FLITE_BUF_DONE_NORMAL;
+ flite->early_buf_done_mode = FLITE_BUF_EARLY_NOTHING;
+ flite->buf_done_wait_time = 0;
+ } else {
+ /* early buffer done mode */
+ flite->buf_done_mode = FLITE_BUF_DONE_EARLY;
+ flite->buf_done_wait_time = duration - margin;
+ }
+ } else {
+ /* normal buffer done mode */
+ flite->buf_done_mode = FLITE_BUF_DONE_NORMAL;
+ flite->early_buf_done_mode = FLITE_BUF_EARLY_NOTHING;
+ flite->buf_done_wait_time = 0;
+ }
+
+ info("[CamIF%d] buffer done mode [m%d/em%d/du%d/mg%d/wt%d]", flite->instance,
+ flite->buf_done_mode, flite->early_buf_done_mode, duration, margin,
+ flite->buf_done_wait_time);
+}
+#endif
+
+static inline void notify_fcount(struct fimc_is_device_flite *flite)
+{
+ if (test_bit(FLITE_JOIN_ISCHAIN, &flite->state)) {
+ if (flite->instance== FLITE_ID_A)
+ writel(atomic_read(&flite->fcount), notify_fcount_sen0);
+ else if (flite->instance == FLITE_ID_B)
+ writel(atomic_read(&flite->fcount), notify_fcount_sen1);
+ else if (flite->instance == FLITE_ID_C)
+ writel(atomic_read(&flite->fcount), notify_fcount_sen2);
+ else
+ err("unresolved channel(%d)", flite->instance);
+ }
+}
+
+static irqreturn_t fimc_is_flite_isr(int irq, void *data)
+{
+ u32 status, status1, status2, i;
+ struct fimc_is_device_flite *flite;
+
+ flite = data;
+ status1 = flite_hw_getnclr_status1(flite->base_reg);
+ status = status1 & (3 << 4);
+
+ if (test_bit(FLITE_LAST_CAPTURE, &flite->state)) {
+ if (status1) {
+ info("[CamIF%d] last status1 : 0x%08X\n", flite->instance, status1);
+ goto clear_status;
+ }
+
+ err("[CamIF%d] unintended intr is occured", flite->instance);
+
+ for (i = 0; i < 278; i += 4)
+ info("REG[%X] : 0x%08X\n", i, readl(flite->base_reg + i));
+
+ flite_hw_force_reset(flite->base_reg);
+
+ goto clear_status;
+ }
+
+ if (status) {
+ if (status == (3 << 4)) {
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "*");
+#endif
+ /* frame both interrupt since latency */
+ if (flite->sw_checker) {
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT ">");
+#endif
+ /* frame end interrupt */
+ flite->sw_checker = EXPECT_FRAME_START;
+ flite->tasklet_param_end = flite->sw_trigger;
+ tasklet_schedule(&flite->tasklet_flite_end);
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "<");
+#endif
+ /* frame start interrupt */
+ flite->sw_checker = EXPECT_FRAME_END;
+ if (flite->sw_trigger)
+ flite->sw_trigger = FLITE_A_SLOT_VALID;
+ else
+ flite->sw_trigger = FLITE_B_SLOT_VALID;
+ flite->tasklet_param_str = flite->sw_trigger;
+ atomic_inc(&flite->fcount);
+ notify_fcount(flite);
+ tasklet_schedule(&flite->tasklet_flite_str);
+ } else {
+ /* W/A: Skip start tasklet at interrupt lost case */
+ warn("[CamIF%d] invalid interrupt interval",
+ flite->instance);
+ goto clear_status;
+/* HACK: Disable dead code because of Prevent Issue */
+#if 0
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "<");
+#endif
+ /* frame start interrupt */
+ flite->sw_checker = EXPECT_FRAME_END;
+ if (flite->sw_trigger)
+ flite->sw_trigger = FLITE_A_SLOT_VALID;
+ else
+ flite->sw_trigger = FLITE_B_SLOT_VALID;
+ flite->tasklet_param_str = flite->sw_trigger;
+ atomic_inc(&flite->fcount);
+ notify_fcount(flite);
+ if (flite->buf_done_mode == FLITE_BUF_DONE_EARLY)
+ flite->early_work_skip = true;
+ tasklet_schedule(&flite->tasklet_flite_str);
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT ">");
+#endif
+ /* frame end interrupt */
+ flite->sw_checker = EXPECT_FRAME_START;
+ flite->tasklet_param_end = flite->sw_trigger;
+ if (flite->buf_done_mode == FLITE_BUF_DONE_EARLY)
+ tasklet_schedule(&flite->tasklet_flite_early_end);
+ tasklet_schedule(&flite->tasklet_flite_end);
+#endif
+ }
+ } else if (status == (2 << 4)) {
+ /* W/A: Skip start tasklet at interrupt lost case */
+ if (flite->sw_checker != EXPECT_FRAME_START)
+ warn("[CamIF%d] Lost end interupt\n",
+ flite->instance);
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "<");
+#endif
+ /* frame start interrupt */
+ flite->sw_checker = EXPECT_FRAME_END;
+ if (flite->sw_trigger)
+ flite->sw_trigger = FLITE_A_SLOT_VALID;
+ else
+ flite->sw_trigger = FLITE_B_SLOT_VALID;
+ flite->tasklet_param_str = flite->sw_trigger;
+ atomic_inc(&flite->fcount);
+ notify_fcount(flite);
+ tasklet_schedule(&flite->tasklet_flite_str);
+ } else {
+ /* W/A: Skip end tasklet at interrupt lost case */
+ if (flite->sw_checker != EXPECT_FRAME_END) {
+ warn("[CamIF%d] Lost start interupt\n",
+ flite->instance);
+ goto clear_status;
+ }
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT ">");
+#endif
+ /* frame end interrupt */
+ flite->sw_checker = EXPECT_FRAME_START;
+ if (flite->buf_done_mode == FLITE_BUF_DONE_NORMAL)
+ flite->tasklet_param_end = flite->sw_trigger;
+ tasklet_schedule(&flite->tasklet_flite_end);
+ }
+ }
+
+clear_status:
+ if (status1 & (1 << 6)) {
+ /* Last Frame Capture Interrupt */
+ info("[CamIF%d] Last Frame Capture(fcount : %d)\n",
+ flite->instance, atomic_read(&flite->fcount));
+
+ /* Clear LastCaptureEnd bit */
+ status2 = flite_hw_get_status2(flite->base_reg);
+ status2 &= ~(0x1 << 1);
+ flite_hw_set_status2(flite->base_reg, status2);
+
+ /* Notify last capture */
+ set_bit(FLITE_LAST_CAPTURE, &flite->state);
+ wake_up(&flite->wait_queue);
+ }
+
+ if (status1 & (1 << 8)) {
+ u32 ciwdofst;
+
+ flite_hw_clr_ovf_interrupt_source(flite->base_reg);
+ flite->overflow_cnt++;
+
+ if ((flite->overflow_cnt % FLITE_OVERFLOW_COUNT == 0) ||
+ (flite->overflow_cnt < FLITE_OVERFLOW_COUNT))
+ pr_err("[CamIF%d] OFCR(cnt:%u)\n", flite->instance, flite->overflow_cnt);
+ ciwdofst = readl(flite->base_reg + TO_WORD_OFFSET(0x10));
+ ciwdofst |= (0x1 << 14);
+ writel(ciwdofst, flite->base_reg + TO_WORD_OFFSET(0x10));
+ ciwdofst &= ~(0x1 << 14);
+ writel(ciwdofst, flite->base_reg + TO_WORD_OFFSET(0x10));
+ }
+
+ if (status1 & (1 << 9)) {
+ u32 ciwdofst;
+
+ flite_hw_clr_ovf_interrupt_source(flite->base_reg);
+ flite->overflow_cnt++;
+
+ if ((flite->overflow_cnt % FLITE_OVERFLOW_COUNT == 0) ||
+ (flite->overflow_cnt < FLITE_OVERFLOW_COUNT))
+ pr_err("[CamIF%d] OFCB(cnt:%u)\n", flite->instance, flite->overflow_cnt);
+ ciwdofst = readl(flite->base_reg + TO_WORD_OFFSET(0x10));
+ ciwdofst |= (0x1 << 15);
+ writel(ciwdofst, flite->base_reg + TO_WORD_OFFSET(0x10));
+ ciwdofst &= ~(0x1 << 15);
+ writel(ciwdofst, flite->base_reg + TO_WORD_OFFSET(0x10));
+ }
+
+ if (status1 & (1 << 10)) {
+ u32 ciwdofst;
+
+ flite_hw_clr_ovf_interrupt_source(flite->base_reg);
+ flite->overflow_cnt++;
+
+ if ((flite->overflow_cnt % FLITE_OVERFLOW_COUNT == 0) ||
+ (flite->overflow_cnt < FLITE_OVERFLOW_COUNT)) {
+ pr_err("[CamIF%d] OFY(cnt:%u)\n", flite->instance, flite->overflow_cnt);
+#ifdef ENABLE_FLITE_OVERFLOW_STOP
+ tasklet_schedule(&flite->tasklet_flite_end);
+#endif
+ }
+ ciwdofst = readl(flite->base_reg + TO_WORD_OFFSET(0x10));
+ ciwdofst |= (0x1 << 30);
+ writel(ciwdofst, flite->base_reg + TO_WORD_OFFSET(0x10));
+ ciwdofst &= ~(0x1 << 30);
+ writel(ciwdofst, flite->base_reg + TO_WORD_OFFSET(0x10));
+ }
+
+ return IRQ_HANDLED;
+}
+
+int fimc_is_flite_open(struct v4l2_subdev *subdev,
+ struct fimc_is_framemgr *framemgr)
+{
+ int ret = 0;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!subdev);
+ BUG_ON(!framemgr);
+
+ flite = v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ flite->group = 0;
+ flite->framemgr = framemgr;
+ atomic_set(&flite->fcount, 0);
+ atomic_set(&flite->bcount, 0);
+
+ clear_bit(FLITE_JOIN_ISCHAIN, &flite->state);
+ clear_bit(FLITE_OTF_WITH_3AA, &flite->state);
+ clear_bit(FLITE_LAST_CAPTURE, &flite->state);
+ clear_bit(FLITE_A_SLOT_VALID, &flite->state);
+ clear_bit(FLITE_B_SLOT_VALID, &flite->state);
+
+ switch(flite->instance) {
+ case FLITE_ID_A:
+ ret = request_irq(IRQ_FIMC_LITE0,
+ fimc_is_flite_isr,
+ IRQF_SHARED,
+ "fimc-lite0",
+ flite);
+ if (ret)
+ err("request_irq(L0) failed\n");
+ break;
+ case FLITE_ID_B:
+ ret = request_irq(IRQ_FIMC_LITE1,
+ fimc_is_flite_isr,
+ IRQF_SHARED,
+ "fimc-lite1",
+ flite);
+ if (ret)
+ err("request_irq(L1) failed\n");
+ break;
+#ifdef IRQ_FIMC_LITE2
+ case FLITE_ID_C:
+ ret = request_irq(IRQ_FIMC_LITE2,
+ fimc_is_flite_isr,
+ IRQF_SHARED,
+ "fimc-lite2",
+ flite);
+ if (ret)
+ err("request_irq(L2) failed\n");
+ break;
+#endif
+ default:
+ err("instance is invalid(%d)", flite->instance);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_flite_close(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!subdev);
+
+ flite = v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ switch(flite->instance) {
+ case FLITE_ID_A:
+ free_irq(IRQ_FIMC_LITE0, flite);
+ break;
+ case FLITE_ID_B:
+ free_irq(IRQ_FIMC_LITE1, flite);
+ break;
+#ifdef IRQ_FIMC_LITE2
+ case FLITE_ID_C:
+ free_irq(IRQ_FIMC_LITE2, flite);
+ break;
+#endif
+ default:
+ err("instance is invalid(%d)", flite->instance);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+/* value : csi ch */
+static int flite_init(struct v4l2_subdev *subdev, u32 value)
+{
+ int ret = 0;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!subdev);
+
+ flite = v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ flite->csi = value;
+
+p_err:
+ return ret;
+}
+
+static int flite_stream_on(struct v4l2_subdev *subdev,
+ struct fimc_is_device_flite *flite)
+{
+ int ret = 0;
+ u32 otf_setting, bns;
+ bool buffer_ready;
+ unsigned long flags;
+ struct fimc_is_image *image;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ struct fimc_is_device_sensor *device = v4l2_get_subdev_hostdata(subdev);
+
+ BUG_ON(!flite);
+ BUG_ON(!flite->framemgr);
+ BUG_ON(!device);
+
+ otf_setting = 0;
+ buffer_ready = false;
+ framemgr = flite->framemgr;
+ image = &flite->image;
+ bns = device->pdata->is_bns;
+
+ flite->overflow_cnt = 0;
+ flite->sw_trigger = FLITE_B_SLOT_VALID;
+ flite->sw_checker = EXPECT_FRAME_START;
+ flite->tasklet_param_str = 0;
+ flite->tasklet_param_end = 0;
+ atomic_set(&flite->bcount, 0);
+ clear_bit(FLITE_LAST_CAPTURE, &flite->state);
+ clear_bit(FLITE_A_SLOT_VALID, &flite->state);
+ clear_bit(FLITE_B_SLOT_VALID, &flite->state);
+
+ /* 1. init */
+ flite_hw_force_reset(flite->base_reg);
+ init_fimc_lite(flite->base_reg);
+
+ /* 2. dma setting */
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ if (framemgr->frame_req_cnt >= 1) {
+ fimc_is_frame_request_head(framemgr, &frame);
+ flite_s_use_buffer(flite, FLITE_A_SLOT_VALID);
+ flite_s_buffer_addr(flite, FLITE_A_SLOT_VALID, frame->dvaddr_buffer[0]);
+ set_bit(FLITE_A_SLOT_VALID, &flite->state);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ buffer_ready = true;
+ }
+
+ if (framemgr->frame_req_cnt >= 1) {
+ fimc_is_frame_request_head(framemgr, &frame);
+ flite_s_use_buffer(flite, FLITE_B_SLOT_VALID);
+ flite_s_buffer_addr(flite, FLITE_B_SLOT_VALID, frame->dvaddr_buffer[0]);
+ set_bit(FLITE_B_SLOT_VALID, &flite->state);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ buffer_ready = true;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+
+ flite_hw_set_output_dma(flite->base_reg, buffer_ready, image->format.pixelformat);
+
+ /* 3. otf setting */
+ if (device->ischain)
+ set_bit(FLITE_JOIN_ISCHAIN, &flite->state);
+ else
+ clear_bit(FLITE_JOIN_ISCHAIN, &flite->state);
+
+ if (device->ischain && IS_ISCHAIN_OTF(device->ischain)) {
+ tasklet_init(&flite->tasklet_flite_str, tasklet_flite_str0, (unsigned long)subdev);
+ tasklet_init(&flite->tasklet_flite_end, tasklet_flite_end, (unsigned long)subdev);
+
+ if (device->ischain->group_3aa.id == GROUP_ID_3A0) {
+ flite->group = GROUP_ID_3A0;
+ } else if (device->ischain->group_3aa.id == GROUP_ID_3A1) {
+ flite->group = GROUP_ID_3A1;
+ } else {
+ merr("invalid otf path(%d)", device, device->ischain->group_3aa.id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ mdbgd_back("Enabling OTF path. target 3aa(%d)\n", flite, flite->group);
+ if (flite->instance == FLITE_ID_A) {
+ if (flite->group == GROUP_ID_3A0)
+ otf_setting = FLITE_REG_CIGENERAL_CAM_A;
+ else
+ otf_setting = FLITE_REG_CIGENERAL_3AA1_CAM_A;
+ } else if (flite->instance == FLITE_ID_B) {
+ if (flite->group == GROUP_ID_3A0)
+ otf_setting = FLITE_REG_CIGENERAL_CAM_B;
+ else
+ otf_setting = FLITE_REG_CIGENERAL_3AA1_CAM_B;
+ } else {
+ merr("invalid FLITE channel for OTF setting", flite);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ flite_hw_set_output_local(flite->base_reg, true);
+ set_bit(FLITE_OTF_WITH_3AA, &flite->state);
+ } else {
+ switch (flite->buf_done_mode) {
+ case FLITE_BUF_DONE_NORMAL:
+ tasklet_init(&flite->tasklet_flite_str, tasklet_flite_str1, (unsigned long)subdev);
+ tasklet_init(&flite->tasklet_flite_end, tasklet_flite_end, (unsigned long)subdev);
+ break;
+ case FLITE_BUF_DONE_EARLY:
+ flite->early_work_skip = false;
+ flite->early_work_called = false;
+ tasklet_init(&flite->tasklet_flite_str, tasklet_flite_str1, (unsigned long)subdev);
+ tasklet_init(&flite->tasklet_flite_early_end, tasklet_flite_end, (unsigned long)subdev);
+ tasklet_init(&flite->tasklet_flite_end, tasklet_flite_end_chk, (unsigned long)subdev);
+ break;
+ default:
+ tasklet_init(&flite->tasklet_flite_str, tasklet_flite_str1, (unsigned long)subdev);
+ tasklet_init(&flite->tasklet_flite_end, tasklet_flite_end, (unsigned long)subdev);
+ break;
+ }
+
+ flite_hw_set_output_local(flite->base_reg, false);
+ clear_bit(FLITE_OTF_WITH_3AA, &flite->state);
+ }
+
+ /* 4. register setting */
+ start_fimc_lite(flite->base_reg, image, otf_setting, bns, flite->csi, flite->instance);
+
+p_err:
+ return ret;
+}
+
+static int flite_stream_off(struct v4l2_subdev *subdev,
+ struct fimc_is_device_flite *flite,
+ bool nowait)
+{
+ int ret = 0;
+ unsigned long __iomem *base_reg;
+ unsigned long flags;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!flite);
+ BUG_ON(!flite->base_reg);
+ BUG_ON(!flite->framemgr);
+
+ base_reg = flite->base_reg;
+ framemgr = flite->framemgr;
+
+ /* for preventing invalid memory access */
+ flite_hw_set_unuse_buffer(base_reg, FLITE_A_SLOT_VALID);
+ flite_hw_set_unuse_buffer(base_reg, FLITE_B_SLOT_VALID);
+ flite_hw_set_output_dma(base_reg, false, flite->image.format.pixelformat);
+ flite_hw_set_output_local(base_reg, false);
+
+ stop_fimc_lite(base_reg);
+ if (!nowait) {
+ u32 timetowait;
+
+ timetowait = wait_event_timeout(flite->wait_queue,
+ test_bit(FLITE_LAST_CAPTURE, &flite->state),
+ FIMC_IS_FLITE_STOP_TIMEOUT);
+ if (!timetowait) {
+ /* forcely stop */
+ stop_fimc_lite(base_reg);
+ set_bit(FLITE_LAST_CAPTURE, &flite->state);
+ err("last capture timeout:%s", __func__);
+ msleep(200);
+ flite_hw_force_reset(base_reg);
+ ret = -ETIME;
+ }
+ } else {
+ if (flite->buf_done_mode == FLITE_BUF_DONE_EARLY)
+ flush_delayed_work(&flite->early_work_wq);
+ /*
+ * DTP test can make iommu fault because senosr is streaming
+ * therefore it need force reset
+ */
+ flite_hw_force_reset(base_reg);
+ }
+
+ if (flite->buf_done_mode == FLITE_BUF_DONE_EARLY)
+ cancel_delayed_work_sync(&flite->early_work_wq);
+
+ /* clr interrupt source */
+ flite_hw_clr_interrupt_source(base_reg);
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_3, flags);
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ fimc_is_frame_complete_head(framemgr, &frame);
+ }
+
+ fimc_is_frame_process_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_pro_to_fre(framemgr, frame);
+ fimc_is_frame_process_head(framemgr, &frame);
+ }
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_req_to_fre(framemgr, frame);
+ fimc_is_frame_request_head(framemgr, &frame);
+ }
+
+ /* buffer done mode init */
+ flite->buf_done_mode = FLITE_BUF_DONE_NORMAL;
+ flite->early_buf_done_mode = FLITE_BUF_EARLY_NOTHING;
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_3, flags);
+
+ return ret;
+}
+
+/*
+ * enable
+ * @X0 : disable
+ * @X1 : enable
+ * @1X : no waiting flag
+ * @0X : waiting flag
+ */
+static int flite_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ int ret = 0;
+ bool nowait;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!subdev);
+
+ nowait = (enable & FLITE_NOWAIT_MASK) >> FLITE_NOWAIT_SHIFT;
+ enable = enable & FLITE_ENABLE_MASK;
+
+ flite = (struct fimc_is_device_flite *)v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (enable) {
+ ret = flite_stream_on(subdev, flite);
+ if (ret) {
+ err("flite_stream_on is fail(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ ret = flite_stream_off(subdev, flite, nowait);
+ if (ret) {
+ err("flite_stream_off is fail(%d)", ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ mdbgd_back("%s(%d, %d)\n", flite, __func__, enable, ret);
+ return 0;
+}
+
+static int flite_s_format(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *fmt)
+{
+ int ret = 0;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!subdev);
+ BUG_ON(!fmt);
+
+ flite = (struct fimc_is_device_flite *)v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ flite->image.window.offs_h = 0;
+ flite->image.window.offs_v = 0;
+ flite->image.window.width = fmt->width;
+ flite->image.window.height = fmt->height;
+ flite->image.window.o_width = fmt->width;
+ flite->image.window.o_height = fmt->height;
+ flite->image.format.pixelformat = fmt->code;
+
+p_err:
+ mdbgd_back("%s(%dx%d, %X)\n", flite, __func__, fmt->width, fmt->height, fmt->code);
+ return ret;
+}
+
+static int flite_s_ctrl(struct v4l2_subdev *subdev, struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!subdev);
+ BUG_ON(!ctrl);
+
+ flite = (struct fimc_is_device_flite *)v4l2_get_subdevdata(subdev);
+ if (!flite) {
+ err("flite is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_S_BNS:
+ {
+ u32 width, height, ratio;
+
+ width = flite->image.window.width;
+ height = flite->image.window.height;
+ ratio = ctrl->value;
+
+ flite->image.window.otf_width
+ = rounddown((width * 1000 / ratio), 4);
+ flite->image.window.otf_height
+ = rounddown((height * 1000 / ratio), 2);
+ }
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = flite_init,
+ .s_ctrl = flite_s_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops video_ops = {
+ .s_stream = flite_s_stream,
+ .s_mbus_fmt = flite_s_format
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops,
+ .video = &video_ops
+};
+
+int fimc_is_flite_probe(struct fimc_is_device_sensor *device,
+ u32 instance)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_flite;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!device);
+
+ subdev_flite = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_flite) {
+ merr("subdev_flite is NULL", device);
+ ret = -ENOMEM;
+ goto err_alloc_subdev_flite;
+ }
+ device->subdev_flite = subdev_flite;
+
+ flite = kzalloc(sizeof(struct fimc_is_device_flite), GFP_KERNEL);
+ if (!flite) {
+ merr("flite is NULL", device);
+ ret = -ENOMEM;
+ goto err_alloc_flite;
+ }
+
+ /* pointer to me from device sensor */
+ flite->subdev = &device->subdev_flite;
+ flite->instance = instance;
+ init_waitqueue_head(&flite->wait_queue);
+ switch(instance) {
+ case FLITE_ID_A:
+ flite->base_reg = (unsigned long *)FIMCLITE0_REG_BASE;
+ break;
+ case FLITE_ID_B:
+ flite->base_reg = (unsigned long *)FIMCLITE1_REG_BASE;
+ break;
+ case FLITE_ID_C:
+ flite->base_reg = (unsigned long *)FIMCLITE2_REG_BASE;
+ break;
+ default:
+ err("instance is invalid(%d)", instance);
+ ret = -EINVAL;
+ goto err_invalid_instance;
+ }
+
+ v4l2_subdev_init(subdev_flite, &subdev_ops);
+ v4l2_set_subdevdata(subdev_flite, (void *)flite);
+ v4l2_set_subdev_hostdata(subdev_flite, device);
+ snprintf(subdev_flite->name, V4L2_SUBDEV_NAME_SIZE, "flite-subdev.%d", instance);
+ ret = v4l2_device_register_subdev(&device->v4l2_dev, subdev_flite);
+ if (ret) {
+ merr("v4l2_device_register_subdev is fail(%d)", device, ret);
+ goto err_reg_v4l2_subdev;
+ }
+
+ /* buffer done mode is normal (default) */
+ flite->buf_done_mode = FLITE_BUF_DONE_NORMAL;
+ flite->early_buf_done_mode = FLITE_BUF_EARLY_NOTHING;
+ flite->chk_early_buf_done = NULL;
+#ifdef SUPPORTED_EARLY_BUF_DONE
+ flite->chk_early_buf_done = chk_early_buf_done;
+ flite->early_workqueue = alloc_workqueue("fimc-is/early_workqueue/highpri", WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
+ if (!flite->early_workqueue) {
+ warn("failed to alloc own workqueue, will be use global one");
+ goto err_reg_v4l2_subdev;
+ } else {
+ INIT_DELAYED_WORK(&flite->early_work_wq, wq_func_flite_early_work);
+ }
+#endif
+ info("[BAK:D:%d] %s(%d)\n", instance, __func__, ret);
+ return 0;
+
+err_reg_v4l2_subdev:
+err_invalid_instance:
+ kfree(flite);
+
+err_alloc_flite:
+ kfree(subdev_flite);
+ device->subdev_flite = NULL;
+
+err_alloc_subdev_flite:
+ err("[BAK:D:%d] %s(%d)\n", instance, __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_FLITE_H
+#define FIMC_IS_DEVICE_FLITE_H
+
+#include <linux/interrupt.h>
+#include "fimc-is-type.h"
+
+#define EXPECT_FRAME_START 0
+#define EXPECT_FRAME_END 1
+
+#define FLITE_NOTIFY_FSTART 0
+#define FLITE_NOTIFY_FEND 1
+
+#define FLITE_ENABLE_FLAG 1
+#define FLITE_ENABLE_MASK 0xFFFF
+#define FLITE_ENABLE_SHIFT 0
+
+#define FLITE_NOWAIT_FLAG 1
+#define FLITE_NOWAIT_MASK 0xFFFF0000
+#define FLITE_NOWAIT_SHIFT 16
+
+#define FLITE_OVERFLOW_COUNT 10
+
+#define FLITE_VVALID_TIME_BASE 32 /* ms */
+
+
+struct fimc_is_device_sensor;
+
+enum fimc_is_flite_state {
+ /* buffer state*/
+ FLITE_A_SLOT_VALID = 0,
+ FLITE_B_SLOT_VALID,
+ /* finish state */
+ FLITE_LAST_CAPTURE,
+ /* flite join ischain */
+ FLITE_JOIN_ISCHAIN,
+ /* one the fly output */
+ FLITE_OTF_WITH_3AA,
+};
+
+enum fimc_is_flite_buf_done_mode {
+ FLITE_BUF_DONE_NORMAL = 0, /* when end-irq */
+ FLITE_BUF_DONE_EARLY = 1, /* when delayed work queue since start-irq */
+};
+
+/*
+ * 10p means 10% early than end irq. We supposed that VVALID time is variable
+ * ex. 32 * 0.1 = 3ms, early interval is (33 - 3) = 29ms
+ * 32 * 0.2 = 6ms, (33 - 6) = 26ms
+ * 32 * 0.3 = 9ms, (33 - 9) = 23ms
+ * 32 * 0.4 = 12ms, (33 - 12) = 20ms
+ */
+enum fimc_is_flite_early_buf_done_mode {
+ FLITE_BUF_EARLY_NOTHING = 0,
+ FLITE_BUF_EARLY_10P = 1, /* 10%(29ms) 3ms */
+ FLITE_BUF_EARLY_20P = 2, /* 20%(26ms) 6ms */
+ FLITE_BUF_EARLY_30P = 3, /* 30%(23ms) 9ms */
+ FLITE_BUF_EARLY_40P = 4, /* 40%(20ms) 12ms */
+};
+
+struct fimc_is_device_flite {
+ u32 instance;
+ unsigned long __iomem *base_reg;
+ unsigned long state;
+ wait_queue_head_t wait_queue;
+
+ struct fimc_is_image image;
+ struct fimc_is_framemgr *framemgr;
+
+ u32 overflow_cnt;
+
+ u32 csi; /* which csi channel is connceted */
+ u32 group; /* which 3aa gorup is connected when otf is enable */
+
+ u32 sw_checker;
+ u32 sw_trigger;
+ atomic_t bcount;
+ atomic_t fcount;
+ u32 tasklet_param_str;
+ struct tasklet_struct tasklet_flite_str;
+ u32 tasklet_param_end;
+ struct tasklet_struct tasklet_flite_end;
+
+ /* for early buffer done */
+ u32 buf_done_mode;
+ u32 early_buf_done_mode;
+ u32 buf_done_wait_time;
+ bool early_work_skip;
+ bool early_work_called;
+ struct tasklet_struct tasklet_flite_early_end;
+ struct workqueue_struct *early_workqueue;
+ struct delayed_work early_work_wq;
+ void (*chk_early_buf_done)(struct fimc_is_device_flite *flite, u32 framerate, u32 position);
+
+ /* pointer address from device sensor */
+ struct v4l2_subdev **subdev;
+};
+
+int fimc_is_flite_probe(struct fimc_is_device_sensor *device,
+ u32 instance);
+int fimc_is_flite_open(struct v4l2_subdev *subdev,
+ struct fimc_is_framemgr *framemgr);
+int fimc_is_flite_close(struct v4l2_subdev *subdev);
+
+extern u32 __iomem *notify_fcount_sen0;
+extern u32 __iomem *notify_fcount_sen1;
+extern u32 __iomem *notify_fcount_sen2;
+extern u32 __iomem *last_fcount0;
+extern u32 __iomem *last_fcount1;
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/vmalloc.h>
+#include <linux/kthread.h>
+#include <linux/pm_qos.h>
+#include <linux/debugfs.h>
+#include <linux/syscalls.h>
+#include <linux/bug.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/smc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#if defined(CONFIG_SOC_EXYNOS3470)
+#include <mach/bts.h>
+#endif
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-groupmgr.h"
+#include "fimc-is-device-ischain.h"
+#include "fimc-is-companion.h"
+#include "fimc-is-clk-gate.h"
+#include "fimc-is-dvfs.h"
+#include "fimc-is-device-companion.h"
+#include <linux/pinctrl/consumer.h>
+#include <mach/pinctrl-samsung.h>
+
+#ifdef CONFIG_USE_VENDER_FEATURE
+#include "fimc-is-sec-define.h"
+#else
+#define SDCARD_FW
+#define FIMC_IS_SETFILE_SDCARD_PATH "/data/"
+#define FIMC_IS_FW "fimc_is_fw2.bin"
+#define FIMC_IS_FW_SDCARD "/data/fimc_is_fw2.bin"
+
+#define FIMC_IS_FW_BASE_MASK ((1 << 26) - 1)
+#define FIMC_IS_VERSION_SIZE 42
+#define FIMC_IS_SETFILE_VER_OFFSET 0x40
+#define FIMC_IS_SETFILE_VER_SIZE 52
+
+#define FIMC_IS_CAL_SDCARD "/data/cal_data.bin"
+#define FIMC_IS_CAL_SDCARD_FRONT "/data/cal_data_front.bin"
+#define FIMC_IS_MAX_FW_SIZE (2048 * 1024)
+#define FIMC_IS_CAL_START_ADDR (0x013D0000)
+#define FIMC_IS_CAL_START_ADDR_FRONT (0x013E0000)
+#define FIMC_IS_CAL_RETRY_CNT (2)
+#define FIMC_IS_FW_RETRY_CNT (2)
+#endif
+
+/* Default setting values */
+#define DEFAULT_PREVIEW_STILL_WIDTH (1280) /* sensor margin : 16 */
+#define DEFAULT_PREVIEW_STILL_HEIGHT (720) /* sensor margin : 12 */
+#define DEFAULT_CAPTURE_VIDEO_WIDTH (1920)
+#define DEFAULT_CAPTURE_VIDEO_HEIGHT (1080)
+#define DEFAULT_CAPTURE_STILL_WIDTH (2560)
+#define DEFAULT_CAPTURE_STILL_HEIGHT (1920)
+#define DEFAULT_CAPTURE_STILL_CROP_WIDTH (2560)
+#define DEFAULT_CAPTURE_STILL_CROP_HEIGHT (1440)
+#define DEFAULT_PREVIEW_VIDEO_WIDTH (640)
+#define DEFAULT_PREVIEW_VIDEO_HEIGHT (480)
+
+/* sysfs variable for debug */
+extern struct fimc_is_sysfs_debug sysfs_debug;
+
+#ifdef FW_DEBUG
+#define DEBUG_FS_ROOT_NAME "fimc-is"
+#define DEBUG_FS_FILE_NAME "isfw-msg"
+static struct dentry *debugfs_root;
+static struct dentry *debugfs_file;
+
+#define SETFILE_SIZE 0x6000
+#define READ_SIZE 0x100
+
+static char fw_name[100];
+//static char setf_name[100];
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+#define FIMC_IS_MAX_CAL_SIZE (8 * 1024)
+#else
+#define FIMC_IS_MAX_CAL_SIZE (64 * 1024)
+#endif
+#define FIMC_IS_MAX_CAL_SIZE_FRONT (8 * 1024)
+
+#define FIMC_IS_DEFAULT_CAL_SIZE (20 * 1024)
+extern bool crc32_check;
+extern bool crc32_header_check;
+extern bool crc32_check_front;
+extern bool crc32_header_check_front;
+
+static int cam_id;
+#ifdef CONFIG_USE_VENDER_FEATURE
+extern bool is_dumped_fw_loading_needed;
+extern char fw_core_version;
+#else
+bool is_dumped_fw_loading_needed = false;
+#endif
+
+static int isfw_debug_open(struct inode *inode, struct file *file)
+{
+ if (inode->i_private)
+ file->private_data = inode->i_private;
+
+ return 0;
+}
+
+static int isfw_debug_read(struct file *file, char __user *user_buf,
+ size_t buf_len, loff_t *ppos)
+{
+ char *debug;
+ size_t debug_cnt, backup_cnt;
+ size_t count1, count2;
+ size_t buf_count = 0;
+ struct fimc_is_device_ischain *device =
+ (struct fimc_is_device_ischain *)file->private_data;
+ struct fimc_is_ishcain_mem *imemory;
+ struct fimc_is_core *core;
+
+ BUG_ON(!device);
+
+ count1 = 0;
+ count2 = 0;
+ debug_cnt = 0;
+ imemory = &device->imemory;
+ core = (struct fimc_is_core *)device->interface->core;
+
+ if (atomic_read(&core->video_isp.refcount) <= 0) {
+ err("isp video node is not open");
+ goto exit;
+ }
+
+ vb2_ion_sync_for_device(imemory->fw_cookie, DEBUG_OFFSET,
+ DEBUG_CNT, DMA_FROM_DEVICE);
+
+ debug_cnt = *((int *)(imemory->kvaddr + DEBUGCTL_OFFSET)) - DEBUG_OFFSET;
+ backup_cnt = core->debug_cnt;
+
+ if (core->debug_cnt > debug_cnt) {
+ count1 = DEBUG_CNT - core->debug_cnt;
+ count2 = debug_cnt;
+ } else {
+ count1 = debug_cnt - core->debug_cnt;
+ count2 = 0;
+ }
+
+ buf_count = buf_len;
+
+ if (buf_count && count1) {
+ debug = (char *)(imemory->kvaddr + DEBUG_OFFSET + core->debug_cnt);
+
+ if (count1 > buf_count)
+ count1 = buf_count;
+
+ buf_count -= count1;
+
+ memcpy(user_buf, debug, count1);
+ core->debug_cnt += count1;
+ }
+
+ if (buf_count && count2) {
+ debug = (char *)(imemory->kvaddr + DEBUG_OFFSET);
+
+ if (count2 > buf_count)
+ count2 = buf_count;
+
+ buf_count -= count2;
+
+ memcpy(user_buf, debug, count2);
+ core->debug_cnt = count2;
+ }
+
+ info("FW_READ : Origin(%d), New(%d) - Length(%d)\n",
+ backup_cnt,
+ core->debug_cnt,
+ (buf_len - buf_count));
+
+exit:
+ return buf_len - buf_count;
+}
+
+static const struct file_operations debug_fops = {
+ .open = isfw_debug_open,
+ .read = isfw_debug_read,
+ .llseek = default_llseek
+};
+
+#endif
+
+static const struct sensor_param init_sensor_param = {
+ .config = {
+#ifdef FIXED_FPS_DEBUG
+ .framerate = FIXED_FPS_VALUE,
+ .min_target_fps = FIXED_FPS_VALUE,
+ .max_target_fps = FIXED_FPS_VALUE,
+#else
+ .framerate = 30,
+ .min_target_fps = 15,
+ .max_target_fps = 30,
+#endif
+ },
+};
+
+static const struct taa_param init_taa_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_BAYER,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_10BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .bayer_crop_offset_x = 0,
+ .bayer_crop_offset_y = 0,
+ .bayer_crop_width = 0,
+ .bayer_crop_height = 0,
+ .frametime_min = 0,
+ .frametime_max = 33333,
+ .sensor_binning_ratio_x = 1000,
+ .sensor_binning_ratio_y = 1000,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .vdma1_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0,
+ .height = 0,
+ .format = 0,
+ .bitwidth = 0,
+ .plane = 0,
+ .order = 0,
+ .bayer_crop_offset_x = 0,
+ .bayer_crop_offset_y = 0,
+ .bayer_crop_width = 0,
+ .bayer_crop_height = 0,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .sensor_binning_ratio_x = 1000,
+ .sensor_binning_ratio_y = 1000,
+ .err = 0,
+ },
+ .ddma_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_DISABLE,
+ },
+ .vdma4_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .dma_out_mask = 0,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_INPUT_FORMAT_YUV444,
+ .bitwidth = DMA_INPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_INPUT_PLANE_1,
+ .order = DMA_INPUT_ORDER_YCbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+ .vdma2_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_BAYER,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_12BIT,
+ .plane = DMA_OUTPUT_PLANE_1,
+ .order = DMA_OUTPUT_ORDER_GB_BG,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xFFFFFFFF,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+ .ddma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ },
+};
+
+static const struct isp_param init_isp_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_DISABLE,
+ },
+ .vdma1_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0,
+ .height = 0,
+ .format = 0,
+ .bitwidth = 0,
+ .plane = 0,
+ .order = 0,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .sensor_binning_ratio_x = 1000,
+ .sensor_binning_ratio_y = 1000,
+ .err = 0,
+ },
+ .vdma3_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_12BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .vdma4_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ },
+ .vdma5_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ },
+};
+
+static const struct drc_param init_drc_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_12BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_INPUT_FORMAT_YUV444,
+ .bitwidth = DMA_INPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_INPUT_PLANE_1,
+ .order = DMA_INPUT_ORDER_YCbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_12BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct scalerc_param init_scalerc_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_12BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .bayer_crop_offset_x = 0,
+ .bayer_crop_offset_y = 0,
+ .bayer_crop_width = 0,
+ .bayer_crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .effect = {
+ .cmd = 0,
+ .arbitrary_cb = 128, /* default value : 128 */
+ .arbitrary_cr = 128, /* default value : 128 */
+ .yuv_range = SCALER_OUTPUT_YUV_RANGE_FULL,
+ .err = 0,
+ },
+ .input_crop = {
+ .cmd = OTF_INPUT_COMMAND_DISABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_STILL_CROP_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_STILL_CROP_HEIGHT,
+ .in_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .in_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .out_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .out_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .err = 0,
+ },
+ .output_crop = {
+ .cmd = SCALER_CROP_COMMAND_DISABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV422,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV422,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_1,
+ .order = DMA_OUTPUT_ORDER_CrYCbY,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .reserved[0] = SCALER_DMA_OUT_UNSCALED,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct odc_param init_odc_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .bayer_crop_offset_x = 0,
+ .bayer_crop_offset_y = 0,
+ .bayer_crop_width = 0,
+ .bayer_crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV422,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct dis_param init_dis_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .bayer_crop_offset_x = 0,
+ .bayer_crop_offset_y = 0,
+ .bayer_crop_width = 0,
+ .bayer_crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV422,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+static const struct tdnr_param init_tdnr_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .frame = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV420,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_2,
+ .order = DMA_OUTPUT_ORDER_CbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct scalerp_param init_scalerp_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .bayer_crop_offset_x = 0,
+ .bayer_crop_offset_y = 0,
+ .bayer_crop_width = 0,
+ .bayer_crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .effect = {
+ .cmd = 0,
+ .arbitrary_cb = 128, /* default value : 128 */
+ .arbitrary_cr = 128, /* default value : 128 */
+ .yuv_range = SCALER_OUTPUT_YUV_RANGE_FULL,
+ .err = 0,
+ },
+ .input_crop = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .in_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .in_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .out_width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .out_height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .err = 0,
+ },
+ .output_crop = {
+ .cmd = SCALER_CROP_COMMAND_DISABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .crop_height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV420,
+ .err = 0,
+ },
+ .rotation = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .flip = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV420,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_3,
+ .order = DMA_OUTPUT_ORDER_NO,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct fd_param init_fd_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_STOP,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0, .height = 0,
+ .format = 0, .bitwidth = 0, .plane = 0,
+ .order = 0, .buffer_number = 0, .buffer_address = 0,
+ .err = 0,
+ },
+ .config = {
+ .cmd = FD_CONFIG_COMMAND_MAXIMUM_NUMBER |
+ FD_CONFIG_COMMAND_ROLL_ANGLE |
+ FD_CONFIG_COMMAND_YAW_ANGLE |
+ FD_CONFIG_COMMAND_SMILE_MODE |
+ FD_CONFIG_COMMAND_BLINK_MODE |
+ FD_CONFIG_COMMAND_EYES_DETECT |
+ FD_CONFIG_COMMAND_MOUTH_DETECT |
+ FD_CONFIG_COMMAND_ORIENTATION |
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE,
+ .max_number = CAMERA2_MAX_FACES,
+ .roll_angle = FD_CONFIG_ROLL_ANGLE_FULL,
+ .yaw_angle = FD_CONFIG_YAW_ANGLE_45_90,
+ .smile_mode = FD_CONFIG_SMILE_MODE_DISABLE,
+ .blink_mode = FD_CONFIG_BLINK_MODE_DISABLE,
+ .eye_detect = FD_CONFIG_EYES_DETECT_ENABLE,
+ .mouth_detect = FD_CONFIG_MOUTH_DETECT_DISABLE,
+ .orientation = FD_CONFIG_ORIENTATION_DISABLE,
+ .orientation_value = 0,
+ .err = ERROR_FD_NO,
+ },
+};
+
+#ifndef RESERVED_MEM
+static int fimc_is_ishcain_deinitmem(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+
+ vb2_ion_private_free(device->imemory.fw_cookie);
+
+ return ret;
+}
+#endif
+
+static void fimc_is_ischain_cache_flush(struct fimc_is_device_ischain *this,
+ u32 offset, u32 size)
+{
+ vb2_ion_sync_for_device(this->imemory.fw_cookie,
+ offset,
+ size,
+ DMA_TO_DEVICE);
+}
+
+static void fimc_is_ischain_region_invalid(struct fimc_is_device_ischain *device)
+{
+ vb2_ion_sync_for_device(
+ device->imemory.fw_cookie,
+ device->imemory.offset_region,
+ sizeof(struct is_region),
+ DMA_FROM_DEVICE);
+}
+
+static void fimc_is_ischain_region_flush(struct fimc_is_device_ischain *device)
+{
+ vb2_ion_sync_for_device(
+ device->imemory.fw_cookie,
+ device->imemory.offset_region,
+ sizeof(struct is_region),
+ DMA_TO_DEVICE);
+}
+
+void fimc_is_ischain_meta_flush(struct fimc_is_frame *frame)
+{
+#ifdef ENABLE_CACHE
+ vb2_ion_sync_for_device(
+ (void *)frame->cookie_shot,
+ 0,
+ frame->shot_size,
+ DMA_TO_DEVICE);
+#endif
+}
+
+void fimc_is_ischain_meta_invalid(struct fimc_is_frame *frame)
+{
+#ifdef ENABLE_CACHE
+ vb2_ion_sync_for_device(
+ (void *)frame->cookie_shot,
+ 0,
+ frame->shot_size,
+ DMA_FROM_DEVICE);
+#endif
+}
+
+static void fimc_is_ischain_version(struct fimc_is_device_ischain *this, char *name, const char *load_bin, u32 size)
+{
+ struct fimc_is_from_info *pinfo = NULL;
+ char version_str[60];
+
+ if (!strcmp(fw_name, name)) {
+ memcpy(version_str, &load_bin[size - FIMC_IS_VERSION_SIZE],
+ FIMC_IS_VERSION_SIZE);
+ version_str[FIMC_IS_VERSION_SIZE] = '\0';
+
+ pinfo = &this->pinfo;
+ memcpy(pinfo->header_ver, &version_str[32], 11);
+ pinfo->header_ver[11] = '\0';
+ } else {
+ memcpy(version_str, &load_bin[size - FIMC_IS_SETFILE_VER_OFFSET],
+ FIMC_IS_SETFILE_VER_SIZE);
+ version_str[FIMC_IS_SETFILE_VER_SIZE] = '\0';
+
+ pinfo = &this->pinfo;
+ memcpy(pinfo->setfile_ver, &version_str[17], 4);
+ pinfo->setfile_ver[4] = '\0';
+ }
+
+ info("%s version : %s\n", name, version_str);
+}
+
+void fimc_is_ischain_savefirm(struct fimc_is_device_ischain *this)
+{
+#ifdef DEBUG_DUMP_FIRMWARE
+ loff_t pos;
+
+ write_data_to_file("/data/firmware.bin", (char *)this->imemory.kvaddr,
+ (size_t)FIMC_IS_A5_MEM_SIZE, &pos);
+#endif
+}
+
+static int fimc_is_ischain_loadfirm(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ int location = 0;
+ const struct firmware *fw_blob = NULL;
+ u8 *buf = NULL;
+#ifdef USE_ION_ALLOC
+ struct ion_handle *handle = NULL;
+ struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(device->pdev);
+#endif
+#ifdef SDCARD_FW
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long fsize, nread;
+ int fw_requested = 1;
+ char fw_path[100];
+ int retry_count = 0;
+
+ mdbgd_ischain("%s\n", device, __func__);
+#ifdef USE_ION_ALLOC
+ BUG_ON(!core);
+ BUG_ON(!core->fimc_ion_client);
+#endif
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fp = filp_open(FIMC_IS_FW_SDCARD, O_RDONLY, 0);
+ if (IS_ERR_OR_NULL(fp)) {
+#ifdef CONFIG_USE_VENDER_FEATURE
+ if (is_dumped_fw_loading_needed &&
+ device->pdev->id == SENSOR_POSITION_REAR) {
+ snprintf(fw_path, sizeof(fw_path), "%s%s",
+ FIMC_IS_FW_DUMP_PATH, FIMC_IS_FW);
+ fp = filp_open(fw_path, O_RDONLY, 0);
+ if (IS_ERR_OR_NULL(fp)) {
+ fp = NULL;
+ ret = -EIO;
+ set_fs(old_fs);
+ goto out;
+ }
+ } else
+#endif
+ goto request_fw;
+ }
+
+ location = 1;
+ fw_requested = 0;
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start, file path %s, size %ld Bytes\n",
+ is_dumped_fw_loading_needed ? fw_path : FIMC_IS_FW_SDCARD, fsize);
+#ifdef USE_ION_ALLOC
+ handle = ion_alloc(core->fimc_ion_client, (size_t)fsize, 0,
+ EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ err("fimc_is_comp_load_binary:failed to ioc_alloc\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ buf = (u8 *)ion_map_kernel(core->fimc_ion_client, handle);
+ if (IS_ERR_OR_NULL(buf)) {
+ err("fimc_is_comp_load_binary:fail to ion_map_kernle\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+#else
+ buf = vmalloc(fsize);
+ if (!buf) {
+ dev_err(&device->pdev->dev,
+ "failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+#endif
+ nread = vfs_read(fp, (char __user *)buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ dev_err(&device->pdev->dev,
+ "failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto out;
+ }
+
+ memcpy((void *)device->imemory.kvaddr, (void *)buf, fsize);
+ fimc_is_ischain_cache_flush(device, 0, fsize + 1);
+ fimc_is_ischain_version(device, fw_name, buf, fsize);
+
+request_fw:
+ if (fw_requested) {
+ set_fs(old_fs);
+#endif
+ retry_count = 3;
+ ret = request_firmware(&fw_blob, fw_name, &device->pdev->dev);
+ while (--retry_count && ret == -EAGAIN) {
+ err("request_firmware retry(count:%d)", retry_count);
+ ret = request_firmware(&fw_blob, fw_name, &device->pdev->dev);
+ }
+
+ if (ret) {
+ err("request_firmware is fail(%d)", ret);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!fw_blob) {
+ merr("fw_blob is NULL", device);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!fw_blob->data) {
+ merr("fw_blob->data is NULL", device);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ memcpy((void *)device->imemory.kvaddr, fw_blob->data,
+ fw_blob->size);
+ fimc_is_ischain_cache_flush(device, 0, fw_blob->size + 1);
+ fimc_is_ischain_version(device, fw_name, fw_blob->data,
+ fw_blob->size);
+#ifdef SDCARD_FW
+ }
+#endif
+
+out:
+#ifdef SDCARD_FW
+#ifdef USE_ION_ALLOC
+ if (!IS_ERR_OR_NULL(buf)) {
+ ion_unmap_kernel(core->fimc_ion_client, handle);
+ }
+
+ if (!IS_ERR_OR_NULL(handle)) {
+ ion_free(core->fimc_ion_client, handle);
+ }
+#endif
+
+ if (!fw_requested) {
+#ifndef USE_ION_ALLOC
+ if (buf) {
+ vfree(buf);
+ }
+#endif
+ if (!IS_ERR_OR_NULL(fp)) {
+ filp_close(fp, current->files);
+ }
+ set_fs(old_fs);
+ } else
+#endif
+ {
+ if (!IS_ERR_OR_NULL(fw_blob)) {
+ release_firmware(fw_blob);
+ }
+ }
+ if (ret)
+ err("firmware loading is fail");
+ else
+ info("Camera: the %s FW were applied successfully.\n",
+ ((cam_id == CAMERA_SINGLE_REAR) &&
+ is_dumped_fw_loading_needed) ? "dumped" : "default");
+
+ return ret;
+}
+
+static int fimc_is_ischain_buf_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node,
+ struct fimc_is_queue *queue,
+ struct fimc_is_framemgr *framemgr,
+ u32 width, u32 height,
+ u32 target_addr[],
+ enum fimc_is_frame_output frame_output)
+{
+ int ret = 0;
+ struct fimc_is_frame *frame;
+ u32 frame_size;
+ unsigned long flags;
+
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ if (!frame->stream) {
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ merr("frame->stream is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ frame_size = width * height;
+
+ switch (queue->framecfg.format.pixelformat) {
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV12:
+ target_addr[0] = frame->dvaddr_buffer[0];
+ target_addr[1] = target_addr[0] + frame_size;
+ break;
+ case V4L2_PIX_FMT_YVU420M:
+ target_addr[0] = frame->dvaddr_buffer[0];
+ target_addr[1] = frame->dvaddr_buffer[2];
+ target_addr[2] = frame->dvaddr_buffer[1];
+ break;
+ default:
+ target_addr[0] = frame->dvaddr_buffer[0];
+ target_addr[1] = frame->dvaddr_buffer[1];
+ target_addr[2] = frame->dvaddr_buffer[2];
+ break;
+ }
+
+ frame->stream->findex = ldr_frame->index;
+ set_bit(frame_output, &ldr_frame->out_flag);
+ set_bit(REQ_FRAME, &frame->req_flag);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ } else {
+ mwarn("%d frame is drop (node-id:%d)", device, ldr_frame->fcount, node->vid);
+ target_addr[0] = 0;
+ target_addr[1] = 0;
+ target_addr[2] = 0;
+ node->request = 0;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_loadsetf(struct fimc_is_device_ischain *device,
+ u32 load_addr, char *setfile_name)
+{
+ int ret = 0;
+ int location = 0;
+ void *address;
+ const struct firmware *fw_blob = NULL;
+ u8 *buf = NULL;
+#ifdef USE_ION_ALLOC
+ struct ion_handle *handle = NULL;
+ struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(device->pdev);
+#endif
+
+#ifdef SDCARD_FW
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long fsize, nread;
+ int fw_requested = 1;
+ char setfile_path[256];
+ u32 retry;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+#ifdef USE_ION_ALLOC
+ BUG_ON(!core);
+ BUG_ON(!core->fimc_ion_client);
+#endif
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ memset(setfile_path, 0x00, sizeof(setfile_path));
+ snprintf(setfile_path, sizeof(setfile_path), "%s%s",
+ FIMC_IS_SETFILE_SDCARD_PATH, setfile_name);
+ fp = filp_open(setfile_path, O_RDONLY, 0);
+ if (IS_ERR_OR_NULL(fp)) {
+#ifdef CONFIG_USE_VENDER_FEATURE
+ if (is_dumped_fw_loading_needed &&
+ device->pdev->id == SENSOR_POSITION_REAR) {
+ memset(setfile_path, 0x00, sizeof(setfile_path));
+ snprintf(setfile_path, sizeof(setfile_path), "%s%s",
+ FIMC_IS_FW_DUMP_PATH, setfile_name);
+ fp = filp_open(setfile_path, O_RDONLY, 0);
+ if (IS_ERR_OR_NULL(fp)) {
+ ret = -EIO;
+ fp = NULL;
+ set_fs(old_fs);
+ goto out;
+ }
+ } else
+#endif
+ goto request_fw;
+ }
+
+ location = 1;
+ fw_requested = 0;
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ info("start, file path %s, size %ld Bytes\n",
+ setfile_path, fsize);
+#ifdef USE_ION_ALLOC
+ handle = ion_alloc(core->fimc_ion_client, (size_t)fsize, 0,
+ EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ err("fimc_is_comp_load_binary:failed to ioc_alloc\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ buf = (u8 *)ion_map_kernel(core->fimc_ion_client, handle);
+ if (IS_ERR_OR_NULL(buf)) {
+ err("fimc_is_comp_load_binary:fail to ion_map_kernle\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+#else
+ buf = vmalloc(fsize);
+ if (!buf) {
+ dev_err(&device->pdev->dev,
+ "failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+#endif
+ nread = vfs_read(fp, (char __user *)buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ dev_err(&device->pdev->dev,
+ "failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto out;
+ }
+
+ address = (void *)(device->imemory.kvaddr + load_addr);
+ memcpy((void *)address, (void *)buf, fsize);
+ fimc_is_ischain_cache_flush(device, load_addr, fsize + 1);
+ fimc_is_ischain_version(device, setfile_name, buf, fsize);
+
+request_fw:
+ if (fw_requested) {
+ set_fs(old_fs);
+#endif
+
+ retry = 4;
+ ret = request_firmware((const struct firmware **)&fw_blob,
+ setfile_name, &device->pdev->dev);
+ while (--retry && ret) {
+ mwarn("request_firmware is fail(%d)", device, ret);
+ ret = request_firmware((const struct firmware **)&fw_blob,
+ setfile_name, &device->pdev->dev);
+ }
+
+ if (!retry) {
+ merr("request_firmware is fail(%d)", device, ret);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!fw_blob) {
+ merr("fw_blob is NULL", device);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!fw_blob->data) {
+ merr("fw_blob->data is NULL", device);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ address = (void *)(device->imemory.kvaddr + load_addr);
+ memcpy(address, fw_blob->data, fw_blob->size);
+ fimc_is_ischain_cache_flush(device, load_addr, fw_blob->size + 1);
+ fimc_is_ischain_version(device, setfile_name, fw_blob->data,
+ (u32)fw_blob->size);
+
+#ifdef SDCARD_FW
+ }
+#endif
+
+out:
+#ifdef SDCARD_FW
+#ifdef USE_ION_ALLOC
+ if (!IS_ERR_OR_NULL(buf)) {
+ ion_unmap_kernel(core->fimc_ion_client, handle);
+ }
+
+ if (!IS_ERR_OR_NULL(handle)) {
+ ion_free(core->fimc_ion_client, handle);
+ }
+#endif
+
+ if (!fw_requested) {
+#ifndef USE_ION_ALLOC
+ if (buf) {
+ vfree(buf);
+ }
+#endif
+ if (!IS_ERR_OR_NULL(fp)) {
+ filp_close(fp, current->files);
+ }
+ set_fs(old_fs);
+ } else
+#endif
+ {
+ if (!IS_ERR_OR_NULL(fw_blob)) {
+ release_firmware(fw_blob);
+ }
+ }
+
+ if (ret)
+ err("setfile loading is fail");
+ else
+ info("Camera: the %s Setfile were applied successfully.\n",
+ ((cam_id == CAMERA_SINGLE_REAR) &&
+ is_dumped_fw_loading_needed) ? "dumped" : "default");
+
+ return ret;
+}
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+static int fimc_is_ischain_loadcalb_eeprom(struct fimc_is_device_ischain *device,
+ struct fimc_is_module_enum *active_sensor, int id)
+ {
+ int ret = 0;
+#ifdef CONFIG_USE_VENDER_FEATURE
+ char *cal_ptr;
+ char *cal_buf = NULL;
+ u32 start_addr = 0;
+ int cal_size = 0;
+ struct fimc_is_from_info *finfo;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ start_addr = FIMC_IS_CAL_START_ADDR_FRONT;
+ cal_size = FIMC_IS_MAX_CAL_SIZE_FRONT;
+ fimc_is_sec_get_sysfs_finfo_front(&finfo);
+ fimc_is_sec_get_front_cal_buf(&cal_buf);
+ } else
+#endif
+ {
+ start_addr = FIMC_IS_CAL_START_ADDR;
+ cal_size = FIMC_IS_MAX_CAL_SIZE;
+ fimc_is_sec_get_sysfs_finfo(&finfo);
+ fimc_is_sec_get_cal_buf(&cal_buf);
+ }
+
+ cal_ptr = (char *)(device->imemory.kvaddr + start_addr);
+
+ info("CAL DATA : MAP ver : %c%c%c%c\n", cal_buf[0x30], cal_buf[0x31],
+ cal_buf[0x32], cal_buf[0x33]);
+
+ /* CRC check */
+ if (id == SENSOR_POSITION_FRONT) {
+ if (crc32_check_front == true) {
+ memcpy((void *)(cal_ptr) ,(void *)cal_buf, cal_size);
+ info("Front Camera : the dumped Cal. data was applied successfully.\n");
+ } else {
+ if (crc32_header_check_front == true) {
+ pr_err("Front Camera : CRC32 error but only header section is no problem.\n");
+ memset((void *)(cal_ptr + 0x1000), 0xFF, cal_size - 0x1000);
+ } else {
+ pr_err("Front Camera : CRC32 error for all section.\n");
+ memset((void *)(cal_ptr), 0xFF, cal_size);
+ ret = -EIO;
+ }
+ }
+ } else {
+ if (crc32_check == true) {
+ memcpy((void *)(cal_ptr) ,(void *)cal_buf, cal_size);
+ info("Rear Camera : the dumped Cal. data was applied successfully.\n");
+ } else {
+ if (crc32_header_check == true) {
+ pr_err("Rear Camera : CRC32 error but only header section is no problem.\n");
+ memset((void *)(cal_ptr + 0x1000), 0xFF, cal_size - 0x1000);
+ } else {
+ pr_err("Rear Camera : CRC32 error for all section.\n");
+ memset((void *)(cal_ptr), 0xFF, cal_size);
+ ret = -EIO;
+ }
+ }
+ }
+
+ fimc_is_ischain_cache_flush(device, start_addr, cal_size);
+ if (ret)
+ mwarn("calibration loading is fail", device);
+ else
+ mwarn("calibration loading is success", device);
+
+#endif
+ return ret;
+ }
+#endif
+
+#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+static int fimc_is_ischain_loadcalb(struct fimc_is_device_ischain *device,
+ struct fimc_is_module_enum *active_sensor)
+{
+ int ret = 0;
+#ifdef CONFIG_USE_VENDER_FEATURE
+ char *cal_ptr;
+ struct fimc_is_from_info *sysfs_finfo;
+ char *cal_buf;
+
+#ifdef CONFIG_COMPANION_USE
+ struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(device->pdev);
+#endif
+ mdbgd_ischain("%s\n", device, __func__);
+
+ cal_ptr = (char *)(device->imemory.kvaddr + FIMC_IS_CAL_START_ADDR);
+
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ fimc_is_sec_get_cal_buf(&cal_buf);
+
+ info("CAL DATA : MAP ver : %c%c%c%c\n", cal_buf[0x60], cal_buf[0x61],
+ cal_buf[0x62], cal_buf[0x63]);
+
+ /* CRC check */
+ if (crc32_check == true) {
+#ifdef CONFIG_COMPANION_USE
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ memcpy((void *)(cal_ptr) ,(void *)cal_buf, FIMC_IS_MAX_CAL_SIZE);
+ info("Camera : the dumped Cal. data was applied successfully.\n");
+ } else {
+ info("Camera : Did not load dumped Cal. Sensor version is lower than V004.\n");
+ }
+#else
+ memcpy((void *)(cal_ptr) ,(void *)cal_buf, FIMC_IS_MAX_CAL_SIZE);
+ info("Camera : the dumped Cal. data was applied successfully.\n");
+#endif
+ } else {
+ if (crc32_header_check == true) {
+ pr_err("Camera : CRC32 error but only header section is no problem.\n");
+ memset((void *)(cal_ptr + 0x1000), 0xFF, FIMC_IS_MAX_CAL_SIZE - 0x1000);
+ } else {
+ pr_err("Camera : CRC32 error for all section.\n");
+ memset((void *)(cal_ptr), 0xFF, FIMC_IS_MAX_CAL_SIZE);
+ ret = -EIO;
+ }
+ }
+
+ fimc_is_ischain_cache_flush(device, FIMC_IS_CAL_START_ADDR,
+ FIMC_IS_MAX_CAL_SIZE);
+ if (ret)
+ mwarn("calibration loading is fail", device);
+ else
+ mwarn("calibration loading is success", device);
+#endif
+ return ret;
+}
+#endif
+static void fimc_is_ischain_forcedown(struct fimc_is_device_ischain *this,
+ bool on)
+{
+ if (on) {
+ printk(KERN_INFO "Set low poweroff mode\n");
+ __raw_writel(0x0, PMUREG_ISP_ARM_OPTION);
+ __raw_writel(0x1CF82000, PMUREG_ISP_LOW_POWER_OFF);
+ this->force_down = true;
+ } else {
+ printk(KERN_INFO "Clear low poweroff mode\n");
+ __raw_writel(0xFFFFFFFF, PMUREG_ISP_ARM_OPTION);
+ __raw_writel(0x8, PMUREG_ISP_LOW_POWER_OFF);
+ this->force_down = false;
+ }
+}
+
+#if !defined(CONFIG_SOC_EXYNOS4415)
+void tdnr_s3d_pixel_async_sw_reset(struct fimc_is_device_ischain *this)
+{
+ u32 cfg = readl(SYSREG_GSCBLK_CFG1);
+ /* S3D pixel async sw reset */
+ cfg &= ~(1 << 25);
+ writel(cfg, SYSREG_GSCBLK_CFG1);
+
+ cfg = readl(SYSREG_ISPBLK_CFG);
+ /* 3DNR pixel async sw reset */
+ cfg &= ~(1 << 5);
+ writel(cfg, SYSREG_ISPBLK_CFG);
+}
+#endif
+
+static void fimc_is_a5_power(struct device *dev, int power_flags)
+{
+ u32 timeout;
+
+ /* configuration */
+ __raw_writel(power_flags, PMUREG_ISP_ARM_CONFIGURATION);
+
+ /* option */
+ if (power_flags) {
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ /* A5 enable[15] */
+ writel((1 << 15), PMUREG_ISP_ARM_OPTION);
+#else
+ /* STANDBY WFI[16] & A5 enable[15] */
+ writel((1 << 16 | 1 << 15), PMUREG_ISP_ARM_OPTION);
+#endif
+ }
+
+ /* status */
+ timeout = 1000;
+ while ((__raw_readl(PMUREG_ISP_ARM_STATUS) & 0x1) != power_flags) {
+ if (timeout == 0)
+ err("%s can't control power(%d), timeout\n", __func__, power_flags);
+ timeout--;
+ udelay(1);
+ }
+}
+
+int fimc_is_ischain_power(struct fimc_is_device_ischain *device, int on)
+{
+#ifdef CONFIG_ARM_TRUSTZONE
+ int i;
+#endif
+ int ret = 0;
+ u32 debug;
+#if defined(CONFIG_PM_RUNTIME)
+ int rpm_ret;
+#endif
+ u32 val;
+ char setf_name[100];
+
+ struct device *dev = &device->pdev->dev;
+ struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(device->pdev);
+ struct fimc_is_from_info *sysfs_finfo;
+
+ if (on) {
+ /* 1. force poweroff setting */
+ if (device->force_down)
+ fimc_is_ischain_forcedown(device, false);
+
+ /* 2. FIMC-IS local power enable */
+#if defined(CONFIG_PM_RUNTIME)
+ mdbgd_ischain("pm_runtime_suspended = %d\n", device, pm_runtime_suspended(dev));
+ rpm_ret = pm_runtime_get_sync(dev);
+ if (rpm_ret < 0)
+ err("pm_runtime_get_sync() return error: %d", rpm_ret);
+#else
+ fimc_is_runtime_resume(dev);
+ info("%s(%d) - fimc_is runtime resume complete\n", __func__, on);
+#endif
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (core->id == SENSOR_POSITION_FRONT) {
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ if (!sysfs_finfo->is_caldata_read) {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ ret = fimc_is_sec_fw_sel_eeprom(dev, fw_name, setf_name, SENSOR_POSITION_REAR, true);
+#else
+ ret = fimc_is_sec_fw_sel(core, dev, fw_name, setf_name, true);
+#endif
+ } else {
+ snprintf(fw_name, sizeof(fw_name), "%s", sysfs_finfo->load_fw_name);
+ }
+ fimc_is_sec_get_sysfs_finfo_front(&sysfs_finfo);
+ if (!sysfs_finfo->is_caldata_read) {
+ ret = fimc_is_sec_fw_sel_eeprom(dev, fw_name, setf_name, SENSOR_POSITION_FRONT, false);
+ if (ret < 0) {
+ err("failed to select firmware (%d)", ret);
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &device->state);
+ goto p_err_pm;
+ }
+ }
+ } else
+#endif
+ {
+ fimc_is_sec_get_sysfs_finfo(&sysfs_finfo);
+ if (!sysfs_finfo->is_caldata_read) {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ ret = fimc_is_sec_fw_sel_eeprom(dev, fw_name, setf_name, SENSOR_POSITION_REAR, false);
+#else
+ ret = fimc_is_sec_fw_sel(core, dev, fw_name, setf_name, false);
+#endif
+ if (ret < 0) {
+ err("failed to select firmware (%d)", ret);
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &device->state);
+ goto p_err_pm;
+ }
+ } else {
+ snprintf(fw_name, sizeof(fw_name), "%s", sysfs_finfo->load_fw_name);
+ }
+ }
+
+#ifdef CONFIG_COMPANION_USE
+// ret = fimc_is_sec_concord_fw_sel(core, dev, device->pdata, companion_fw_name, master_setf_name, mode_setf_name);
+ /*if (ret < 0) {
+ err("failed to select companion firmware (%d)", ret);
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &device->state);
+ goto exit;
+ }*/
+#endif
+ /* 3. Load IS firmware */
+ ret = fimc_is_ischain_loadfirm(device);
+ if (ret) {
+ err("failed to fimc_is_request_firmware (%d)", ret);
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &device->state);
+ ret = -EINVAL;
+ goto p_err_pm;
+ }
+ set_bit(FIMC_IS_ISCHAIN_LOADED, &device->state);
+
+#if defined(CONFIG_SOC_EXYNOS5422)
+ tdnr_s3d_pixel_async_sw_reset(device);
+#endif /* defined(CONFIG_SOC_EXYNOS5422) */
+ /* 4. A5 start address setting */
+ mdbgd_ischain("imemory.base(dvaddr) : 0x%08x\n", device, device->imemory.dvaddr);
+ mdbgd_ischain("imemory.base(kvaddr) : 0x%08X\n", device, device->imemory.kvaddr);
+
+ if (!device->imemory.dvaddr) {
+ merr("firmware device virtual is null", device);
+ ret = -ENOMEM;
+ goto p_err_pm;
+ }
+
+ writel(device->imemory.dvaddr, device->regs + BBOAR);
+ val = __raw_readl(device->regs + BBOAR);
+ if(device->imemory.dvaddr != val)
+ err("dvaddr : %x , BBOAR : %x", device->imemory.dvaddr,val);
+
+#ifdef CONFIG_ARM_TRUSTZONE
+ exynos_smc(SMC_CMD_REG, SMC_REG_ID_SFR_W(PA_FIMC_IS_GIC_C + 0x4), 0x000000FF, 0);
+ for (i = 0; i < 3; i++)
+ exynos_smc(SMC_CMD_REG, SMC_REG_ID_SFR_W(PA_FIMC_IS_GIC_D + 0x80 + (i * 4)), 0xFFFFFFFF, 0);
+ for (i = 0; i < 18; i++)
+ exynos_smc(SMC_CMD_REG, SMC_REG_ID_SFR_W(PA_FIMC_IS_GIC_D + 0x400 + (i * 4)), 0x10101010, 0);
+
+ exynos_smc_readsfr(PA_FIMC_IS_GIC_C + 0x4, &debug);
+ info("%s : PA_FIMC_IS_GIC_C : 0x%08x\n", __func__, debug);
+ if (debug == 0x00)
+ merr("secure configuration is fail[0x131E0004:%08X]", device, debug);
+#endif
+
+ /* To guarantee FW restart */
+ if (__raw_readl(PMUREG_ISP_ARM_STATUS) & 0x1) {
+ fimc_is_a5_power(dev, 0);
+ }
+
+ /* 5. A5 power on*/
+ fimc_is_a5_power(dev, 1);
+
+ set_bit(FIMC_IS_ISCHAIN_POWER_ON, &device->state);
+
+ /* for mideaserver force down */
+ set_bit(FIMC_IS_ISCHAIN_POWER_ON, &core->state);
+ } else {
+ /* Check FW state for WFI of A5 */
+ debug = readl(device->interface->regs + ISSR6);
+ printk(KERN_INFO "%s: A5 state(0x%x)\n", __func__, debug);
+
+ /* FIMC-IS local power down */
+#if defined(CONFIG_PM_RUNTIME)
+ rpm_ret = pm_runtime_put_sync(dev);
+ if (rpm_ret < 0)
+ err("pm_runtime_put_sync() return error: %d", rpm_ret);
+ mdbgd_ischain("pm_runtime_suspended = %d\n", device, pm_runtime_suspended(dev));
+
+ if (!pm_runtime_suspended(dev)) {
+ err("failed to call RPM device callback, try A5 power down manually\n");
+
+ fimc_is_a5_power(dev, 0);
+ }
+#else
+ fimc_is_a5_power(dev, 0);
+
+ fimc_is_runtime_suspend(dev);
+#endif
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &device->state);
+
+ /* for mideaserver force down */
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &core->state);
+ }
+
+ info("%s(%d)\n", __func__, test_bit(FIMC_IS_ISCHAIN_POWER_ON, &device->state));
+ return ret;
+
+p_err_pm:
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(dev);
+#else
+ fimc_is_runtime_suspend(dev);
+#endif
+
+ return ret;
+}
+
+static int fimc_is_itf_s_param(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ u32 lindex,
+ u32 hindex,
+ u32 indexes)
+{
+ int ret = 0;
+ u32 flag, index;
+ u32 dst_base, src_base;
+
+ BUG_ON(!device);
+
+ if (frame) {
+ if (!test_bit(FIMC_IS_ISHCAIN_START, &device->state)) {
+ merr("s_param is fail, device already is stopped", device);
+ BUG();
+ }
+
+ dst_base = (u32)&device->is_region->parameter;
+ src_base = (u32)frame->shot->ctl.entry.parameter;
+
+ for (index = 0; lindex && (index < 32); index++) {
+ flag = 1 << index;
+ if (lindex & flag) {
+ memcpy((u32 *)(dst_base + (index * PARAMETER_MAX_SIZE)),
+ (u32 *)(src_base + (index * PARAMETER_MAX_SIZE)),
+ PARAMETER_MAX_SIZE);
+ lindex &= ~flag;
+ }
+ }
+
+ for (index = 0; hindex && (index < 32); index++) {
+ flag = 1 << index;
+ if (hindex & flag) {
+ memcpy((u32 *)(dst_base + ((32 + index) * PARAMETER_MAX_SIZE)),
+ (u32 *)(src_base + ((32 + index) * PARAMETER_MAX_SIZE)),
+ PARAMETER_MAX_SIZE);
+ hindex &= ~flag;
+ }
+ }
+
+ fimc_is_ischain_region_flush(device);
+ } else {
+ /*
+ * this check code is commented until per-frame control is worked fully
+ *
+ * if ( test_bit(FIMC_IS_ISHCAIN_START, &device->state)) {
+ * merr("s_param is fail, device already is started", device);
+ * BUG();
+ * }
+ */
+
+ fimc_is_ischain_region_flush(device);
+
+ if (lindex || hindex) {
+ ret = fimc_is_hw_s_param(device->interface,
+ device->instance,
+ lindex,
+ hindex,
+ indexes);
+ }
+ }
+
+ return ret;
+}
+
+static void * fimc_is_itf_g_param(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ u32 index)
+{
+ u32 dst_base, src_base, dst_param, src_param;
+
+ BUG_ON(!device);
+
+ if (frame) {
+ if (!test_bit(FIMC_IS_ISHCAIN_START, &device->state)) {
+ merr("s_param is fail, device already is stopped", device);
+ BUG();
+ }
+
+ dst_base = (u32)&frame->shot->ctl.entry.parameter[0];
+ dst_param = (dst_base + (index * PARAMETER_MAX_SIZE));
+ src_base = (u32)&device->is_region->parameter;
+ src_param = (src_base + (index * PARAMETER_MAX_SIZE));
+ memcpy((u32 *)dst_param, (u32 *)src_param, PARAMETER_MAX_SIZE);
+ } else {
+ dst_base = (u32)&device->is_region->parameter;
+ dst_param = (dst_base + (index * PARAMETER_MAX_SIZE));
+ }
+
+ return (void *)dst_param;
+}
+
+static int fimc_is_itf_a_param(struct fimc_is_device_ischain *device,
+ u32 group)
+{
+ int ret = 0;
+
+ BUG_ON(!device);
+
+ if (device->setfile >= ISS_SUB_END) {
+ mwarn("setfile id(%d) is invalid", device, device->setfile);
+ device->setfile = ISS_SUB_SCENARIO_STILL_PREVIEW;
+ }
+
+ ret = fimc_is_hw_a_param(device->interface,
+ device->instance,
+ group,
+ device->setfile);
+
+ return ret;
+}
+
+static int fimc_is_itf_f_param(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ u32 group = 0;
+#ifdef DEBUG
+ u32 navailable = 0;
+ struct is_region *region = device->is_region;
+#endif
+
+ mdbgd_ischain(" NAME SIZE BINNING FRAMERATE\n", device);
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state) ||
+ !IS_ISCHAIN_OTF(device))
+ mdbgd_ischain("SENSOR : %04dx%04d %1dx%1d %3d\n",
+ device,
+ region->parameter.taa.vdma1_input.width + device->margin_width,
+ region->parameter.taa.vdma1_input.height + device->margin_height,
+ (region->parameter.taa.vdma1_input.sensor_binning_ratio_x / 1000),
+ (region->parameter.taa.vdma1_input.sensor_binning_ratio_y / 1000),
+ region->parameter.sensor.config.framerate
+ );
+ else
+ mdbgd_ischain("SENSOR : %04dx%04d %1dx%1d %3d\n",
+ device,
+ region->parameter.sensor.dma_output.width,
+ region->parameter.sensor.dma_output.height,
+ (region->parameter.taa.otf_input.sensor_binning_ratio_x / 1000),
+ (region->parameter.taa.otf_input.sensor_binning_ratio_y / 1000),
+ region->parameter.sensor.config.framerate
+ );
+ mdbgd_ischain(" NAME ON BYPASS PATH SIZE FORMAT\n", device);
+ mdbgd_ischain("3AX OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.taa.control.cmd,
+ region->parameter.taa.control.bypass,
+ region->parameter.taa.otf_input.cmd,
+ region->parameter.taa.otf_input.width,
+ region->parameter.taa.otf_input.height,
+ region->parameter.taa.otf_input.format
+ );
+ mdbgd_ischain("3AX DI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.taa.control.cmd,
+ region->parameter.taa.control.bypass,
+ region->parameter.taa.vdma1_input.cmd,
+ region->parameter.taa.vdma1_input.width,
+ region->parameter.taa.vdma1_input.height,
+ region->parameter.taa.vdma1_input.format
+ );
+ mdbgd_ischain("3AX DO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.taa.control.cmd,
+ region->parameter.taa.control.bypass,
+ region->parameter.taa.vdma2_output.cmd,
+ region->parameter.taa.vdma2_output.width,
+ region->parameter.taa.vdma2_output.height,
+ region->parameter.taa.vdma2_output.format
+ );
+ mdbgd_ischain("ISP OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.isp.control.cmd,
+ region->parameter.isp.control.bypass,
+ region->parameter.isp.otf_input.cmd,
+ region->parameter.isp.otf_input.width,
+ region->parameter.isp.otf_input.height,
+ region->parameter.isp.otf_input.format
+ );
+ mdbgd_ischain("ISP DI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.isp.control.cmd,
+ region->parameter.isp.control.bypass,
+ region->parameter.isp.vdma1_input.cmd,
+ region->parameter.isp.vdma1_input.width,
+ region->parameter.isp.vdma1_input.height,
+ region->parameter.isp.vdma1_input.format
+ );
+ mdbgd_ischain("ISP OO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.isp.control.cmd,
+ region->parameter.isp.control.bypass,
+ region->parameter.isp.otf_output.cmd,
+ region->parameter.isp.otf_output.width,
+ region->parameter.isp.otf_output.height,
+ region->parameter.isp.otf_output.format
+ );
+ mdbgd_ischain("DRC OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.drc.control.cmd,
+ region->parameter.drc.control.bypass,
+ region->parameter.drc.otf_input.cmd,
+ region->parameter.drc.otf_input.width,
+ region->parameter.drc.otf_input.height,
+ region->parameter.drc.otf_input.format
+ );
+ mdbgd_ischain("DRC OO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.drc.control.cmd,
+ region->parameter.drc.control.bypass,
+ region->parameter.drc.otf_output.cmd,
+ region->parameter.drc.otf_output.width,
+ region->parameter.drc.otf_output.height,
+ region->parameter.drc.otf_output.format
+ );
+ mdbgd_ischain("SCC OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.scalerc.control.cmd,
+ region->parameter.scalerc.control.bypass,
+ region->parameter.scalerc.otf_input.cmd,
+ region->parameter.scalerc.otf_input.width,
+ region->parameter.scalerc.otf_input.height,
+ region->parameter.scalerc.otf_input.format
+ );
+ mdbgd_ischain("SCC DO : %2d %4d %3d %04dx%04d %4d,%d\n", device,
+ region->parameter.scalerc.control.cmd,
+ region->parameter.scalerc.control.bypass,
+ region->parameter.scalerc.dma_output.cmd,
+ region->parameter.scalerc.dma_output.width,
+ region->parameter.scalerc.dma_output.height,
+ region->parameter.scalerc.dma_output.format,
+ region->parameter.scalerc.dma_output.plane
+ );
+ mdbgd_ischain("SCC OO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.scalerc.control.cmd,
+ region->parameter.scalerc.control.bypass,
+ region->parameter.scalerc.otf_output.cmd,
+ region->parameter.scalerc.otf_output.width,
+ region->parameter.scalerc.otf_output.height,
+ region->parameter.scalerc.otf_output.format
+ );
+ mdbgd_ischain("ODC OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.odc.control.cmd,
+ region->parameter.odc.control.bypass,
+ region->parameter.odc.otf_input.cmd,
+ region->parameter.odc.otf_input.width,
+ region->parameter.odc.otf_input.height,
+ region->parameter.odc.otf_input.format
+ );
+ mdbgd_ischain("ODC OO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.odc.control.cmd,
+ region->parameter.odc.control.bypass,
+ region->parameter.odc.otf_output.cmd,
+ region->parameter.odc.otf_output.width,
+ region->parameter.odc.otf_output.height,
+ region->parameter.odc.otf_output.format
+ );
+ mdbgd_ischain("DIS OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.dis.control.cmd,
+ region->parameter.dis.control.bypass,
+ region->parameter.dis.otf_input.cmd,
+ region->parameter.dis.otf_input.width,
+ region->parameter.dis.otf_input.height,
+ region->parameter.dis.otf_input.format
+ );
+ mdbgd_ischain("DIS OO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.dis.control.cmd,
+ region->parameter.dis.control.bypass,
+ region->parameter.dis.otf_output.cmd,
+ region->parameter.dis.otf_output.width,
+ region->parameter.dis.otf_output.height,
+ region->parameter.dis.otf_output.format
+ );
+ mdbgd_ischain("DNR OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.tdnr.control.cmd,
+ region->parameter.tdnr.control.bypass,
+ region->parameter.tdnr.otf_input.cmd,
+ region->parameter.tdnr.otf_input.width,
+ region->parameter.tdnr.otf_input.height,
+ region->parameter.tdnr.otf_input.format
+ );
+ mdbgd_ischain("DNR OO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.tdnr.control.cmd,
+ region->parameter.tdnr.control.bypass,
+ region->parameter.tdnr.otf_output.cmd,
+ region->parameter.tdnr.otf_output.width,
+ region->parameter.tdnr.otf_output.height,
+ region->parameter.tdnr.otf_output.format
+ );
+ mdbgd_ischain("SCP OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.scalerp.control.cmd,
+ region->parameter.scalerp.control.bypass,
+ region->parameter.scalerp.otf_input.cmd,
+ region->parameter.scalerp.otf_input.width,
+ region->parameter.scalerp.otf_input.height,
+ region->parameter.scalerp.otf_input.format
+ );
+ mdbgd_ischain("SCP DO : %2d %4d %3d %04dx%04d %4d,%d\n", device,
+ region->parameter.scalerp.control.cmd,
+ region->parameter.scalerp.control.bypass,
+ region->parameter.scalerp.dma_output.cmd,
+ region->parameter.scalerp.dma_output.width,
+ region->parameter.scalerp.dma_output.height,
+ region->parameter.scalerp.dma_output.format,
+ region->parameter.scalerp.dma_output.plane
+ );
+ mdbgd_ischain("SCP OO : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.scalerp.control.cmd,
+ region->parameter.scalerp.control.bypass,
+ region->parameter.scalerp.otf_output.cmd,
+ region->parameter.scalerp.otf_output.width,
+ region->parameter.scalerp.otf_output.height,
+ region->parameter.scalerp.otf_output.format
+ );
+ mdbgd_ischain("FD OI : %2d %4d %3d %04dx%04d %3d\n", device,
+ region->parameter.fd.control.cmd,
+ region->parameter.fd.control.bypass,
+ region->parameter.fd.otf_input.cmd,
+ region->parameter.fd.otf_input.width,
+ region->parameter.fd.otf_input.height,
+ region->parameter.fd.otf_input.format
+ );
+ mdbgd_ischain(" NAME CMD IN_SZIE OT_SIZE CROP POS\n", device);
+ mdbgd_ischain("SCC CI : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n", device,
+ region->parameter.scalerc.input_crop.cmd,
+ region->parameter.scalerc.input_crop.in_width,
+ region->parameter.scalerc.input_crop.in_height,
+ region->parameter.scalerc.input_crop.out_width,
+ region->parameter.scalerc.input_crop.out_height,
+ region->parameter.scalerc.input_crop.crop_width,
+ region->parameter.scalerc.input_crop.crop_height,
+ region->parameter.scalerc.input_crop.pos_x,
+ region->parameter.scalerc.input_crop.pos_y
+ );
+ mdbgd_ischain("SCC CO : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n", device,
+ region->parameter.scalerc.output_crop.cmd,
+ navailable,
+ navailable,
+ navailable,
+ navailable,
+ region->parameter.scalerc.output_crop.crop_width,
+ region->parameter.scalerc.output_crop.crop_height,
+ region->parameter.scalerc.output_crop.pos_x,
+ region->parameter.scalerc.output_crop.pos_y
+ );
+ mdbgd_ischain("SCP CI : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n", device,
+ region->parameter.scalerp.input_crop.cmd,
+ region->parameter.scalerp.input_crop.in_width,
+ region->parameter.scalerp.input_crop.in_height,
+ region->parameter.scalerp.input_crop.out_width,
+ region->parameter.scalerp.input_crop.out_height,
+ region->parameter.scalerp.input_crop.crop_width,
+ region->parameter.scalerp.input_crop.crop_height,
+ region->parameter.scalerp.input_crop.pos_x,
+ region->parameter.scalerp.input_crop.pos_y
+ );
+ mdbgd_ischain("SCP CO : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n", device,
+ region->parameter.scalerp.output_crop.cmd,
+ navailable,
+ navailable,
+ navailable,
+ navailable,
+ region->parameter.scalerp.output_crop.crop_width,
+ region->parameter.scalerp.output_crop.crop_height,
+ region->parameter.scalerp.output_crop.pos_x,
+ region->parameter.scalerp.output_crop.pos_y
+ );
+
+ group |= GROUP_ID(device->group_3aa.id);
+ group |= GROUP_ID(device->group_isp.id);
+
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group = GROUP_ID(GROUP_ID_3A0);
+
+ if (device->setfile >= ISS_SUB_END) {
+ mwarn("setfile id(%d) is invalid", device, device->setfile);
+ device->setfile = ISS_SUB_SCENARIO_STILL_PREVIEW;
+ }
+
+ ret = fimc_is_hw_a_param(device->interface,
+ device->instance,
+ (group & GROUP_ID_PARM_MASK),
+ device->setfile);
+ return ret;
+}
+
+static int fimc_is_itf_enum(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+
+ mdbgd_ischain("%s()\n", device, __func__);
+
+ ret = fimc_is_hw_enum(device->interface);
+ if (ret) {
+ merr("fimc_is_itf_enum is fail(%d)", device, ret);
+ CALL_POPS(device, print_pwr, device->pdev);
+ CALL_POPS(device, print_clk, device->pdev);
+ }
+
+ return ret;
+}
+
+static int fimc_is_itf_open(struct fimc_is_device_ischain *device,
+ u32 module_id,
+ u32 group_id,
+ u32 flag,
+ struct sensor_open_extended *ext_info)
+{
+ int ret = 0;
+ struct is_region *region;
+ struct fimc_is_interface *itf;
+
+ BUG_ON(!device);
+ BUG_ON(!device->is_region);
+ BUG_ON(!device->sensor);
+ BUG_ON(!device->interface);
+ BUG_ON(!ext_info);
+
+ region = device->is_region;
+ itf = device->interface;
+
+ memcpy(®ion->shared[0], ext_info, sizeof(struct sensor_open_extended));
+
+ fimc_is_ischain_region_flush(device);
+
+ ret = fimc_is_hw_open(device->interface,
+ device->instance,
+ module_id,
+ device->imemory.dvaddr_shared,
+ group_id,
+ flag,
+ &device->margin_width,
+ &device->margin_height);
+ if (ret) {
+ merr("fimc_is_hw_open is fail", device);
+ CALL_POPS(device, print_cfg, device->pdev,
+ fimc_is_sensor_g_instance(device->sensor));
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* HACK */
+ device->margin_left = 8;
+ device->margin_right = 8;
+ device->margin_top = 6;
+ device->margin_bottom = 4;
+ device->margin_width = device->margin_left + device->margin_right;
+ device->margin_height = device->margin_top + device->margin_bottom;
+ mdbgd_ischain("margin %dx%d\n", device,
+ device->margin_width, device->margin_height);
+
+ fimc_is_ischain_region_invalid(device);
+
+ if (region->shared[MAX_SHARED_COUNT-1] != MAGIC_NUMBER) {
+ merr("MAGIC NUMBER error", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ memset(®ion->parameter, 0x0, sizeof(struct is_param_region));
+
+ memcpy(®ion->parameter.sensor, &init_sensor_param,
+ sizeof(struct sensor_param));
+ memcpy(®ion->parameter.taa, &init_taa_param,
+ sizeof(struct taa_param));
+ memcpy(®ion->parameter.isp, &init_isp_param,
+ sizeof(struct isp_param));
+ memcpy(®ion->parameter.drc, &init_drc_param,
+ sizeof(struct drc_param));
+ memcpy(®ion->parameter.scalerc, &init_scalerc_param,
+ sizeof(struct scalerc_param));
+ memcpy(®ion->parameter.odc, &init_odc_param,
+ sizeof(struct odc_param));
+ memcpy(®ion->parameter.dis, &init_dis_param,
+ sizeof(struct dis_param));
+ memcpy(®ion->parameter.tdnr, &init_tdnr_param,
+ sizeof(struct tdnr_param));
+ memcpy(®ion->parameter.scalerp, &init_scalerp_param,
+ sizeof(struct scalerp_param));
+ memcpy(®ion->parameter.fd, &init_fd_param,
+ sizeof(struct fd_param));
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_itf_close(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ struct fimc_is_interface *itf;
+
+ BUG_ON(!device);
+ BUG_ON(!device->interface);
+
+ itf = device->interface;
+
+ ret = fimc_is_hw_close(itf, device->instance);
+ if (ret) {
+ merr("fimc_is_hw_close is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_itf_setfile(struct fimc_is_device_ischain *device,
+ char *setfile_name)
+{
+ int ret = 0;
+ u32 setfile_addr = 0;
+ struct fimc_is_interface *itf;
+
+ BUG_ON(!device);
+ BUG_ON(!device->interface);
+ BUG_ON(!setfile_name);
+
+ itf = device->interface;
+
+ mdbgd_ischain("%s(setfile : %s)\n", device, __func__, setfile_name);
+
+ ret = fimc_is_hw_saddr(itf, device->instance, &setfile_addr);
+ if (ret) {
+ merr("fimc_is_hw_saddr is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ if (!setfile_addr) {
+ merr("setfile address is NULL", device);
+ pr_err("cmd : %08X\n", readl(&itf->com_regs->ihcmd));
+ pr_err("id : %08X\n", readl(&itf->com_regs->ihc_sensorid));
+ pr_err("param1 : %08X\n", readl(&itf->com_regs->ihc_param1));
+ pr_err("param2 : %08X\n", readl(&itf->com_regs->ihc_param2));
+ pr_err("param3 : %08X\n", readl(&itf->com_regs->ihc_param3));
+ pr_err("param4 : %08X\n", readl(&itf->com_regs->ihc_param4));
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_loadsetf(device, setfile_addr, setfile_name);
+ if (ret) {
+ merr("fimc_is_ischain_loadsetf is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_hw_setfile(itf, device->instance);
+ if (ret) {
+ merr("fimc_is_hw_setfile is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_itf_map(struct fimc_is_device_ischain *device,
+ u32 group, u32 shot_addr, u32 shot_size)
+{
+ int ret = 0;
+
+ BUG_ON(!device);
+
+ mdbgd_ischain("%s()\n", device, __func__);
+
+ ret = fimc_is_hw_map(device->interface, device->instance, group, shot_addr, shot_size);
+ if (ret)
+ merr("fimc_is_hw_map is fail(%d)", device, ret);
+
+ return ret;
+}
+
+static int fimc_is_itf_unmap(struct fimc_is_device_ischain *device,
+ u32 group)
+{
+ int ret = 0;
+
+ mdbgd_ischain("%s()\n", device, __func__);
+
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group = GROUP_ID(GROUP_ID_3A0);
+
+ ret = fimc_is_hw_unmap(device->interface, device->instance, group);
+ if (ret)
+ merr("fimc_is_hw_unmap is fail(%d)", device, ret);
+
+ return ret;
+}
+
+int fimc_is_itf_stream_on(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ u32 retry = 10000;
+#ifdef ENABLE_DVFS
+ int scenario_id;
+#endif
+ struct fimc_is_group *group_3aa, *group_isp;
+ struct fimc_is_resourcemgr *resourcemgr;
+
+ BUG_ON(!device);
+ BUG_ON(!device->resourcemgr);
+
+ resourcemgr = device->resourcemgr;
+ group_3aa = &device->group_3aa;
+ group_isp = &device->group_isp;
+
+ /* 3ax, isp group should be started */
+ if (!test_bit(FIMC_IS_GROUP_READY, &group_3aa->state)) {
+ merr("group isp is not start", device);
+ goto p_err;
+ }
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) ||
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1)) {
+ if (!test_bit(FIMC_IS_GROUP_READY, &group_3aa->state)) {
+ merr("group 3ax is not start", device);
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group_3aa->state)) {
+ while (--retry && (atomic_read(&group_3aa->scount) <
+ group_3aa->async_shots)) {
+ udelay(100);
+ }
+ }
+ }
+
+ if (retry)
+ info("[ISC:D:%d] stream on ready\n", device->instance);
+ else
+ pr_err("[ISC:D:%d] stream on NOT ready\n", device->instance);
+
+#ifdef ENABLE_DVFS
+ mutex_lock(&resourcemgr->dvfs_ctrl.lock);
+ if ((!pm_qos_request_active(&device->user_qos)) &&
+ (sysfs_debug.en_dvfs)) {
+ /* try to find dynamic scenario to apply */
+ scenario_id = fimc_is_dvfs_sel_scenario(FIMC_IS_STATIC_SN, device, NULL);
+ if (scenario_id >= 0) {
+ struct fimc_is_dvfs_scenario_ctrl *static_ctrl =
+ resourcemgr->dvfs_ctrl.static_ctrl;
+ info("[ISC:D:%d] static scenario(%d)-[%s]\n",
+ device->instance, scenario_id,
+ static_ctrl->scenarios[static_ctrl->cur_scenario_idx].scenario_nm);
+ fimc_is_set_dvfs(device, scenario_id);
+ }
+ }
+ mutex_unlock(&resourcemgr->dvfs_ctrl.lock);
+#endif
+ ret = fimc_is_hw_stream_on(device->interface, device->instance);
+ if (ret) {
+ merr("fimc_is_hw_stream_on is fail(%d)", device, ret);
+ CALL_POPS(device, print_clk, device->pdev);
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_itf_stream_off(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+
+ info("[ISC:D:%d] stream off ready\n", device->instance);
+
+ ret = fimc_is_hw_stream_off(device->interface, device->instance);
+
+ return ret;
+}
+
+int fimc_is_itf_process_start(struct fimc_is_device_ischain *device,
+ u32 group)
+{
+ int ret = 0;
+
+ ret = fimc_is_hw_process_on(device->interface,
+ device->instance, group);
+
+ return ret;
+}
+
+int fimc_is_itf_process_stop(struct fimc_is_device_ischain *device,
+ u32 group)
+{
+ int ret = 0;
+
+#ifdef ENABLE_CLOCK_GATE
+ struct fimc_is_core *core = (struct fimc_is_core *)device->interface->core;
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST) {
+ fimc_is_clk_gate_lock_set(core, device->instance, true);
+ fimc_is_wrap_clk_gate_set(core, (1 << GROUP_ID_MAX) - 1, true);
+ }
+#endif
+ ret = fimc_is_hw_process_off(device->interface,
+ device->instance, group, 0);
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_lock_set(core, device->instance, false);
+#endif
+ return ret;
+}
+
+int fimc_is_itf_force_stop(struct fimc_is_device_ischain *device,
+ u32 group)
+{
+ int ret = 0;
+
+#ifdef ENABLE_CLOCK_GATE
+ struct fimc_is_core *core = (struct fimc_is_core *)device->interface->core;
+#endif
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group = GROUP_ID(GROUP_ID_3A0);
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST) {
+ fimc_is_clk_gate_lock_set(core, device->instance, true);
+ fimc_is_wrap_clk_gate_set(core, (1 << GROUP_ID_MAX) - 1, true);
+ }
+#endif
+ ret = fimc_is_hw_process_off(device->interface,
+ device->instance, group, 1);
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_lock_set(core, device->instance, false);
+#endif
+ return ret;
+}
+
+static int fimc_is_itf_init_process_start(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ u32 group = 0;
+
+ group |= GROUP_ID(device->group_3aa.id);
+ group |= GROUP_ID(device->group_isp.id);
+
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group = GROUP_ID(GROUP_ID_3A0);
+
+ ret = fimc_is_hw_process_on(device->interface,
+ device->instance,
+ (group & GROUP_ID_PARM_MASK));
+
+ return ret;
+}
+
+static int fimc_is_itf_init_process_stop(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ u32 group = 0;
+
+#ifdef ENABLE_CLOCK_GATE
+ struct fimc_is_core *core = (struct fimc_is_core *)device->interface->core;
+#endif
+ group |= GROUP_ID(device->group_3aa.id);
+ group |= GROUP_ID(device->group_isp.id);
+
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group = GROUP_ID(GROUP_ID_3A0);
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST) {
+ fimc_is_clk_gate_lock_set(core, device->instance, true);
+ fimc_is_wrap_clk_gate_set(core, (1 << GROUP_ID_MAX) - 1, true);
+
+ }
+#endif
+ ret = fimc_is_hw_process_off(device->interface,
+ device->instance, (group & GROUP_ID_PARM_MASK), 0);
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_lock_set(core, device->instance, false);
+#endif
+ return ret;
+}
+
+int fimc_is_itf_i2c_lock(struct fimc_is_device_ischain *this,
+ int i2c_clk, bool lock)
+{
+ int ret = 0;
+ struct fimc_is_interface *itf = this->interface;
+
+ if (lock)
+ fimc_is_interface_lock(itf);
+
+ ret = fimc_is_hw_i2c_lock(itf, this->instance,
+ i2c_clk, lock);
+
+ if (!lock)
+ fimc_is_interface_unlock(itf);
+
+ return ret;
+}
+
+int fimc_is_itf_g_capability(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+#ifdef PRINT_CAPABILITY
+ u32 metadata;
+ u32 index;
+ struct camera2_sm *capability;
+#endif
+
+ ret = fimc_is_hw_g_capability(this->interface, this->instance,
+ (this->imemory.kvaddr_shared - this->imemory.kvaddr));
+
+ fimc_is_ischain_region_invalid(this);
+
+#ifdef PRINT_CAPABILITY
+ memcpy(&this->capability, &this->is_region->shared,
+ sizeof(struct camera2_sm));
+ capability = &this->capability;
+
+ printk(KERN_INFO "===ColorC================================\n");
+ printk(KERN_INFO "===ToneMapping===========================\n");
+ metadata = capability->tonemap.maxCurvePoints;
+ printk(KERN_INFO "maxCurvePoints : %d\n", metadata);
+
+ printk(KERN_INFO "===Scaler================================\n");
+ printk(KERN_INFO "foramt : %d, %d, %d, %d\n",
+ capability->scaler.availableFormats[0],
+ capability->scaler.availableFormats[1],
+ capability->scaler.availableFormats[2],
+ capability->scaler.availableFormats[3]);
+
+ printk(KERN_INFO "===StatisTicsG===========================\n");
+ index = 0;
+ metadata = capability->stats.availableFaceDetectModes[index];
+ while (metadata) {
+ printk(KERN_INFO "availableFaceDetectModes : %d\n", metadata);
+ index++;
+ metadata = capability->stats.availableFaceDetectModes[index];
+ }
+ printk(KERN_INFO "maxFaceCount : %d\n",
+ capability->stats.maxFaceCount);
+ printk(KERN_INFO "histogrambucketCount : %d\n",
+ capability->stats.histogramBucketCount);
+ printk(KERN_INFO "maxHistogramCount : %d\n",
+ capability->stats.maxHistogramCount);
+ printk(KERN_INFO "sharpnessMapSize : %dx%d\n",
+ capability->stats.sharpnessMapSize[0],
+ capability->stats.sharpnessMapSize[1]);
+ printk(KERN_INFO "maxSharpnessMapValue : %d\n",
+ capability->stats.maxSharpnessMapValue);
+
+ printk(KERN_INFO "===3A====================================\n");
+ printk(KERN_INFO "maxRegions : %d\n", capability->aa.maxRegions);
+
+ index = 0;
+ metadata = capability->aa.aeAvailableModes[index];
+ while (metadata) {
+ printk(KERN_INFO "aeAvailableModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.aeAvailableModes[index];
+ }
+ printk(KERN_INFO "aeCompensationStep : %d,%d\n",
+ capability->aa.aeCompensationStep.num,
+ capability->aa.aeCompensationStep.den);
+ printk(KERN_INFO "aeCompensationRange : %d ~ %d\n",
+ capability->aa.aeCompensationRange[0],
+ capability->aa.aeCompensationRange[1]);
+ index = 0;
+ metadata = capability->aa.aeAvailableTargetFpsRanges[index][0];
+ while (metadata) {
+ printk(KERN_INFO "TargetFpsRanges : %d ~ %d\n", metadata,
+ capability->aa.aeAvailableTargetFpsRanges[index][1]);
+ index++;
+ metadata = capability->aa.aeAvailableTargetFpsRanges[index][0];
+ }
+ index = 0;
+ metadata = capability->aa.aeAvailableAntibandingModes[index];
+ while (metadata) {
+ printk(KERN_INFO "aeAvailableAntibandingModes : %d\n",
+ metadata);
+ index++;
+ metadata = capability->aa.aeAvailableAntibandingModes[index];
+ }
+ index = 0;
+ metadata = capability->aa.awbAvailableModes[index];
+ while (metadata) {
+ printk(KERN_INFO "awbAvailableModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.awbAvailableModes[index];
+ }
+ index = 0;
+ metadata = capability->aa.afAvailableModes[index];
+ while (metadata) {
+ printk(KERN_INFO "afAvailableModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.afAvailableModes[index];
+ }
+#endif
+ return ret;
+}
+
+int fimc_is_itf_power_down(struct fimc_is_interface *interface)
+{
+ int ret = 0;
+#ifdef ENABLE_CLOCK_GATE
+ /* HACK */
+ struct fimc_is_core *core = (struct fimc_is_core *)interface->core;
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST) {
+ fimc_is_clk_gate_lock_set(core, 0, true);
+ fimc_is_wrap_clk_gate_set(core, (1 << GROUP_ID_MAX) - 1, true);
+ }
+#endif
+ ret = fimc_is_hw_power_down(interface, 0);
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_lock_set(core, 0, false);
+#endif
+ return ret;
+}
+
+int fimc_is_itf_sys_ctl(struct fimc_is_device_ischain *this,
+ int cmd, int val)
+{
+ int ret = 0;
+ struct fimc_is_interface *itf = this->interface;
+
+ ret = fimc_is_hw_sys_ctl(itf, this->instance,
+ cmd, val);
+
+ return ret;
+}
+
+int fimc_is_itf_sensor_mode(struct fimc_is_device_ischain *ischain)
+{
+ struct fimc_is_device_sensor *sensor = ischain->sensor;
+
+ return fimc_is_hw_sensor_mode(ischain->interface,
+ ischain->instance,
+ ((sensor->mode << 16) | (ischain->module & 0xFFFF)));
+}
+
+static int fimc_is_itf_grp_shot(struct fimc_is_device_ischain *device,
+ struct fimc_is_group *group,
+ struct fimc_is_frame *frame)
+{
+ int ret = 0;
+ u32 group_id = 0;
+#ifdef ENABLE_CLOCK_GATE
+ struct fimc_is_core *core = (struct fimc_is_core *)device->interface->core;
+#endif
+ BUG_ON(!device);
+ BUG_ON(!group);
+ BUG_ON(!frame);
+ BUG_ON(!frame->shot);
+
+ /* Cache Flush */
+ fimc_is_ischain_meta_flush(frame);
+
+ if (frame->shot->magicNumber != SHOT_MAGIC_NUMBER) {
+ merr("shot magic number error(0x%08X)\n", device, frame->shot->magicNumber);
+ merr("shot_ext size : %d", device, sizeof(struct camera2_shot_ext));
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+#ifdef DBG_STREAMING
+ if (group->id == GROUP_ID_3A0)
+ info("[3A0:D:%d] GRP%d SHOT(%d)\n", device->instance, group->id, frame->fcount);
+ else if (group->id == GROUP_ID_3A1)
+ info("[3A1:D:%d] GRP%d SHOT(%d)\n", device->instance, group->id, frame->fcount);
+ else if (group->id == GROUP_ID_ISP)
+ info("[ISP:D:%d] GRP%d SHOT(%d)\n", device->instance, group->id, frame->fcount);
+ else if (group->id == GROUP_ID_DIS)
+ info("[DIS:D:%d] GRP%d SHOT(%d)\n", device->instance, group->id, frame->fcount);
+ else
+ info("[ERR:D:%d] GRP%d SHOT(%d)\n", device->instance, group->id, frame->fcount);
+#endif
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_shot);
+#endif
+#ifdef EXTERNAL_TIME
+ do_gettimeofday(&frame->tzone[TM_SHOT]);
+#endif
+#endif
+
+#ifdef ENABLE_CLOCK_GATE
+ /* HACK */
+ /* dynamic clock on */
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_set(core, group->id, true, false, true);
+#endif
+ group_id = GROUP_ID(group->id);
+
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group_id & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group_id = GROUP_ID(GROUP_ID_3A0);
+
+ ret = fimc_is_hw_shot_nblk(device->interface,
+ device->instance,
+ group_id,
+ frame->dvaddr_buffer[0],
+ frame->dvaddr_shot,
+ frame->fcount,
+ frame->rcount);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_probe(struct fimc_is_device_ischain *device,
+ struct fimc_is_interface *interface,
+ struct fimc_is_resourcemgr *resourcemgr,
+ struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_mem *mem,
+ struct platform_device *pdev,
+ u32 instance,
+ u32 regs)
+{
+ int ret = 0;
+ struct fimc_is_subdev *scc, *dis, *scp;
+
+ BUG_ON(!interface);
+ BUG_ON(!mem);
+ BUG_ON(!pdev);
+ BUG_ON(!device);
+
+ /*device initialization should be just one time*/
+ scc = &device->scc;
+ dis = &device->dis;
+ scp = &device->scp;
+
+ device->interface = interface;
+ device->mem = mem;
+ device->pdev = pdev;
+ device->pdata = pdev->dev.platform_data;
+ device->regs = (void *)regs;
+ device->instance = instance;
+ device->groupmgr = groupmgr;
+ device->resourcemgr = resourcemgr;
+ device->sensor = NULL;
+ device->margin_left = 0;
+ device->margin_right = 0;
+ device->margin_width = 0;
+ device->margin_top = 0;
+ device->margin_bottom = 0;
+ device->margin_height = 0;
+ device->dis_width = 0;
+ device->dis_height = 0;
+ device->chain0_width = 0;
+ device->chain0_height = 0;
+ device->chain1_width = 0;
+ device->chain1_height = 0;
+ device->chain2_width = 0;
+ device->chain2_height = 0;
+ device->chain3_width = 0;
+ device->chain3_height = 0;
+ device->crop_x = 0;
+ device->crop_y = 0;
+ device->crop_width = 0;
+ device->crop_height = 0;
+ device->setfile = 0;
+ device->color_range = 0;
+ device->dzoom_width = 0;
+ device->force_down = false;
+ device->is_region = NULL;
+ device->taa_size_forceset = 0;
+ device->taa_size_changed_fcount = 0;
+ device->isp_size_forceset = 0;
+ device->isp_size_changed_fcount = 0;
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0))
+ fimc_is_group_probe(groupmgr, &device->group_3aa, ENTRY_3AA);
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, isp))
+ fimc_is_group_probe(groupmgr, &device->group_isp, ENTRY_ISP);
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, dis))
+ fimc_is_group_probe(groupmgr, &device->group_dis, ENTRY_DIS);
+
+ device->drc.entry = ENTRY_DRC;
+ device->scc.entry = ENTRY_SCALERC;
+ device->dis.entry = ENTRY_DIS;
+ device->dnr.entry = ENTRY_TDNR;
+ device->scp.entry = ENTRY_SCALERP;
+ device->fd.entry = ENTRY_LHFD;
+ device->taac.entry = ENTRY_3AAC;
+ device->taap.entry = ENTRY_3AAP;
+
+ clear_bit(FIMC_IS_ISCHAIN_OPEN, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state);
+
+ /* clear group open state */
+ clear_bit(FIMC_IS_GROUP_OPEN, &device->group_3aa.state);
+ clear_bit(FIMC_IS_GROUP_OPEN, &device->group_isp.state);
+ clear_bit(FIMC_IS_GROUP_OPEN, &device->group_dis.state);
+
+ /* clear subdevice state */
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->group_3aa.leader.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->group_isp.leader.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->group_dis.leader.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->drc.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->scc.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->dis.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->dnr.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->scp.state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &device->fd.state);
+
+ clear_bit(FIMC_IS_SUBDEV_START, &device->group_3aa.leader.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->group_isp.leader.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->group_dis.leader.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->drc.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->scc.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->dis.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->dnr.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->scp.state);
+ clear_bit(FIMC_IS_SUBDEV_START, &device->fd.state);
+
+ mutex_init(&device->mutex_state);
+
+#ifdef FW_DEBUG
+ debugfs_root = debugfs_create_dir(DEBUG_FS_ROOT_NAME, NULL);
+ if (debugfs_root)
+ mdbgd_ischain("debugfs %s is created\n", device, DEBUG_FS_ROOT_NAME);
+
+ debugfs_file = debugfs_create_file(DEBUG_FS_FILE_NAME, S_IRUSR,
+ debugfs_root, device, &debug_fops);
+ if (debugfs_file)
+ mdbgd_ischain("debugfs %s is created\n", device, DEBUG_FS_FILE_NAME);
+#endif
+
+ return ret;
+}
+
+int fimc_is_ischain_open(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx,
+ struct fimc_is_minfo *minfo)
+{
+ int ret = 0;
+ struct fimc_is_ishcain_mem *imemory;
+#ifdef ENABLE_CLOCK_GATE
+ struct fimc_is_core *core;
+#endif
+ BUG_ON(!device);
+ BUG_ON(!device->groupmgr);
+ BUG_ON(!vctx);
+ BUG_ON(!minfo);
+
+ if (test_bit(FIMC_IS_ISCHAIN_OPEN, &device->state)) {
+ merr("already open", device);
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+#ifndef RESERVED_MEM
+ if (device->instance == 0) {
+ /* 1. init memory */
+ ret = fimc_is_ishcain_initmem(device);
+ if (ret) {
+ err("fimc_is_ishcain_initmem is fail(%d)\n", ret);
+ goto p_err;
+ }
+ }
+#endif
+
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state);
+ clear_bit(FIMC_IS_ISHCAIN_START, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state);
+
+ /* 2. Init variables */
+ memset(&device->cur_peri_ctl, 0,
+ sizeof(struct camera2_uctl));
+ memset(&device->peri_ctls, 0,
+ sizeof(struct camera2_uctl)*SENSOR_MAX_CTL);
+ memset(&device->capability, 0,
+ sizeof(struct camera2_sm));
+
+ /* initial state, it's real apply to setting when opening*/
+ device->margin_left = 0;
+ device->margin_right = 0;
+ device->margin_width = 0;
+ device->margin_top = 0;
+ device->margin_bottom = 0;
+ device->margin_height = 0;
+ device->dis_width = 0;
+ device->dis_height = 0;
+ device->chain0_width = 0;
+ device->chain0_height = 0;
+ device->chain1_width = 0;
+ device->chain1_height = 0;
+ device->chain2_width = 0;
+ device->chain2_height = 0;
+ device->chain3_width = 0;
+ device->chain3_height = 0;
+ device->crop_x = 0;
+ device->crop_y = 0;
+ device->crop_width = 0;
+ device->crop_height = 0;
+ device->setfile = ISS_SUB_SCENARIO_STILL_PREVIEW;
+ device->color_range = 0;
+ device->color_range |= (FIMC_IS_CRANGE_FULL << FIMC_IS_ISP_CRANGE_SHIFT);
+ device->color_range |= (FIMC_IS_CRANGE_FULL << FIMC_IS_SCC_CRANGE_SHIFT);
+ device->color_range |= (FIMC_IS_CRANGE_FULL << FIMC_IS_SCP_CRANGE_SHIFT);
+ device->dzoom_width = 0;
+ device->force_down = false;
+ device->sensor = NULL;
+ device->module = 0;
+
+ imemory = &device->imemory;
+ imemory->base = minfo->base;
+ imemory->size = minfo->size;
+ imemory->vaddr_base = minfo->vaddr_base;
+ imemory->vaddr_curr = minfo->vaddr_curr;
+ imemory->fw_cookie = minfo->fw_cookie;
+ imemory->dvaddr = minfo->dvaddr;
+ imemory->kvaddr = minfo->kvaddr;
+ imemory->dvaddr_odc = minfo->dvaddr_odc;
+ imemory->kvaddr_odc = minfo->kvaddr_odc;
+ imemory->dvaddr_dis = minfo->dvaddr_dis;
+ imemory->kvaddr_dis = minfo->kvaddr_dis;
+ imemory->dvaddr_3dnr = minfo->dvaddr_3dnr;
+ imemory->kvaddr_3dnr = minfo->kvaddr_3dnr;
+ imemory->offset_region = (FIMC_IS_A5_MEM_SIZE -
+ ((device->instance + 1) * FIMC_IS_REGION_SIZE));
+ imemory->dvaddr_region = imemory->dvaddr + imemory->offset_region;
+ imemory->kvaddr_region = imemory->kvaddr + imemory->offset_region;
+ imemory->is_region = (struct is_region *)imemory->kvaddr_region;
+ imemory->offset_shared = (u32)&imemory->is_region->shared[0] -
+ imemory->kvaddr;
+ imemory->dvaddr_shared = imemory->dvaddr + imemory->offset_shared;
+ imemory->kvaddr_shared = imemory->kvaddr + imemory->offset_shared;
+ device->is_region = imemory->is_region;
+
+ fimc_is_group_open(device->groupmgr, &device->group_isp, GROUP_ID_ISP,
+ device->instance, vctx, device, fimc_is_ischain_isp_callback);
+
+ /* subdev open */
+ fimc_is_subdev_open(&device->drc, NULL, &init_drc_param.control);
+ fimc_is_subdev_open(&device->dis, NULL, &init_dis_param.control);
+ fimc_is_subdev_open(&device->dnr, NULL, &init_tdnr_param.control);
+ /* FD see only control.command not bypass */
+ fimc_is_subdev_open(&device->fd, NULL, NULL);
+
+ /* for mediaserver force close */
+ ret = fimc_is_resource_get(device->resourcemgr, RESOURCE_TYPE_ISCHAIN);
+ if (ret) {
+ merr("fimc_is_resource_get is fail", device);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_ISCHAIN_OPEN, &device->state);
+
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST) {
+ core = (struct fimc_is_core *)device->interface->core;
+ fimc_is_clk_gate_lock_set(core, device->instance, true);
+ fimc_is_wrap_clk_gate_set(core, (1 << GROUP_ID_MAX) - 1, true);
+ }
+#endif
+p_err:
+ info("[ISC:D:%d] %s(%d)\n", device->instance, __func__, ret);
+ return ret;
+}
+
+int fimc_is_ischain_close(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+ int refcount;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_queue *queue;
+ struct fimc_is_core *core;
+#ifdef CONFIG_COMPANION_USE
+ struct fimc_is_spi_gpio *spi_gpio;
+#endif
+ BUG_ON(!device);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_isp;
+ leader = &group->leader;
+ queue = GET_SRC_QUEUE(vctx);
+ core = (struct fimc_is_core *)device->interface->core;
+ refcount = atomic_read(&vctx->video->refcount);
+#ifdef CONFIG_COMPANION_USE
+ spi_gpio = &core->spi_gpio;
+#endif
+ if (refcount < 0) {
+ merr("invalid ischain refcount", device);
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_OPEN, &device->state)) {
+ merr("already close", device);
+ ret = -EMFILE;
+ goto exit;
+ }
+
+#ifdef ENABLE_CLOCK_GATE
+ core = (struct fimc_is_core *)device->interface->core;
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST) {
+ fimc_is_clk_gate_lock_set(core, device->instance, true);
+ fimc_is_wrap_clk_gate_set(core, (1 << GROUP_ID_MAX) - 1, true);
+ }
+#endif
+ /* 1. Stop all request */
+ ret = fimc_is_ischain_isp_stop(device, leader, queue);
+ if (ret)
+ merr("fimc_is_ischain_isp_stop is fail", device);
+
+ /* group close */
+ ret = fimc_is_group_close(groupmgr, group);
+ if (ret)
+ merr("fimc_is_group_close is fail", device);
+
+ /* subdev close */
+ fimc_is_subdev_close(&device->drc);
+ fimc_is_subdev_close(&device->dis);
+ fimc_is_subdev_close(&device->dnr);
+ fimc_is_subdev_close(&device->fd);
+
+ /* CLOSE_SENSOR */
+ if (test_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state)) {
+ ret = fimc_is_itf_close(device);
+ if (ret)
+ merr("fimc_is_itf_close is fail", device);
+
+ if(device->sensor->pdata->is_softlanding)
+ fimc_is_sensor_gpio_off_softlanding(device->sensor);
+ }
+
+ /* for mediaserver force close */
+ ret = fimc_is_resource_put(device->resourcemgr, RESOURCE_TYPE_ISCHAIN);
+ if (ret) {
+ merr("fimc_is_resource_put is fail", device);
+ goto exit;
+ }
+
+ clear_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state);
+ clear_bit(FIMC_IS_ISCHAIN_OPEN, &device->state);
+#ifdef CONFIG_COMPANION_USE
+ fimc_is_set_spi_config(spi_gpio, FIMC_IS_SPI_OUTPUT, true);
+#endif
+
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_lock_set(core, device->instance, false);
+#endif
+exit:
+ pr_info("[ISC:D:%d] %s(%d)\n", device->instance, __func__, ret);
+ return ret;
+}
+
+static int fimc_is_ischain_init(struct fimc_is_device_ischain *device,
+ u32 module_id,
+ u32 group_id,
+ u32 video_id,
+ u32 flag)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *sensor;
+#ifdef CONFIG_COMPANION_USE
+ struct fimc_is_core *core
+ = (struct fimc_is_core *)platform_get_drvdata(device->pdev);
+ /* Workaround for Host to use ISP-SPI. Will be removed later.*/
+// struct fimc_is_spi_gpio *spi_gpio = &core->spi_gpio;
+#endif
+
+ BUG_ON(!device);
+ BUG_ON(!device->sensor);
+
+ mdbgd_ischain("%s(module : %d)\n", device, __func__, module_id);
+
+ sensor = device->sensor;
+
+ if (test_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state)) {
+ mwarn("sensor is already open", device);
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_SENSOR_OPEN, &sensor->state)) {
+ merr("I2C gpio is not yet set", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_g_module(sensor, &module);
+ if (ret) {
+ merr("fimc_is_sensor_g_module is fail(%d)", device, ret);
+ goto p_err;
+ }
+ if (module->id != module_id) {
+ merr("module id is invalid(%d != %d)", device, module->id, module_id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ /* sensor instance means flite channel */
+ if(sensor->instance == 0) {
+ /* Load calibration data from sensor */
+ module->ext.sensor_con.cal_address = FIMC_IS_CAL_START_ADDR;
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ ret = fimc_is_ischain_loadcalb_eeprom(device, NULL, SENSOR_POSITION_REAR);
+#else
+ ret = fimc_is_ischain_loadcalb(device, NULL);
+#endif
+ if (ret) {
+ err("loadcalb fail, load default caldata\n");
+ }
+ } else {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ module->ext.sensor_con.cal_address = FIMC_IS_CAL_START_ADDR_FRONT;
+ ret = fimc_is_ischain_loadcalb_eeprom(device, NULL, SENSOR_POSITION_FRONT);
+ if (ret) {
+ err("loadcalb fail, load default caldata\n");
+ }
+#else
+ module->ext.sensor_con.cal_address = 0;
+#endif
+ }
+ }
+
+#ifdef CONFIG_COMPANION_USE
+ if(core->companion->companion_status != FIMC_IS_COMPANION_IDLE) {
+ pr_info("[ISC:D:%d] fimc_is_companion_wait wait(%d)\n", device->instance,core->companion->companion_status);
+ fimc_is_companion_wait(core->companion);
+ pr_info("[ISC:D:%d] fimc_is_companion_wait wake up(%d)\n", device->instance,core->companion->companion_status);
+ }
+
+ fimc_is_s_int_comb_isp(core, false, INTMR2_INTMCIS22);
+
+#if 0
+ /* FW loading of peripheral device */
+ if ((module->position == SENSOR_POSITION_REAR)
+ && !test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ // Workaround for Host to use ISP-SPI. Will be removed later.
+ /* set pin output for Host to use SPI*/
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_ssn,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, FUNC_OUTPUT));
+
+ fimc_is_set_spi_config(spi_gpio, FIMC_IS_SPI_FUNC, false);
+
+ if (fimc_is_comp_is_valid(core) == 0) {
+ fimc_is_power_binning(core);
+ ret = fimc_is_comp_loadfirm(core);
+ if (ret) {
+ err("fimc_is_comp_loadfirm() fail");
+ goto p_err;
+ }
+ ret = fimc_is_comp_loadcal(core);
+ if (ret) {
+ err("fimc_is_comp_loadcal() fail");
+ }
+ ret = fimc_is_comp_loadsetf(core);
+ if (ret) {
+ err("fimc_is_comp_loadsetf() fail");
+ goto p_err;
+ }
+ } else {
+ module->ext.companion_con.product_name
+ = COMPANION_NAME_NOTHING;
+ }
+ // Workaround for Host to use ISP-SPI. Will be removed later.
+ /* Set SPI pins to low before changing pin function */
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_sclk,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_ssn,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_miso,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_mois,
+ PINCFG_PACK(PINCFG_TYPE_DAT, 0));
+
+ /* Set pin function for A5 to use SPI */
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_ssn,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+ }
+#endif
+#endif
+
+ ret = fimc_is_itf_enum(device);
+ if (ret) {
+ err("enum fail");
+ goto p_err;
+ }
+
+#if (FW_HAS_SENSOR_MODE_CMD)
+ ret = fimc_is_itf_open(device, ((sensor->mode << 16) | (module_id & 0xFFFF)),
+ group_id, flag, &module->ext);
+#else
+ ret = fimc_is_itf_open(device, module_id, group_id, flag, &module->ext);
+#endif
+ if (ret) {
+ merr("open fail", device);
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_setfile(device, module->setfile_name);
+ if (ret) {
+ merr("setfile fail", device);
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ ret = fimc_is_itf_stream_off(device);
+ if (ret) {
+ merr("streamoff fail", device);
+ goto p_err;
+ }
+ }
+
+ ret = fimc_is_itf_init_process_stop(device);
+ if (ret) {
+ merr("fimc_is_itf_init_process_stop is fail", device);
+ goto p_err;
+ }
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ measure_period(&device->group_3aa.time, 1);
+ measure_period(&device->group_isp.time, 1);
+ measure_period(&device->group_dis.time, 1);
+ } else {
+ measure_period(&device->group_3aa.time, 66);
+ measure_period(&device->group_isp.time, 66);
+ measure_period(&device->group_dis.time, 66);
+ }
+#endif
+#endif
+
+ device->module = module_id;
+ set_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_init_wrap(struct fimc_is_device_ischain *device,
+ u32 input)
+{
+ int ret = 0;
+ u32 flag = 0;
+ u32 group_id = 0;
+ u32 module, ssx_vindex, tax_vindex, rep_stream;
+ struct fimc_is_core *core = NULL;
+ struct fimc_is_device_sensor *sensor = NULL;
+
+ BUG_ON(!device);
+
+ mdbgd_ischain("%s(input : %08X)\n", device, __func__, input);
+
+ core = (struct fimc_is_core *)platform_get_drvdata(device->pdev);
+
+ module = input & MODULE_MASK;
+ ssx_vindex = (input & SSX_VINDEX_MASK) >> SSX_VINDEX_SHIFT;
+ tax_vindex = (input & TAX_VINDEX_MASK) >> TAX_VINDEX_SHIFT;
+ rep_stream = (input & REPROCESSING_MASK) >> REPROCESSING_SHIFT;
+
+ /* 1. checking 3ax group to connect */
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)
+ || GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1))
+ group_id = device->group_3aa.id;
+ else
+ group_id = GROUP_ID_3A0;
+
+ /* 2. checking sensor video node to connect */
+ if (ssx_vindex == FIMC_IS_VIDEO_SS0_NUM) {
+ sensor = &core->sensor[0];
+ info("[ISP:V:%d] <-> [SS0:V:0]\n", device->instance);
+ } else if (ssx_vindex == FIMC_IS_VIDEO_SS1_NUM) {
+ sensor = &core->sensor[1];
+ info("[ISP:V:%d] <-> [SS1:V:0]\n", device->instance);
+ } else {
+ sensor = NULL;
+ merr("sensor is not matched", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* 3. checking reprocessing stream */
+ if (rep_stream) {
+ flag = REPROCESSING_FLAG;
+ set_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state);
+ } else {
+ /* connect to sensor if it's not a reprocessing stream */
+ sensor->ischain = device;
+ flag = 0;
+ }
+
+ /* 4. init variable */
+ device->instance_sensor = sensor->instance;
+ device->sensor = sensor;
+
+ info("%s(%s) : module(%d), flag(%08X), group_id(%d)\n", __func__,
+ (rep_stream ? "Reprocessing" : "Preview"), module, flag, group_id);
+
+ /* 5. init ischain */
+ ret = fimc_is_ischain_init(device, module, group_id, tax_vindex, flag);
+ if (ret)
+ merr("fimc_is_device_init(%d, %d, %d) is fail", device, module, group_id, rep_stream);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_s_color_range(struct fimc_is_device_ischain *device,
+ u32 color_range, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ int ret = 0;
+ u32 crange;
+ struct param_otf_output *otf_output;
+ struct param_scaler_imageeffect *scaler_effect;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ /*
+ * Color Range
+ * 0 : Wide range
+ * 1 : Narrow range
+ */
+ otf_output = fimc_is_itf_g_param(device, NULL, PARAM_ISP_OTF_OUTPUT);
+ crange = (color_range & FIMC_IS_ISP_CRANGE_MASK) >> FIMC_IS_ISP_CRANGE_SHIFT;
+ if (crange)
+ otf_output->format = OTF_OUTPUT_FORMAT_YUV444_TRUNCATED;
+ else
+ otf_output->format = OTF_OUTPUT_FORMAT_YUV444;
+ *lindex |= LOWBIT_OF(PARAM_ISP_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_ISP_OTF_OUTPUT);
+
+ info("[ISC:D:%d] ISP color range: %s\n", device->instance,
+ (crange ? "limited" : "full"));
+
+ scaler_effect = fimc_is_itf_g_param(device, NULL, PARAM_SCALERC_IMAGE_EFFECT);
+ crange = (color_range & FIMC_IS_SCC_CRANGE_MASK) >> FIMC_IS_SCC_CRANGE_SHIFT;
+ if (crange)
+ scaler_effect->yuv_range = SCALER_OUTPUT_YUV_RANGE_NARROW;
+ else
+ scaler_effect->yuv_range = SCALER_OUTPUT_YUV_RANGE_FULL;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_IMAGE_EFFECT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_IMAGE_EFFECT);
+ (*indexes)++;
+
+ info("[ISC:D:%d] SCC color range: %s\n", device->instance,
+ (crange ? "limited" : "full"));
+
+ scaler_effect = fimc_is_itf_g_param(device, NULL, PARAM_SCALERP_IMAGE_EFFECT);
+ crange = (color_range & FIMC_IS_SCP_CRANGE_MASK) >> FIMC_IS_SCP_CRANGE_SHIFT;
+ if (crange)
+ scaler_effect->yuv_range = SCALER_OUTPUT_YUV_RANGE_NARROW;
+ else
+ scaler_effect->yuv_range = SCALER_OUTPUT_YUV_RANGE_FULL;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_IMAGE_EFFECT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_IMAGE_EFFECT);
+ (*indexes)++;
+
+ info("[ISC:D:%d] SCP color range: %s\n", device->instance,
+ (crange ? "limited" : "full"));
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_sensor(struct fimc_is_device_ischain *device,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct sensor_param *sensor_param;
+ size_t sensor_width, sensor_height;
+ u32 framerate;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+ BUG_ON(!device->sensor);
+
+ sensor_param = &device->is_region->parameter.sensor;
+ sensor_width = fimc_is_sensor_g_width(device->sensor);
+ sensor_height = fimc_is_sensor_g_height(device->sensor);
+ framerate = fimc_is_sensor_g_framerate(device->sensor);
+
+#ifdef FIXED_FPS_DEBUG
+ sensor_param->config.framerate = FIXED_FPS_VALUE;
+#else
+ sensor_param->config.framerate = framerate;
+#endif
+ if (device->sensor->min_target_fps > 0)
+ sensor_param->config.min_target_fps = device->sensor->min_target_fps;
+ if (device->sensor->max_target_fps > 0)
+ sensor_param->config.max_target_fps = device->sensor->max_target_fps;
+ if (device->sensor->scene_mode >= AA_SCENE_MODE_UNSUPPORTED)
+ sensor_param->config.scene_mode = device->sensor->scene_mode;
+
+ *lindex |= LOWBIT_OF(PARAM_SENSOR_CONFIG);
+ *hindex |= HIGHBIT_OF(PARAM_SENSOR_CONFIG);
+ (*indexes)++;
+
+ sensor_param->dma_output.width = sensor_width;
+ sensor_param->dma_output.height = sensor_height;
+
+ *lindex |= LOWBIT_OF(PARAM_SENSOR_DMA_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SENSOR_DMA_OUTPUT);
+ (*indexes)++;
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_3aa_size(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ u32 *input_crop,
+ u32 *output_crop,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct fimc_is_group *group_3aa;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_queue *queue;
+ struct param_control *taa_control;
+ struct param_otf_input *taa_otf_input;
+ struct param_dma_input *taa_dma_input;
+ size_t sensor_width, sensor_height;
+ size_t bns_width, bns_height;
+ size_t total_width, total_height;
+ u32 binning;
+ u32 bns_binning;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+ BUG_ON(!device->sensor);
+
+ sensor_width = fimc_is_sensor_g_width(device->sensor);
+ sensor_height = fimc_is_sensor_g_height(device->sensor);
+ bns_width = fimc_is_sensor_g_bns_width(device->sensor);
+ bns_height = fimc_is_sensor_g_bns_height(device->sensor);
+ binning = fimc_is_sensor_g_bratio(device->sensor);
+ bns_binning = fimc_is_sensor_g_bns_ratio(device->sensor);
+ total_width = 2 * input_crop[0] + input_crop[2];
+ total_height = 2 * input_crop[1] + input_crop[3];
+
+ /* check crop size */
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &device->group_3aa.state)) {
+ if (bns_width <= total_width) {
+ merr("crop width(%d) is bigger than input width(%d)\n",
+ device, total_width, bns_width);
+ goto p_err;
+ }
+
+ if (bns_height <= total_height) {
+ merr("crop height(%d) is bigger than input height(%d)\n",
+ device, total_height, bns_height);
+ goto p_err;
+ }
+
+ taa_otf_input = fimc_is_itf_g_param(device, frame, PARAM_3AA_OTF_INPUT);
+ taa_otf_input->cmd = OTF_INPUT_COMMAND_ENABLE;
+
+ taa_dma_input = fimc_is_itf_g_param(device, frame, PARAM_3AA_VDMA1_INPUT);
+ taa_dma_input->cmd = DMA_INPUT_COMMAND_DISABLE;
+ } else {
+ if (sensor_width <= total_width) {
+ merr("crop width(%d) is bigger than input width(%d)\n",
+ device, total_width, sensor_width);
+ goto p_err;
+ }
+
+ if (sensor_height <= total_height) {
+ merr("crop height(%d) is bigger than input height(%d)\n",
+ device, total_height, sensor_height);
+ goto p_err;
+ }
+
+ taa_otf_input = fimc_is_itf_g_param(device, frame, PARAM_3AA_OTF_INPUT);
+ taa_otf_input->cmd = OTF_INPUT_COMMAND_DISABLE;
+
+ taa_dma_input = fimc_is_itf_g_param(device, frame, PARAM_3AA_VDMA1_INPUT);
+ taa_dma_input->cmd = DMA_INPUT_COMMAND_BUF_MNGR;
+ }
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0))
+ group_3aa = &device->group_3aa;
+ else
+ group_3aa = &device->group_isp;
+ leader = &group_3aa->leader;
+ queue = GET_LEADER_QUEUE(leader);
+ if (!queue) {
+ merr("get queue fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ taa_control = fimc_is_itf_g_param(device, frame, PARAM_3AA_CONTROL);
+ taa_control->cmd = CONTROL_COMMAND_START;
+ taa_control->bypass = CONTROL_BYPASS_DISABLE;
+ taa_control->run_mode = 1;
+ *lindex |= LOWBIT_OF(PARAM_3AA_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_CONTROL);
+ (*indexes)++;
+
+ /* OTF */
+ taa_otf_input->width = sensor_width;
+ taa_otf_input->height = sensor_height;
+ taa_otf_input->bayer_crop_enable = 1;
+ taa_otf_input->bayer_crop_offset_x = input_crop[0];
+ taa_otf_input->bayer_crop_offset_y = input_crop[1];
+ taa_otf_input->bayer_crop_width = input_crop[2];
+ taa_otf_input->bayer_crop_height = input_crop[3];
+ taa_otf_input->sensor_binning_ratio_x = binning;
+ taa_otf_input->sensor_binning_ratio_y = binning;
+
+ taa_otf_input->bns_binning_enable = 1;
+ taa_otf_input->bns_binning_ratio_x = bns_binning;
+ taa_otf_input->bns_binning_ratio_y = bns_binning;
+ taa_otf_input->bns_margin_left = 0;
+ taa_otf_input->bns_margin_top = 0;
+ taa_otf_input->bns_output_width = bns_width;
+ taa_otf_input->bns_output_height = bns_height;
+
+ taa_otf_input->format = OTF_INPUT_FORMAT_BAYER;
+ taa_otf_input->bitwidth = OTF_INPUT_BIT_WIDTH_10BIT;
+ taa_otf_input->order = OTF_INPUT_ORDER_BAYER_GR_BG;
+ taa_otf_input->frametime_min = 0;
+ taa_otf_input->frametime_max = 1000000;
+ *lindex |= LOWBIT_OF(PARAM_3AA_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_OTF_INPUT);
+ (*indexes)++;
+
+ /* M2M */
+ taa_dma_input->width = sensor_width;
+ taa_dma_input->height = sensor_height;
+ taa_dma_input->bayer_crop_enable = 1;
+ taa_dma_input->bayer_crop_offset_x = input_crop[0];
+ taa_dma_input->bayer_crop_offset_y = input_crop[1];
+ taa_dma_input->bayer_crop_width = input_crop[2];
+ taa_dma_input->bayer_crop_height = input_crop[3];
+
+ if (!GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)) {
+ taa_dma_input->bds_out_enable = ISP_BDS_COMMAND_ENABLE;
+ taa_dma_input->bds_out_width = output_crop[2];
+ taa_dma_input->bds_out_height = output_crop[3];
+ }
+
+ taa_dma_input->user_min_frame_time = 0;
+ taa_dma_input->user_max_frame_time = 1000000;
+
+ if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+ queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR12) {
+ taa_dma_input->format = DMA_INPUT_FORMAT_BAYER_PACKED12;
+ } else if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR16) {
+ taa_dma_input->format = DMA_INPUT_FORMAT_BAYER;
+ } else {
+ merr("Invalid bayer format(%d)", device, queue->framecfg.format.pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ taa_dma_input->bitwidth = DMA_INPUT_BIT_WIDTH_10BIT;
+ taa_dma_input->order = DMA_INPUT_ORDER_GR_BG;
+ taa_dma_input->plane = 1;
+ taa_dma_input->buffer_number = 0;
+ taa_dma_input->buffer_address = 0;
+ taa_dma_input->sensor_binning_ratio_x = binning;
+ taa_dma_input->sensor_binning_ratio_y = binning;
+ /*
+ * hidden spec
+ * [0] : sensor size is dma input size
+ * [X] : sensor size is reserved field
+ */
+ taa_dma_input->reserved[1] = 0;
+ taa_dma_input->reserved[2] = 0;
+ *lindex |= LOWBIT_OF(PARAM_3AA_VDMA1_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_VDMA1_INPUT);
+ (*indexes)++;
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain0_size(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ u32 width,
+ u32 height,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct fimc_is_group *group_isp;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_queue *queue;
+ struct param_otf_input *otf_input;
+ struct param_dma_input *dma_input;
+ struct param_otf_output *otf_output;
+ struct param_scaler_input_crop *input_crop;
+ u32 chain0_width, chain0_height;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ chain0_width = width;
+ chain0_height = height;
+
+ group_isp = &device->group_isp;
+ if (!group_isp) {
+ merr("get gourp_isp fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ leader = &group_isp->leader;
+ if (!leader) {
+ merr("get leader fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ queue = GET_LEADER_QUEUE(leader);
+ if (!queue) {
+ merr("get queue fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ mdbgd_ischain("request chain0 size : %dx%d\n", device, chain0_width, chain0_height);
+
+ /* ISP */
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)) {
+ dma_input = fimc_is_itf_g_param(device, frame, PARAM_ISP_VDMA1_INPUT);
+ dma_input->cmd = DMA_INPUT_COMMAND_BUF_MNGR;
+ dma_input->width = chain0_width;
+ dma_input->height = chain0_height;
+ dma_input->bitwidth = DMA_INPUT_BIT_WIDTH_10BIT;
+
+ if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+ queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR12) {
+ dma_input->format = DMA_INPUT_FORMAT_BAYER_PACKED12;
+ } else if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR16) {
+ dma_input->format = DMA_INPUT_FORMAT_BAYER;
+ } else {
+ merr("Invalid bayer format(%d)", device, queue->framecfg.format.pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ *lindex |= LOWBIT_OF(PARAM_ISP_VDMA1_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_ISP_VDMA1_INPUT);
+ (*indexes)++;
+ }
+
+ otf_output = fimc_is_itf_g_param(device, frame, PARAM_ISP_OTF_OUTPUT);
+ otf_output->cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ otf_output->width = chain0_width;
+ otf_output->height = chain0_height;
+ otf_output->format = OTF_OUTPUT_FORMAT_YUV444;
+ otf_output->bitwidth = OTF_OUTPUT_BIT_WIDTH_12BIT;
+ otf_output->order = OTF_INPUT_ORDER_BAYER_GR_BG;
+ *lindex |= LOWBIT_OF(PARAM_ISP_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_ISP_OTF_OUTPUT);
+ (*indexes)++;
+
+ /* DRC */
+ otf_input = fimc_is_itf_g_param(device, frame, PARAM_DRC_OTF_INPUT);
+ otf_input->cmd = OTF_INPUT_COMMAND_ENABLE;
+ otf_input->width = chain0_width;
+ otf_input->height = chain0_height;
+ *lindex |= LOWBIT_OF(PARAM_DRC_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_DRC_OTF_INPUT);
+ (*indexes)++;
+
+ otf_output = fimc_is_itf_g_param(device, frame, PARAM_DRC_OTF_OUTPUT);
+ otf_output->cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ otf_output->width = chain0_width;
+ otf_output->height = chain0_height;
+ *lindex |= LOWBIT_OF(PARAM_DRC_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_DRC_OTF_OUTPUT);
+ (*indexes)++;
+
+ /* SCC */
+ otf_input = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_OTF_INPUT);
+ otf_input->cmd = OTF_INPUT_COMMAND_ENABLE;
+ otf_input->width = chain0_width;
+ otf_input->height = chain0_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_INPUT);
+ (*indexes)++;
+
+ /* SCC CROP */
+ input_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_INPUT_CROP);
+ input_crop->pos_x = 0;
+ input_crop->pos_y = 0;
+ input_crop->crop_width = chain0_width;
+ input_crop->crop_height = chain0_height;
+ input_crop->in_width = chain0_width;
+ input_crop->in_height = chain0_height;
+
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ (*indexes)++;
+
+ device->bds_width = width;
+ device->bds_height = height;
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain1_size(struct fimc_is_device_ischain *device,
+ u32 width, u32 height, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ int ret = 0;
+ struct scalerc_param *scc_param;
+ struct odc_param *odc_param;
+ struct dis_param *dis_param;
+ u32 chain1_width, chain1_height;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state))
+ return 0;
+
+ scc_param = &device->is_region->parameter.scalerc;
+ odc_param = &device->is_region->parameter.odc;
+ dis_param = &device->is_region->parameter.dis;
+ chain1_width = width;
+ chain1_height = height;
+
+ mdbgd_ischain("current chain1 size : %dx%d\n", device,
+ device->chain1_width, device->chain1_height);
+ mdbgd_ischain("request chain1 size : %dx%d\n", device,
+ chain1_width, chain1_height);
+
+ if (!chain1_width) {
+ err("chain1 width is zero");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (!chain1_height) {
+ err("chain1 height is zero");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* SCC OUTPUT */
+ scc_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_param->input_crop.out_width = chain1_width;
+ scc_param->input_crop.out_height = chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ (*indexes)++;
+
+ scc_param->output_crop.cmd = SCALER_CROP_COMMAND_DISABLE;
+ scc_param->output_crop.pos_x = 0;
+ scc_param->output_crop.pos_y = 0;
+ scc_param->output_crop.crop_width = chain1_width;
+ scc_param->output_crop.crop_height = chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ (*indexes)++;
+
+ scc_param->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ scc_param->otf_output.width = chain1_width;
+ scc_param->otf_output.height = chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ (*indexes)++;
+
+ /* ODC */
+ odc_param->otf_input.width = chain1_width;
+ odc_param->otf_input.height = chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_ODC_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_ODC_OTF_INPUT);
+ (*indexes)++;
+
+ odc_param->otf_output.width = chain1_width;
+ odc_param->otf_output.height = chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_ODC_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_ODC_OTF_OUTPUT);
+ (*indexes)++;
+
+ /* DIS INPUT */
+ dis_param->otf_input.width = chain1_width;
+ dis_param->otf_input.height = chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_DIS_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_DIS_OTF_INPUT);
+ (*indexes)++;
+
+exit:
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain2_size(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ u32 width,
+ u32 height,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_otf_input *otf_input;
+ struct param_otf_output *otf_output;
+ struct param_dma_output *dma_output;
+ u32 chain2_width, chain2_height;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state))
+ return 0;
+
+ mdbgd_ischain("request chain2 size : %dx%d\n", device, width, height);
+ mdbgd_ischain("current chain2 size : %dx%d\n",
+ device, device->chain2_width, device->chain2_height);
+
+ /* CALCULATION */
+ chain2_width = width;
+ chain2_height = height;
+
+ /* DIS OUTPUT */
+ otf_output = fimc_is_itf_g_param(device, frame, PARAM_DIS_OTF_OUTPUT);
+ otf_output->width = chain2_width;
+ otf_output->height = chain2_height;
+ *lindex |= LOWBIT_OF(PARAM_DIS_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_DIS_OTF_OUTPUT);
+ (*indexes)++;
+
+ otf_input = fimc_is_itf_g_param(device, frame, PARAM_TDNR_OTF_INPUT);
+ otf_input->width = chain2_width;
+ otf_input->height = chain2_height;
+ *lindex |= LOWBIT_OF(PARAM_TDNR_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_TDNR_OTF_INPUT);
+ (*indexes)++;
+
+ dma_output = fimc_is_itf_g_param(device, frame, PARAM_TDNR_DMA_OUTPUT);
+ dma_output->width = chain2_width;
+ dma_output->height = chain2_height;
+ *lindex |= LOWBIT_OF(PARAM_TDNR_DMA_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_TDNR_DMA_OUTPUT);
+ (*indexes)++;
+
+ otf_output = fimc_is_itf_g_param(device, frame, PARAM_TDNR_OTF_OUTPUT);
+ otf_output->width = chain2_width;
+ otf_output->height = chain2_height;
+ *lindex |= LOWBIT_OF(PARAM_TDNR_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_TDNR_OTF_OUTPUT);
+ (*indexes)++;
+
+ otf_input = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_OTF_INPUT);
+ otf_input->width = chain2_width;
+ otf_input->height = chain2_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_OTF_INPUT);
+ (*indexes)++;
+
+ return ret;
+}
+
+/**
+ Utility function to adjust output crop size based on the
+ H/W limitation of SCP scaling.
+ output_crop_w and output_crop_h are call-by reference parameter,
+ which contain intended cropping size. Adjusted size will be stored on
+ those parameters when this function returns.
+ */
+static int fimc_is_ischain_scp_adjust_crop(struct fimc_is_device_ischain *device,
+ struct scalerp_param *scp_param,
+ u32 *output_crop_w, u32 *output_crop_h)
+{
+ int changed = 0;
+
+ if (*output_crop_w > scp_param->otf_input.width * 4) {
+ mwarn("Cannot be scaled up beyond 4 times(%d -> %d)",
+ device, scp_param->otf_input.width, *output_crop_w);
+ *output_crop_w = scp_param->otf_input.width * 4;
+ changed |= 0x01;
+ }
+
+ if (*output_crop_h > scp_param->otf_input.height * 4) {
+ mwarn("Cannot be scaled up beyond 4 times(%d -> %d)",
+ device, scp_param->otf_input.height, *output_crop_h);
+ *output_crop_h = scp_param->otf_input.height * 4;
+ changed |= 0x02;
+ }
+
+ if (*output_crop_w < (scp_param->otf_input.width + 15) / 16) {
+ mwarn("Cannot be scaled down beyond 1/16 times(%d -> %d)",
+ device, scp_param->otf_input.width, *output_crop_w);
+ *output_crop_w = (scp_param->otf_input.width + 15) / 16;
+ changed |= 0x10;
+ }
+
+ if (*output_crop_h < (scp_param->otf_input.height + 15) / 16) {
+ mwarn("Cannot be scaled down beyond 1/16 times(%d -> %d)",
+ device, scp_param->otf_input.height, *output_crop_h);
+ *output_crop_h = (scp_param->otf_input.height + 15) / 16;
+ changed |= 0x20;
+ }
+
+ return changed;
+}
+
+static int fimc_is_ischain_s_chain3_size(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ u32 width,
+ u32 height,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_scaler_input_crop *input_crop;
+ struct param_scaler_output_crop *output_crop;
+ struct param_otf_input *otf_input;
+ struct param_otf_output *otf_output;
+ struct param_dma_output *dma_output;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_queue *queue;
+ struct scalerp_param *scp_param;
+ u32 chain2_width, chain2_height;
+ u32 chain3_width, chain3_height;
+ u32 scp_crop_width, scp_crop_height;
+ u32 scp_crop_x, scp_crop_y;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state))
+ return 0;
+
+ /* Adjust output crop to prevent exceeding SCP limitation */
+ scp_param = &device->is_region->parameter.scalerp;
+ fimc_is_ischain_scp_adjust_crop(device, scp_param, &width, &height);
+
+ vctx = device->scp.vctx;
+ queue = vctx->q_dst;
+
+ chain2_width = device->chain2_width;
+ chain2_height = device->chain2_height;
+ chain3_width = width;
+ chain3_height = height;
+
+ scp_crop_x = 0;
+ scp_crop_y = 0;
+ scp_crop_width = chain2_width;
+ scp_crop_height = chain2_height;
+
+ mdbgd_ischain("request chain3 size : %dx%d\n", device, width, height);
+ mdbgd_ischain("current chain3 size : %dx%d\n",
+ device, device->chain3_width, device->chain3_height);
+
+ /* SCP */
+ input_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_INPUT_CROP);
+ input_crop->cmd = SCALER_CROP_COMMAND_ENABLE;
+ input_crop->pos_x = scp_crop_x;
+ input_crop->pos_y = scp_crop_y;
+ input_crop->crop_width = scp_crop_width;
+ input_crop->crop_height = scp_crop_height;
+ input_crop->in_width = chain2_width;
+ input_crop->in_height = chain2_height;
+ input_crop->out_width = chain3_width;
+ input_crop->out_height = chain3_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ (*indexes)++;
+
+ /*
+ * scaler can't apply stride to each plane, only y plane.
+ * basically cb, cr plane should be half of y plane,
+ * and it's automatically set
+ *
+ * 3 plane : all plane should be 8 or 16 stride
+ * 2 plane : y plane should be 32, 16 stride, others should be half stride of y
+ * 1 plane : all plane should be 8 stride
+ */
+ /*
+ * limitation of output_crop.pos_x and pos_y
+ * YUV422 3P, YUV420 3P : pos_x and pos_y should be x2
+ * YUV422 1P : pos_x should be x2
+ */
+ output_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_OUTPUT_CROP);
+ if (queue->framecfg.width_stride[0]) {
+ output_crop->cmd = SCALER_CROP_COMMAND_ENABLE;
+ output_crop->pos_x = 0;
+ output_crop->pos_y = 0;
+ output_crop->crop_width = chain3_width + queue->framecfg.width_stride[0];
+ output_crop->crop_height = chain3_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ (*indexes)++;
+ } else {
+ output_crop->cmd = SCALER_CROP_COMMAND_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ (*indexes)++;
+ }
+
+ otf_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_OTF_OUTPUT);
+ otf_output->width = chain3_width;
+ otf_output->height = chain3_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_OTF_OUTPUT);
+ (*indexes)++;
+
+ dma_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_DMA_OUTPUT);
+ dma_output->width = chain3_width;
+ dma_output->height = chain3_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ (*indexes)++;
+
+ /* FD */
+ otf_input = fimc_is_itf_g_param(device, frame, PARAM_FD_OTF_INPUT);
+ otf_input->width = chain3_width;
+ otf_input->height = chain3_height;
+ *lindex |= LOWBIT_OF(PARAM_FD_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_FD_OTF_INPUT);
+ (*indexes)++;
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_path(struct fimc_is_device_ischain *device,
+ u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ int ret = 0;
+ struct isp_param *isp_param;
+ struct drc_param *drc_param;
+ struct scalerc_param *scc_param;
+ struct odc_param *odc_param;
+ struct dis_param *dis_param;
+ struct tdnr_param *dnr_param;
+ struct scalerp_param *scp_param;
+
+ BUG_ON(!device);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ isp_param = &device->is_region->parameter.isp;
+ drc_param = &device->is_region->parameter.drc;
+ scc_param = &device->is_region->parameter.scalerc;
+ odc_param = &device->is_region->parameter.odc;
+ dis_param = &device->is_region->parameter.dis;
+ dnr_param = &device->is_region->parameter.tdnr;
+ scp_param = &device->is_region->parameter.scalerp;
+
+ isp_param->control.cmd = CONTROL_COMMAND_START;
+ isp_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ isp_param->control.run_mode = 1;
+ *lindex |= LOWBIT_OF(PARAM_ISP_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_ISP_CONTROL);
+ (*indexes)++;
+
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ scc_param->otf_output.cmd = OTF_OUTPUT_COMMAND_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ (*indexes)++;
+
+ odc_param->control.cmd = CONTROL_COMMAND_STOP;
+ *lindex |= LOWBIT_OF(PARAM_ODC_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_ODC_CONTROL);
+ (*indexes)++;
+
+ fimc_is_subdev_drc_bypass(device, &drc_param->control, lindex, hindex, indexes);
+ fimc_is_subdev_dis_stop(device, dis_param, lindex, hindex, indexes);
+ fimc_is_subdev_dnr_stop(device, &dnr_param->control, lindex, hindex, indexes);
+
+ scp_param->control.cmd = CONTROL_COMMAND_STOP;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_CONTROL);
+ (*indexes)++;
+ } else {
+ scc_param->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ (*indexes)++;
+
+ odc_param->control.cmd = CONTROL_COMMAND_START;
+ *lindex |= LOWBIT_OF(PARAM_ODC_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_ODC_CONTROL);
+ (*indexes)++;
+
+ fimc_is_subdev_drc_bypass(device, &drc_param->control, lindex, hindex, indexes);
+ fimc_is_subdev_dis_bypass(device, dis_param, lindex, hindex, indexes);
+ fimc_is_subdev_dnr_bypass(device, &dnr_param->control, lindex, hindex, indexes);
+
+ scp_param->control.cmd = CONTROL_COMMAND_START;
+#ifdef SCALER_PARALLEL_MODE
+ scp_param->otf_input.scaler_path_sel = OTF_INPUT_PARAL_PATH;
+#else
+ scp_param->otf_input.scaler_path_sel = OTF_INPUT_SERIAL_PATH;
+#endif
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_CONTROL);
+ (*indexes)++;
+ }
+
+ return ret;
+}
+
+#ifdef ENABLE_SETFILE
+static int fimc_is_ischain_chg_setfile(struct fimc_is_device_ischain *device,
+ unsigned int setfile)
+{
+ int ret = 0;
+ u32 group_id = 0;
+ struct fimc_is_group *group_isp;
+ unsigned int save_setfile;
+
+ BUG_ON(!device);
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &device->group_3aa.state)) {
+ mwarn("Changing setfile index is not supportd at OTF group\n", device);
+ goto p_err;
+ }
+
+ group_isp = &device->group_isp;
+
+ if (group_isp->smp_shot.count < 1) {
+ mwarn("group%d is working(%d), setfile change is fail",
+ device, group_isp->id, group_isp->smp_shot.count);
+ goto p_err;
+ }
+
+ group_id |= GROUP_ID(device->group_3aa.id);
+ group_id |= GROUP_ID(device->group_isp.id);
+
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group_id & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group_id = GROUP_ID(GROUP_ID_3A0);
+
+ if (test_bit(FIMC_IS_GROUP_ACTIVE, &device->group_dis.state))
+ group_id |= GROUP_ID(device->group_dis.id);
+
+ save_setfile = device->setfile;
+ device->setfile = setfile;
+
+ ret = fimc_is_itf_process_stop(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_stop fail", device);
+ device->setfile = save_setfile;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_a_param(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_a_param is fail", device);
+ device->setfile = save_setfile;
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_process_start(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_start fail", device);
+ device->setfile = save_setfile;
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ minfo("[ISC:D] setfile: 0x%08X\n", device, device->setfile);
+
+p_err:
+ return ret;
+}
+#endif
+
+#ifdef SCALER_CROP_DZOOM
+static int fimc_is_ischain_s_dzoom(struct fimc_is_device_ischain *this,
+ u32 crop_x, u32 crop_y, u32 crop_width)
+{
+ int ret = 0;
+ u32 indexes, lindex, hindex;
+ u32 chain0_width, chain0_height;
+ u32 temp_width, temp_height, input_width;
+ u32 zoom_input, zoom_target;
+ u32 crop_cx, crop_cy, crop_cwidth, crop_cheight;
+ struct scalerc_param *scc_param;
+ u32 chain0_ratio, preview_ratio;
+ u32 chain0_ratio_width, chain0_ratio_height;
+#ifdef USE_ADVANCED_DZOOM
+ u32 zoom_pre, zoom_post, zoom_pre_max;
+ u32 crop_px, crop_py, crop_pwidth, crop_pheight;
+ u32 chain1_width, chain1_height;
+ u32 chain2_width, chain2_height;
+ u32 chain3_width, chain3_height;
+ u32 scp_input_width, scp_input_height;
+ struct scalerp_param *scp_param;
+
+ scc_param = &this->is_region->parameter.scalerc;
+ scp_param = &this->is_region->parameter.scalerp;
+ indexes = lindex = hindex = 0;
+ chain0_width = this->chain0_width;
+ chain0_height = this->chain0_height;
+ chain1_width = this->chain1_width;
+ chain1_height = this->chain1_height;
+ chain2_width = this->chain2_width;
+ chain2_height = this->chain2_height;
+ chain3_width = this->chain3_width;
+ chain3_height = this->chain3_height;
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "chain0(%d, %d), chain1(%d, %d), chain2(%d, %d)\n",
+ chain0_width, chain0_height,
+ chain1_width, chain1_height,
+ chain2_width, chain2_height);
+#endif
+#else
+ scc_param = &this->is_region->parameter.scalerc;
+ indexes = lindex = hindex = 0;
+ chain0_width = this->chain0_width;
+ chain0_height = this->chain0_height;
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "chain0(%d, %d)\n", chain0_width, chain0_height);
+#endif
+#endif
+
+ /* CHECK */
+ input_width = crop_width;
+ temp_width = crop_width + (crop_x<<1);
+ if (temp_width != chain0_width) {
+ err("input width is not valid(%d != %d)",
+ temp_width, chain0_width);
+ /* if invalid input come, dzoom is not apply and
+ shot command is sent to firmware */
+ ret = 0;
+ goto exit;
+ }
+
+ chain0_ratio_width = chain0_width;
+ chain0_ratio_height = chain0_height;
+
+#ifdef USE_ADVANCED_DZOOM
+ zoom_input = (chain0_ratio_width * 1000) / crop_width;
+ zoom_pre_max = (chain0_ratio_width * 1000) / chain1_width;
+
+ if (zoom_pre_max < 1000)
+ zoom_pre_max = 1000;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "zoom input : %d, premax-zoom : %d\n",
+ zoom_input, zoom_pre_max);
+#endif
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &this->dis.state))
+ zoom_target = (zoom_input * 91 + 34000) / 125;
+ else
+ zoom_target = zoom_input;
+
+ if (zoom_target > zoom_pre_max) {
+ zoom_pre = zoom_pre_max;
+ zoom_post = (zoom_target * 1000) / zoom_pre;
+ } else {
+ zoom_pre = zoom_target;
+ zoom_post = 1000;
+ }
+
+ /* CALCULATION */
+ temp_width = (chain0_ratio_width * 1000) / zoom_pre;
+ temp_height = (chain0_ratio_height * 1000) / zoom_pre;
+ crop_cx = (chain0_width - temp_width)>>1;
+ crop_cy = (chain0_height - temp_height)>>1;
+ crop_cwidth = chain0_width - (crop_cx<<1);
+ crop_cheight = chain0_height - (crop_cy<<1);
+
+ scc_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_param->input_crop.pos_x = crop_cx;
+ scc_param->input_crop.pos_y = crop_cy;
+ scc_param->input_crop.crop_width = crop_cwidth;
+ scc_param->input_crop.crop_height = crop_cheight;
+ scc_param->input_crop.in_width = chain0_width;
+ scc_param->input_crop.in_height = chain0_height;
+ scc_param->input_crop.out_width = chain1_width;
+ scc_param->input_crop.out_height = chain1_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ indexes++;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "pre-zoom target : %d(%d, %d, %d %d)\n",
+ zoom_pre, crop_cx, crop_cy, crop_cwidth, crop_cheight);
+#endif
+
+#ifdef SCALER_PARALLEL_MODE
+ scp_input_width = chain0_width;
+ scp_input_height = chain0_height;
+#else
+ scp_input_width = chain2_width;
+ scp_input_height = chain2_height;
+#endif
+ temp_width = (scp_input_width * 1000) / zoom_post;
+ temp_height = (scp_input_height * 1000) / zoom_post;
+ crop_px = (scp_input_width - temp_width)>>1;
+ crop_py = (scp_input_height - temp_height)>>1;
+ crop_pwidth = scp_input_width - (crop_px<<1);
+ crop_pheight = scp_input_height - (crop_py<<1);
+
+ scp_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scp_param->input_crop.pos_x = crop_px;
+ scp_param->input_crop.pos_y = crop_py;
+ scp_param->input_crop.crop_width = crop_pwidth;
+ scp_param->input_crop.crop_height = crop_pheight;
+ scp_param->input_crop.in_width = scp_input_width;
+ scp_param->input_crop.in_height = scp_input_height;
+ scp_param->input_crop.out_width = chain3_width;
+ scp_param->input_crop.out_height = chain3_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ indexes++;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "post-zoom target : %d(%d, %d, %d %d)\n",
+ zoom_post, crop_px, crop_py, crop_pwidth, crop_pheight);
+#endif
+#else
+ zoom_input = (chain0_ratio_width * 1000) / crop_width;
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &this->dis.state))
+ zoom_target = (zoom_input * 91 + 34000) / 125;
+ else
+ zoom_target = zoom_input;
+
+ temp_width = (chain0_ratio_width * 1000) / zoom_target;
+ temp_height = (chain0_ratio_height * 1000) / zoom_target;
+ crop_cx = (chain0_width - temp_width)>>1;
+ crop_cy = (chain0_height - temp_height)>>1;
+ crop_cwidth = chain0_width - (crop_cx<<1);
+ crop_cheight = chain0_height - (crop_cy<<1);
+
+ scc_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_param->input_crop.pos_x = crop_cx;
+ scc_param->input_crop.pos_y = crop_cy;
+ scc_param->input_crop.crop_width = crop_cwidth;
+ scc_param->input_crop.crop_height = crop_cheight;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ indexes++;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "zoom input : %d, zoom target : %d(%d, %d, %d %d)\n",
+ zoom_input, zoom_target,
+ crop_cx, crop_cy, crop_cwidth, crop_cheight);
+#endif
+#endif
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (ret) {
+ err("fimc_is_itf_s_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ this->crop_x = crop_cx;
+ this->crop_y = crop_cy;
+ this->crop_width = crop_cwidth;
+ this->crop_height = crop_cheight;
+ this->dzoom_width = input_width;
+
+exit:
+ return ret;
+}
+#endif
+
+#ifdef ENABLE_DRC
+static int fimc_is_ischain_drc_bypass(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ bool bypass)
+{
+ int ret = 0;
+ u32 lindex, hindex, indexes;
+ struct param_control *ctl_param;
+ u32 group_id = 0;
+ struct fimc_is_group *group;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+ group = &device->group_isp;
+ if (!group) {
+ merr("group is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group_id = GROUP_ID(GROUP_ID_3A0);
+ else
+ group_id = GROUP_ID(group->id);
+
+ lindex = hindex = indexes = 0;
+ ctl_param = fimc_is_itf_g_param(device, NULL, PARAM_DRC_CONTROL);
+
+ ret = fimc_is_itf_process_stop(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_stop is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (bypass)
+ fimc_is_subdev_drc_bypass(device, ctl_param, &lindex, &hindex, &indexes);
+ else
+ fimc_is_subdev_drc_start(device, ctl_param, &lindex, &hindex, &indexes);
+
+ /*
+ * It deleted a per-frame control at here. Because It is impossible to use
+ * DRC full_bypass with per-frame. So per-frame deleted and changed to set param
+ * control by g_param , s_param parameters to NULL.
+ */
+
+ ret = fimc_is_itf_s_param(device, NULL, lindex, hindex, indexes);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, frame, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_a_param(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_a_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_process_start(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (bypass)
+ clear_bit(FIMC_IS_SUBDEV_START, &device->drc.state);
+ else
+ set_bit(FIMC_IS_SUBDEV_START, &device->drc.state);
+
+p_err:
+ mrinfo("[DRC] bypass : %d\n", device, frame, bypass);
+ return ret;
+}
+#endif
+
+#ifdef ENABLE_TDNR
+static int fimc_is_ischain_dnr_bypass(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame,
+ bool bypass)
+{
+ int ret = 0;
+ u32 lindex, hindex, indexes;
+ struct param_control *ctl_param;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+ lindex = hindex = indexes = 0;
+ ctl_param = fimc_is_itf_g_param(device, frame, PARAM_TDNR_CONTROL);
+
+ if (bypass)
+ fimc_is_subdev_dnr_bypass(device, ctl_param, &lindex, &hindex, &indexes);
+ else
+ fimc_is_subdev_dnr_start(device, ctl_param, &lindex, &hindex, &indexes);
+
+ frame->shot->ctl.entry.lowIndexParam |= lindex;
+ frame->shot->ctl.entry.highIndexParam |= hindex;
+ ret = fimc_is_itf_s_param(device, frame, lindex, hindex, indexes);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, frame, ret);
+ goto p_err;
+ }
+
+ if (bypass)
+ clear_bit(FIMC_IS_SUBDEV_START, &device->dnr.state);
+ else
+ set_bit(FIMC_IS_SUBDEV_START, &device->dnr.state);
+
+p_err:
+ mrinfo("[DNR] bypass : %d\n", device, frame, bypass);
+ return ret;
+}
+#endif
+
+static int fimc_is_ischain_fd_bypass(struct fimc_is_device_ischain *device,
+ bool bypass)
+{
+ int ret = 0;
+ struct fd_param *fd_param;
+ struct fimc_is_subdev *fd;
+ struct fimc_is_group *group;
+ u32 indexes, lindex, hindex;
+ u32 group_id = 0;
+
+ BUG_ON(!device);
+
+ mdbgd_ischain("%s(%d)\n", device, __func__, bypass);
+
+ fd = &device->fd;
+ group = fd->group;
+ if (!group) {
+ merr("group is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ group_id |= GROUP_ID(group->id);
+ fd_param = &device->is_region->parameter.fd;
+ indexes = lindex = hindex = 0;
+
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group_id & GROUP_ID(GROUP_ID_ISP)) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group_id = GROUP_ID(GROUP_ID_3A0);
+
+ ret = fimc_is_itf_process_stop(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_stop is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (bypass) {
+ fd_param->control.cmd = CONTROL_COMMAND_STOP;
+ fd_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ } else {
+ fd_param->control.cmd = CONTROL_COMMAND_START;
+ fd_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ }
+
+ lindex |= LOWBIT_OF(PARAM_FD_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_FD_CONTROL);
+ indexes++;
+
+ fd_param->otf_input.width = device->chain3_width;
+ fd_param->otf_input.height = device->chain3_height;
+ lindex |= LOWBIT_OF(PARAM_FD_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_FD_OTF_INPUT);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(device, NULL, lindex, hindex, indexes);
+ if (ret) {
+ merr("fimc_is_itf_s_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_process_start(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (bypass) {
+ clear_bit(FIMC_IS_SUBDEV_START, &fd->state);
+ mdbgd_ischain("FD off\n", device);
+ } else {
+ set_bit(FIMC_IS_SUBDEV_START, &fd->state);
+ mdbgd_ischain("FD on\n", device);
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_3aa_open(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+ u32 group_id;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_3aa;
+ group_id = GET_3AA_ID(vctx->video);
+
+ ret = fimc_is_group_open(groupmgr,
+ group,
+ group_id,
+ device->instance,
+ vctx,
+ device,
+ fimc_is_ischain_3aa_callback);
+ if (ret)
+ merr("fimc_is_group_open is fail", device);
+
+ return ret;
+}
+
+int fimc_is_ischain_3aa_close(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!device);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_3aa;
+ leader = &group->leader;
+ queue = GET_SRC_QUEUE(vctx);
+
+ ret = fimc_is_ischain_3aa_stop(device, leader, queue);
+ if (ret)
+ merr("fimc_is_ischain_3aa_stop is fail", device);
+
+ ret = fimc_is_group_close(groupmgr, group);
+ if (ret)
+ merr("fimc_is_group_close is fail", device);
+
+ return ret;
+}
+
+int fimc_is_ischain_3aa_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!leader);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_3aa;
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ merr("already start", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_group_process_start(groupmgr, group, queue);
+ if (ret) {
+ merr("fimc_is_group_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SUBDEV_START, &leader->state);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_3aa_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!leader);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_3aa;
+
+ if (!test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ mwarn("already stop", device);
+ goto p_err;
+ }
+
+ ret = fimc_is_group_process_stop(groupmgr, group, queue);
+ if (ret) {
+ merr("fimc_is_group_process_stop is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SUBDEV_START, &leader->state);
+
+p_err:
+ info("[3A%d:D:%d] %s(%d, %d)\n", group->id, device->instance, __func__,
+ ret, atomic_read(&group->scount));
+ return ret;
+}
+
+int fimc_is_ischain_3aa_reqbufs(struct fimc_is_device_ischain *device,
+ u32 count)
+{
+ int ret = 0;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+
+ group = &device->group_3aa;
+
+ if (!count) {
+ ret = fimc_is_itf_unmap(device, GROUP_ID(group->id));
+ if (ret)
+ merr("fimc_is_itf_unmap is fail(%d)", device, ret);
+ }
+
+ return ret;
+}
+
+int fimc_is_ischain_3aa_s_format(struct fimc_is_device_ischain *device,
+ u32 width, u32 height)
+{
+ int ret = 0;
+ struct fimc_is_group *group;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!device);
+
+ group = &device->group_3aa;
+ leader = &group->leader;
+
+ leader->input.width = width;
+ leader->input.height = height;
+
+ return ret;
+}
+
+int fimc_is_ischain_3aa_s_input(struct fimc_is_device_ischain *device,
+ u32 input)
+{
+ int ret = 0;
+ u32 otf_input;
+ struct fimc_is_group *group;
+ struct fimc_is_groupmgr *groupmgr;
+
+ BUG_ON(!device);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_3aa;
+ otf_input = (input & OTF_3AA_MASK) >> OTF_3AA_SHIFT;
+
+ mdbgd_ischain("%s() calling fimc_is_group_init\n", device, __func__);
+
+ ret = fimc_is_group_init(groupmgr, group, otf_input, 0);
+ if (ret) {
+ merr("fimc_is_group_init is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_3aa_buffer_queue(struct fimc_is_device_ischain *device,
+ struct fimc_is_queue *queue,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!test_bit(FIMC_IS_ISCHAIN_OPEN, &device->state));
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s\n", device, __func__);
+#endif
+
+ groupmgr = device->groupmgr;
+ group = &device->group_3aa;
+
+ ret = fimc_is_group_buffer_queue(groupmgr, group, queue, index);
+ if (ret)
+ merr("fimc_is_group_buffer_queue is fail(%d)", device, ret);
+
+ return ret;
+}
+
+int fimc_is_ischain_3aa_buffer_finish(struct fimc_is_device_ischain *device,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s\n", device, __func__);
+#endif
+
+ groupmgr = device->groupmgr;
+ group = &device->group_3aa;
+
+ ret = fimc_is_group_buffer_finish(groupmgr, group, index);
+ if (ret)
+ merr("fimc_is_group_buffer_finish is fail(%d)", device, ret);
+
+ return ret;
+}
+
+int fimc_is_ischain_3aa_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct taa_param *taa_param;
+ u32 lindex, hindex, indexes;
+ u32 crop_x, crop_y, crop_width, crop_height;
+ u32 *input_crop;
+ u32 *output_crop;
+ u32 size_change_request = 0;
+
+ BUG_ON(!device);
+ BUG_ON(!device->is_region);
+ BUG_ON(!subdev);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!ldr_frame->shot);
+ BUG_ON(!node);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("3AA TAG(request %d)\n", device, node->request);
+#endif
+
+ lindex = hindex = indexes = 0;
+ taa_param = &device->is_region->parameter.taa;
+ input_crop = node->input.cropRegion;
+ output_crop = node->output.cropRegion;
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &device->group_3aa.state)) {
+ crop_x = taa_param->otf_input.bayer_crop_offset_x;
+ crop_y = taa_param->otf_input.bayer_crop_offset_y;
+ crop_width = taa_param->otf_input.bayer_crop_width;
+ crop_height = taa_param->otf_input.bayer_crop_height;
+ } else {
+ crop_x = taa_param->vdma1_input.bayer_crop_offset_x;
+ crop_y = taa_param->vdma1_input.bayer_crop_offset_y;
+ crop_width = taa_param->vdma1_input.bayer_crop_width;
+ crop_height = taa_param->vdma1_input.bayer_crop_height;
+ }
+
+ if (IS_NULL_COORD(input_crop)) {
+ input_crop[0] = crop_x;
+ input_crop[1] = crop_y;
+ input_crop[2] = crop_width;
+ input_crop[3] = crop_height;
+ }
+
+ if (!GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)) {
+
+ size_change_request = ((taa_param->vdma1_input.bds_out_width != output_crop[2]) ||
+ (taa_param->vdma1_input.bds_out_height != output_crop[3]) ||
+ (taa_param->vdma1_input.bayer_crop_width != input_crop[2]) ||
+ (taa_param->vdma1_input.bayer_crop_height != input_crop[3]));
+
+ if (size_change_request || device->isp_size_forceset) {
+ /*
+ * forcefully set subsequent frame 3aa sizes until firmware acknowledges the
+ * updation of the changed information
+ */
+ device->isp_size_forceset = 1;
+ if (size_change_request)
+ device->taa_size_changed_fcount = ldr_frame->fcount;
+
+ ret = fimc_is_ischain_s_3aa_size(device,
+ ldr_frame,
+ input_crop,
+ output_crop,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_3aa_size is fail(%d)", device, ret);
+ goto p_err;
+ }
+ mrdbg("[3AA] in_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ input_crop[0], input_crop[1], input_crop[2], input_crop[3]);
+ mdbg_pframe("[3AA] out_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3]);
+ }
+ } else {
+
+ size_change_request = ((input_crop[0] != crop_x) ||
+ (input_crop[1] != crop_y) ||
+ (input_crop[2] != crop_width) ||
+ (input_crop[3] != crop_height));
+
+ if (size_change_request || device->taa_size_forceset) {
+ /*
+ * forcefully set subsequent frame 3aa sizes until firmware acknowledges the
+ * updation of the changed information
+ */
+ device->taa_size_forceset = 1;
+ if (size_change_request)
+ device->taa_size_changed_fcount = ldr_frame->fcount;
+
+ ret = fimc_is_ischain_s_3aa_size(device,
+ ldr_frame,
+ input_crop,
+ output_crop,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_3aa_size is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mrdbg("[3AA] in_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ input_crop[0], input_crop[1], input_crop[2], input_crop[3]);
+ }
+ }
+
+ ldr_frame->shot->ctl.entry.lowIndexParam |= lindex;
+ ldr_frame->shot->ctl.entry.highIndexParam |= hindex;
+ ret = fimc_is_itf_s_param(device, ldr_frame, lindex, hindex, 0);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, ldr_frame, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+const struct fimc_is_queue_ops fimc_is_ischain_3aa_ops = {
+ .start_streaming = fimc_is_ischain_3aa_start,
+ .stop_streaming = fimc_is_ischain_3aa_stop
+};
+
+static int fimc_is_ischain_3aap_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ struct fimc_is_queue *queue,
+ struct taa_param *taa_param,
+ u32 *output_crop,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_dma_output *taa_vdma2_output;
+
+ if ((output_crop[2] > taa_param->otf_input.bayer_crop_width) ||
+ (output_crop[3] > taa_param->otf_input.bayer_crop_height)) {
+ mrerr("bds output size is invalid((%d, %d) > (%d, %d))", device, frame,
+ output_crop[2],
+ output_crop[3],
+ taa_param->otf_input.bayer_crop_width,
+ taa_param->otf_input.bayer_crop_height);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* HACK */
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &device->group_3aa.state)) {
+ struct param_otf_input *taa_otf_input;
+
+ taa_otf_input = fimc_is_itf_g_param(device, frame, PARAM_3AA_OTF_INPUT);
+ taa_otf_input->bds_out_enable = ISP_BDS_COMMAND_ENABLE;
+ taa_otf_input->bds_out_width = output_crop[2];
+ taa_otf_input->bds_out_height = output_crop[3];
+ *lindex |= LOWBIT_OF(PARAM_3AA_OTF_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_OTF_INPUT);
+ (*indexes)++;
+ } else {
+ struct param_dma_input *taa_dma_input;
+
+ taa_dma_input = fimc_is_itf_g_param(device, frame, PARAM_3AA_VDMA1_INPUT);
+ taa_dma_input->bds_out_enable = ISP_BDS_COMMAND_ENABLE;
+ taa_dma_input->bds_out_width = output_crop[2];
+ taa_dma_input->bds_out_height = output_crop[3];
+ *lindex |= LOWBIT_OF(PARAM_3AA_VDMA1_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_VDMA1_INPUT);
+ (*indexes)++;
+ }
+
+ taa_vdma2_output = fimc_is_itf_g_param(device, frame, PARAM_3AA_VDMA2_OUTPUT);
+ taa_vdma2_output->cmd = DMA_OUTPUT_COMMAND_ENABLE;
+ taa_vdma2_output->width = output_crop[2];
+ taa_vdma2_output->height = output_crop[3];
+ taa_vdma2_output->buffer_number = 0;
+ taa_vdma2_output->buffer_address = 0;
+ taa_vdma2_output->dma_out_mask = 0;
+ taa_vdma2_output->bitwidth = DMA_OUTPUT_BIT_WIDTH_12BIT;
+ taa_vdma2_output->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_ENBABLE;
+
+ if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+ queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR12) {
+ taa_vdma2_output->format = DMA_INPUT_FORMAT_BAYER_PACKED12;
+ } else if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR16) {
+ taa_vdma2_output->format = DMA_INPUT_FORMAT_BAYER;
+ } else {
+ mwarn("Invalid bayer format", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ *lindex |= LOWBIT_OF(PARAM_3AA_VDMA2_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_VDMA2_OUTPUT);
+ (*indexes)++;
+
+ set_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+p_err:
+ return ret;
+}
+
+
+static int fimc_is_ischain_3aap_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_dma_output *taa_vdma2_output;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+ taa_vdma2_output = fimc_is_itf_g_param(device, frame, PARAM_3AA_VDMA2_OUTPUT);
+ taa_vdma2_output->cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_3AA_VDMA2_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_VDMA2_OUTPUT);
+ (*indexes)++;
+
+ clear_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+ return ret;
+}
+
+static int fimc_is_ischain_3aap_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+ struct camera2_scaler_uctl *scalerUd;
+ struct taa_param *taa_param;
+ u32 lindex, hindex, indexes;
+ u32 *output_crop;
+
+ BUG_ON(!device);
+ BUG_ON(!device->is_region);
+ BUG_ON(!subdev);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!ldr_frame->shot);
+ BUG_ON(!node);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("3AAP TAG(request %d)\n", device, node->request);
+#endif
+
+ lindex = hindex = indexes = 0;
+ taa_param = &device->is_region->parameter.taa;
+ scalerUd = &ldr_frame->shot->uctl.scalerUd;
+ /* HACK */
+ framemgr = GET_SUBDEV_FRAMEMGR(subdev->leader);
+ if (!framemgr) {
+ merr("framemgr is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* HACK */
+ queue = GET_SUBDEV_QUEUE(subdev->leader);
+ if (!queue) {
+ merr("queue is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (node->request) {
+ output_crop = node->output.cropRegion;
+
+ if (output_crop[0] || output_crop[1]) {
+ mwarn("crop pos(%d, %d) is ignored", device,
+ output_crop[0],
+ output_crop[1]);
+ output_crop[0] = 0;
+ output_crop[1] = 0;
+ }
+
+ if (!output_crop[0] && !output_crop[1] &&
+ !output_crop[2] && !output_crop[3]) {
+ output_crop[0] = 0;
+ output_crop[1] = 0;
+ output_crop[2] = taa_param->vdma2_output.width;
+ output_crop[3] = taa_param->vdma2_output.height;
+ }
+
+ if ((output_crop[2] != taa_param->vdma2_output.width) ||
+ (output_crop[3] != taa_param->vdma2_output.height) ||
+ !test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_3aap_start(device,
+ subdev,
+ ldr_frame,
+ queue,
+ taa_param,
+ output_crop,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_3aap_start is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mdbg_pframe("[3AP] ot_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3]);
+ }
+
+ /* device address setting */
+ if (fimc_is_ischain_buf_tag(device,
+ subdev,
+ ldr_frame,
+ node,
+ queue,
+ framemgr,
+ output_crop[2], output_crop[3],
+ scalerUd->taapTargetAddress,
+ OUT_3AAP_FRAME))
+ goto p_err;
+ } else {
+ if (test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_3aap_stop(device,
+ subdev,
+ ldr_frame,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_3aap_stop is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ info("[3AP:D:%d] off, %d\n", device->instance, ldr_frame->fcount);
+ }
+
+ mwarn("3aap request is 0", device);
+ scalerUd->taapTargetAddress[0] = 0;
+ scalerUd->taapTargetAddress[1] = 0;
+ scalerUd->taapTargetAddress[2] = 0;
+ node->request = 0;
+ }
+
+ ldr_frame->shot->ctl.entry.lowIndexParam |= lindex;
+ ldr_frame->shot->ctl.entry.highIndexParam |= hindex;
+ ret = fimc_is_itf_s_param(device, ldr_frame, lindex, hindex, 0);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, ldr_frame, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_3aac_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ struct fimc_is_queue *queue,
+ struct taa_param *taa_param,
+ u32 *output_crop,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_dma_output *taa_vdma4_output;
+
+ if ((output_crop[2] != taa_param->otf_input.bayer_crop_width) ||
+ (output_crop[3] != taa_param->otf_input.bayer_crop_height)) {
+ merr("bds output size is invalid((%d, %d) != (%d, %d))", device,
+ output_crop[2],
+ output_crop[3],
+ taa_param->otf_input.bayer_crop_width,
+ taa_param->otf_input.bayer_crop_height);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ taa_vdma4_output = fimc_is_itf_g_param(device, frame, PARAM_3AA_VDMA4_OUTPUT);
+ taa_vdma4_output->cmd = DMA_OUTPUT_COMMAND_ENABLE;
+ taa_vdma4_output->width = output_crop[2];
+ taa_vdma4_output->height = output_crop[3];
+ taa_vdma4_output->buffer_number = 0;
+ taa_vdma4_output->buffer_address = 0;
+ taa_vdma4_output->dma_out_mask = 0;
+ taa_vdma4_output->bitwidth = DMA_OUTPUT_BIT_WIDTH_12BIT;
+ taa_vdma4_output->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_ENBABLE;
+
+ if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+ queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR12) {
+ taa_vdma4_output->format = DMA_INPUT_FORMAT_BAYER_PACKED12;
+ } else if (queue->framecfg.format.pixelformat == V4L2_PIX_FMT_SBGGR16) {
+ taa_vdma4_output->format = DMA_INPUT_FORMAT_BAYER;
+ } else {
+ mwarn("Invalid bayer format", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ *lindex |= LOWBIT_OF(PARAM_3AA_VDMA4_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_VDMA4_OUTPUT);
+ (*indexes)++;
+
+ set_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_3aac_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_dma_output *taa_vdma4_output;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+ taa_vdma4_output = fimc_is_itf_g_param(device, frame, PARAM_3AA_VDMA4_OUTPUT);
+ taa_vdma4_output->cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_3AA_VDMA4_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_3AA_VDMA4_OUTPUT);
+ (*indexes)++;
+
+ clear_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+ return ret;
+}
+
+static int fimc_is_ischain_3aac_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+ struct camera2_scaler_uctl *scalerUd;
+ struct taa_param *taa_param;
+ u32 lindex, hindex, indexes;
+ u32 *output_crop;
+
+ BUG_ON(!device);
+ BUG_ON(!subdev);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!ldr_frame->shot);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("3AAC TAG(request %d)\n", device, node->request);
+#endif
+
+ lindex = hindex = indexes = 0;
+ taa_param = &device->is_region->parameter.taa;
+ scalerUd = &ldr_frame->shot->uctl.scalerUd;
+ framemgr = GET_SUBDEV_FRAMEMGR(subdev);
+ if (!framemgr) {
+ merr("framemgr is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ queue = GET_SUBDEV_QUEUE(subdev);
+ if (!queue) {
+ merr("queue is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (node->request) {
+ output_crop = node->output.cropRegion;
+
+ output_crop[0] = 0;
+ output_crop[1] = 0;
+ output_crop[2] = taa_param->otf_input.bayer_crop_width;
+ output_crop[3] = taa_param->otf_input.bayer_crop_height;
+
+ if (!test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_3aac_start(device,
+ subdev,
+ ldr_frame,
+ queue,
+ taa_param,
+ output_crop,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_3aac_start is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mdbg_pframe("[3AC] ot_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3]);
+ }
+
+ /* device address setting */
+ if (fimc_is_ischain_buf_tag(device,
+ subdev,
+ ldr_frame,
+ node,
+ queue,
+ framemgr,
+ output_crop[2], output_crop[3],
+ scalerUd->taacTargetAddress,
+ OUT_3AAC_FRAME))
+ goto p_err;
+ } else {
+ if (test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_3aac_stop(device,
+ subdev,
+ ldr_frame,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_3aac_stop is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ info("[3AC:D:%d] off, %d\n", device->instance, ldr_frame->fcount);
+ }
+
+ scalerUd->taacTargetAddress[0] = 0;
+ scalerUd->taacTargetAddress[1] = 0;
+ scalerUd->taacTargetAddress[2] = 0;
+ node->request = 0;
+ }
+
+ ldr_frame->shot->ctl.entry.lowIndexParam |= lindex;
+ ldr_frame->shot->ctl.entry.highIndexParam |= hindex;
+ ret = fimc_is_itf_s_param(device, ldr_frame, lindex, hindex, 0);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, ldr_frame, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_isp_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ struct fimc_is_subdev *leader_3aa;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+#ifdef ENABLE_BAYER_CROP
+ u32 crop_x, crop_y, crop_width, crop_height;
+ u32 sensor_width, sensor_height, sensor_ratio;
+ u32 chain0_width, chain0_height, chain0_ratio;
+ u32 chain3_width, chain3_height, chain3_ratio;
+ u32 chain1_wmin, chain1_hmin;
+#endif
+ u32 input_crop[4] = {0, };
+ u32 output_crop[4] = {0, };
+ u32 lindex = 0;
+ u32 hindex = 0;
+ u32 indexes = 0;
+
+ BUG_ON(!device);
+ BUG_ON(!device->sensor);
+ BUG_ON(!queue);
+
+ mdbgd_isp("%s()\n", device, __func__);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_isp;
+ if (device->group_3aa.id == GROUP_ID_INVALID)
+ leader_3aa = NULL;
+ else
+ leader_3aa = &device->group_3aa.leader;
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ merr("already start", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* 1. check chain size */
+ if (leader_3aa && (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) ||
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1))) {
+ if (test_bit(FIMC_IS_SUBDEV_OPEN, &leader_3aa->state) &&
+ (leader_3aa->output.width != leader->input.width)) {
+ merr("width size is invalid(%d != %d)", device,
+ leader_3aa->output.width, leader->input.width);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SUBDEV_OPEN, &leader_3aa->state) &&
+ (leader_3aa->output.height != leader->input.height)) {
+ merr("height size is invalid(%d != %d)", device,
+ leader_3aa->output.height, leader->input.height);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* BDS size */
+ device->chain0_width = leader->input.width;
+ device->chain0_height = leader->input.height;
+ } else {
+ /* BDS size */
+ device->chain0_width = leader->input.width - device->margin_width;
+ device->chain0_height = leader->input.height - device->margin_height;
+ }
+
+ device->dzoom_width = 0;
+ device->bds_width = 0;
+ device->bds_height = 0;
+#ifdef ENABLE_BAYER_CROP
+ /* 2. crop calculation */
+ sensor_width = device->sensor_width;
+ sensor_height = device->sensor_height;
+ chain3_width = device->chain3_width;
+ chain3_height = device->chain3_height;
+ crop_width = sensor_width;
+ crop_height = sensor_height;
+ crop_x = crop_y = 0;
+
+ sensor_ratio = sensor_width * 1000 / sensor_height;
+ chain3_ratio = chain3_width * 1000 / chain3_height;
+
+ if (sensor_ratio == chain3_ratio) {
+ crop_width = sensor_width;
+ crop_height = sensor_height;
+ } else if (sensor_ratio < chain3_ratio) {
+ /*
+ * isp dma input limitation
+ * height : 2 times
+ */
+ crop_height =
+ (sensor_width * chain3_height) / chain3_width;
+ crop_height = ALIGN(crop_height, 2);
+ crop_y = ((sensor_height - crop_height) >> 1) & 0xFFFFFFFE;
+ } else {
+ /*
+ * isp dma input limitation
+ * width : 4 times
+ */
+ crop_width =
+ (sensor_height * chain3_width) / chain3_height;
+ crop_width = ALIGN(crop_width, 4);
+ crop_x = ((sensor_width - crop_width) >> 1) & 0xFFFFFFFE;
+ }
+ device->chain0_width = crop_width;
+ device->chain0_height = crop_height;
+
+ device->dzoom_width = crop_width;
+ device->crop_width = crop_width;
+ device->crop_height = crop_height;
+ device->crop_x = crop_x;
+ device->crop_y = crop_y;
+
+ dbg_isp("crop_x : %d, crop y : %d\n", crop_x, crop_y);
+ dbg_isp("crop width : %d, crop height : %d\n",
+ crop_width, crop_height);
+
+ /* 2. scaling calculation */
+ chain1_wmin = (crop_width >> 4) & 0xFFFFFFFE;
+ chain1_hmin = (crop_height >> 4) & 0xFFFFFFFE;
+
+ if (chain1_wmin > device->chain1_width) {
+ printk(KERN_INFO "scc down scale limited : (%d,%d)->(%d,%d)\n",
+ device->chain1_width, device->chain1_height,
+ chain1_wmin, chain1_hmin);
+ device->chain1_width = chain1_wmin;
+ device->chain1_height = chain1_hmin;
+ device->chain2_width = chain1_wmin;
+ device->chain2_height = chain1_hmin;
+ }
+#endif
+
+ fimc_is_ischain_s_sensor(device, &lindex, &hindex, &indexes);
+
+ /* init value: perframe parameters are not set before stream on. */
+ input_crop[0] = 0;
+ input_crop[1] = 0;
+ input_crop[2] = fimc_is_sensor_g_bns_width(device->sensor) - device->margin_width;
+ input_crop[3] = fimc_is_sensor_g_bns_height(device->sensor) - device->margin_height;
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)) {
+ /*
+ * In case of dirty bayer capture, reprocessing instance does not use 3aa.
+ * In this case, ischain device has no 3aa group.
+ */
+ if (leader_3aa && test_bit(FIMC_IS_SUBDEV_OPEN, &leader_3aa->state))
+ fimc_is_ischain_s_3aa_size(device, NULL, input_crop,
+ output_crop, &lindex, &hindex, &indexes);
+ } else {
+ output_crop[0] = 0;
+ output_crop[1] = 0;
+ output_crop[2] = device->chain0_width;
+ output_crop[3] = device->chain0_height;
+
+ fimc_is_ischain_s_3aa_size(device, NULL, input_crop,
+ output_crop, &lindex, &hindex, &indexes);
+ }
+
+ fimc_is_ischain_s_chain0_size(device,
+ NULL, device->chain0_width, device->chain0_height,
+ &lindex, &hindex, &indexes);
+
+ fimc_is_ischain_s_chain1_size(device,
+ device->chain1_width, device->chain1_height,
+ &lindex, &hindex, &indexes);
+
+ fimc_is_ischain_s_chain2_size(device,
+ NULL, device->chain2_width, device->chain2_height,
+ &lindex, &hindex, &indexes);
+
+ fimc_is_ischain_s_chain3_size(device,
+ NULL, device->chain3_width, device->chain3_height,
+ &lindex, &hindex, &indexes);
+
+ info("[3AA:D:%d] 3AA in size(%d x %d)\n", device->instance, input_crop[2], input_crop[3]);
+ info("[ISC:D:%d] BDS out to SCC in size(%d x %d)\n", device->instance,
+ device->chain0_width, device->chain0_height);
+ info("[ISC:D:%d] SCC out to DIS in size(%d x %d)\n", device->instance,
+ device->chain1_width, device->chain1_height);
+ info("[ISC:D:%d] DIS out to SCP in size(%d x %d)\n", device->instance,
+ device->chain2_width, device->chain2_height);
+ info("[ISC:D:%d] SCP out to FD in size(%d x %d)\n", device->instance,
+ device->chain3_width, device->chain3_height);
+
+
+ fimc_is_ischain_s_path(device, &lindex, &hindex, &indexes);
+
+ fimc_is_ischain_s_color_range(device, device->color_range, &lindex, &hindex, &indexes);
+
+ if (test_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state))
+ fimc_is_itf_sensor_mode(device);
+
+ lindex = 0xFFFFFFFF;
+ hindex = 0xFFFFFFFF;
+ indexes = 64;
+
+ ret = fimc_is_itf_s_param(device , NULL, lindex, hindex, indexes);
+ if (ret) {
+ merr("fimc_is_itf_s_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_f_param(device);
+ if (ret) {
+ merr("fimc_is_itf_f_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_sys_ctl(device, IS_SYS_CLOCK_GATE, sysfs_debug.clk_gate_mode);
+ if (ret) {
+ merr("fimc_is_itf_sys_ctl is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /*
+ * this code is enabled when camera 2.0 feature is enabled
+ * ret = fimc_is_itf_g_capability(device);
+ * if (ret) {
+ * err("fimc_is_itf_g_capability is fail\n");
+ * ret = -EINVAL;
+ * goto p_err;
+ *}
+ */
+
+ ret = fimc_is_itf_init_process_start(device);
+ if (ret) {
+ merr("fimc_is_itf_init_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_group_process_start(groupmgr, group, queue);
+ if (ret) {
+ merr("fimc_is_group_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SUBDEV_START, &leader->state);
+ set_bit(FIMC_IS_ISHCAIN_START, &device->state);
+
+p_err:
+ info("[ISP:D:%d] %s(%d)\n", device->instance, __func__, ret);
+ return ret;
+}
+
+int fimc_is_ischain_isp_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!leader);
+ BUG_ON(!queue);
+
+ mdbgd_isp("%s\n", device, __func__);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_isp;
+
+ if (!test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ mwarn("already stop", device);
+ goto p_err;
+ }
+
+ ret = fimc_is_group_process_stop(groupmgr, group, queue);
+ if (ret) {
+ merr("fimc_is_group_process_stop is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SUBDEV_START, &leader->state);
+ clear_bit(FIMC_IS_ISHCAIN_START, &device->state);
+
+p_err:
+ info("[ISP:D:%d] %s(%d, %d)\n", device->instance, __func__,
+ ret, atomic_read(&group->scount));
+ return ret;
+}
+
+int fimc_is_ischain_isp_reqbufs(struct fimc_is_device_ischain *device,
+ u32 count)
+{
+ int ret = 0;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+
+ group = &device->group_isp;
+
+ if (!count) {
+ ret = fimc_is_itf_unmap(device, GROUP_ID(group->id));
+ if (ret)
+ merr("fimc_is_itf_unmap is fail(%d)", device, ret);
+ }
+
+ return ret;
+}
+
+int fimc_is_ischain_isp_s_format(struct fimc_is_device_ischain *device,
+ u32 width, u32 height)
+{
+ int ret = 0;
+ struct fimc_is_group *group;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!device);
+
+ group = &device->group_isp;
+ subdev = &group->leader;
+
+ subdev->input.width = width;
+ subdev->input.height = height;
+
+ return ret;
+}
+
+int fimc_is_ischain_isp_s_input(struct fimc_is_device_ischain *device,
+ u32 input)
+{
+ int ret = 0;
+ struct fimc_is_group *group;
+ struct fimc_is_groupmgr *groupmgr;
+ u32 tax_vindex;
+
+ BUG_ON(!device);
+
+ group = &device->group_isp;
+ groupmgr = device->groupmgr;
+ tax_vindex = (input & TAX_VINDEX_MASK) >> TAX_VINDEX_SHIFT;
+
+
+ /* checking 3ax group connection */
+ if ((GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == true) ||
+ (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == true)) {
+ if (!((tax_vindex == FIMC_IS_VIDEO_3A0C_NUM) ||
+ (tax_vindex == FIMC_IS_VIDEO_3A0P_NUM) ||
+ (tax_vindex == FIMC_IS_VIDEO_3A1C_NUM) ||
+ (tax_vindex == FIMC_IS_VIDEO_3A1P_NUM))) {
+ merr("TAX_VINDEX(%d) is invalid", device, tax_vindex);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ }
+
+ mdbgd_ischain("%s() calling fimc_is_group_init\n", device, __func__);
+
+ ret = fimc_is_group_init(groupmgr, group, false, tax_vindex);
+ if (ret) {
+ merr("fimc_is_group_init is fail", device);
+ ret = -EINVAL;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_isp_buffer_queue(struct fimc_is_device_ischain *device,
+ struct fimc_is_queue *queue,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!test_bit(FIMC_IS_ISCHAIN_OPEN, &device->state));
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s\n", device, __func__);
+#endif
+
+ groupmgr = device->groupmgr;
+ group = &device->group_isp;
+
+ ret = fimc_is_group_buffer_queue(groupmgr, group, queue, index);
+ if (ret) {
+ merr("fimc_is_group_buffer_queue is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_isp_buffer_finish(struct fimc_is_device_ischain *device,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s\n", device, __func__);
+#endif
+
+ groupmgr = device->groupmgr;
+ group = &device->group_isp;
+
+ ret = fimc_is_group_buffer_finish(groupmgr, group, index);
+ if (ret)
+ merr("fimc_is_group_buffer_finish is fail(%d)", device, ret);
+
+ return ret;
+}
+
+int fimc_is_ischain_isp_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct isp_param *isp_param;
+ u32 lindex, hindex, indexes;
+ u32 *input_crop;
+ u32 *output_crop;
+ u32 size_change_request = 0;
+
+ BUG_ON(!device);
+ BUG_ON(!device->is_region);
+ BUG_ON(!subdev);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!ldr_frame->shot);
+ BUG_ON(!node);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("ISP TAG(request %d)\n", device, node->request);
+#endif
+
+ lindex = hindex = indexes = 0;
+ isp_param = &device->is_region->parameter.isp;
+ input_crop = node->input.cropRegion;
+ output_crop = node->output.cropRegion;
+
+ if (!GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)) {
+ if (IS_NULL_COORD(output_crop)) {
+ output_crop[0] = 0;
+ output_crop[1] = 0;
+ output_crop[2] = isp_param->otf_output.width;
+ output_crop[3] = isp_param->otf_output.height;
+ }
+
+ size_change_request = ((output_crop[2] != isp_param->otf_output.width) ||
+ (output_crop[3] != isp_param->otf_output.height));
+
+ if (size_change_request || device->isp_size_forceset) {
+ device->isp_size_forceset = 1;
+ if (size_change_request)
+ device->isp_size_changed_fcount = ldr_frame->fcount;
+
+ ret = fimc_is_ischain_s_chain0_size(device,
+ ldr_frame,
+ output_crop[2],
+ output_crop[3],
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_s_chain0_size is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mrinfo("[ISP] out_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3]);
+ }
+ } else {
+ if (IS_NULL_COORD(input_crop)) {
+ input_crop[0] = 0;
+ input_crop[1] = 0;
+ input_crop[2] = isp_param->vdma1_input.width;
+ input_crop[3] = isp_param->vdma1_input.height;
+ }
+
+ size_change_request = ((input_crop[2] != isp_param->vdma1_input.width) ||
+ (input_crop[3] != isp_param->vdma1_input.height));
+
+ if (size_change_request || device->isp_size_forceset) {
+
+ device->isp_size_forceset = 1;
+ if (size_change_request)
+ device->isp_size_changed_fcount = ldr_frame->fcount;
+
+ ret = fimc_is_ischain_s_chain0_size(device,
+ ldr_frame,
+ input_crop[2],
+ input_crop[3],
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_s_chain0_size is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mrdbg("[ISP] in_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ input_crop[0], input_crop[1], input_crop[2], input_crop[3]);
+ }
+ }
+
+ ldr_frame->shot->ctl.entry.lowIndexParam |= lindex;
+ ldr_frame->shot->ctl.entry.highIndexParam |= hindex;
+ ret = fimc_is_itf_s_param(device, ldr_frame, lindex, hindex, 0);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, ldr_frame, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+const struct fimc_is_queue_ops fimc_is_ischain_isp_ops = {
+ .start_streaming = fimc_is_ischain_isp_start,
+ .stop_streaming = fimc_is_ischain_isp_stop
+};
+
+static int fimc_is_ischain_scc_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ struct fimc_is_queue *queue,
+ struct scalerc_param *scc_param,
+ u32 *input_crop,
+ u32 *output_crop,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ u32 planes, i, j, buf_index;
+ struct param_dma_output *scc_dma_output;
+ struct param_otf_output *scc_otf_output;
+ struct param_scaler_input_crop *scc_input_crop;
+ struct param_scaler_output_crop *scc_output_crop;
+#ifndef SCALER_PARALLEL_MODE
+ struct param_otf_input *scp_otf_input;
+#endif
+
+ if (output_crop[2] > scc_param->otf_input.width * MAX_ZOOM_LEVEL) {
+ mwarn("Cannot be scaled up beyond %d times(%d -> %d)",
+ device, MAX_ZOOM_LEVEL, scc_param->otf_input.width, output_crop[2]);
+ output_crop[2] = scc_param->otf_input.width * MAX_ZOOM_LEVEL;
+ }
+
+ if (output_crop[3] > scc_param->otf_input.height * MAX_ZOOM_LEVEL) {
+ mwarn("Cannot be scaled up beyond %d times(%d -> %d)",
+ device, MAX_ZOOM_LEVEL, scc_param->otf_input.height, output_crop[3]);
+ output_crop[3] = scc_param->otf_input.height * MAX_ZOOM_LEVEL;
+ }
+
+ if (output_crop[2] < (scc_param->otf_input.width + 15) / 16) {
+ mwarn("Cannot be scaled down beyond 1/16 times(%d -> %d)",
+ device, scc_param->otf_input.width, output_crop[2]);
+ output_crop[2] = (scc_param->otf_input.width + 15) / 16;
+ }
+
+ if (output_crop[3] < (scc_param->otf_input.height + 15) / 16) {
+ mwarn("Cannot be scaled down beyond 1/16 times(%d -> %d)",
+ device, scc_param->otf_input.height, output_crop[3]);
+ output_crop[3] = (scc_param->otf_input.height + 15) / 16;
+ }
+
+ planes = queue->framecfg.format.num_planes;
+ for (i = 0; i < queue->buf_maxcount; i++) {
+ for (j = 0; j < planes; j++) {
+ buf_index = i*planes + j;
+ device->is_region->shared[447+buf_index] = queue->buf_dva[i][j];
+ }
+ }
+
+ mdbgd_ischain("buf_num:%d buf_plane:%d shared[447] : 0x%X\n",
+ device,
+ queue->buf_maxcount,
+ queue->framecfg.format.num_planes,
+ device->imemory.kvaddr_shared + 447 * sizeof(u32));
+
+ /* setting always although otf output is not used. */
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ scc_otf_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_OTF_OUTPUT);
+ scc_otf_output->width = output_crop[2];
+ scc_otf_output->height = output_crop[3];
+ } else {
+ scc_otf_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_OTF_OUTPUT);
+#ifdef SCALER_PARALLEL_MODE
+ scc_otf_output->width = output_crop[2];
+ scc_otf_output->height = output_crop[3];
+#else
+ scp_otf_input = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_OTF_INPUT);
+ scc_otf_output->width = scp_otf_input->width;
+ scc_otf_output->height = scp_otf_input->height;
+#endif
+ }
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ (*indexes)++;
+
+ scc_input_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_INPUT_CROP);
+ scc_input_crop->cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_input_crop->pos_x = input_crop[0];
+ scc_input_crop->pos_y = input_crop[1];
+ scc_input_crop->crop_width = input_crop[2];
+ scc_input_crop->crop_height = input_crop[3];
+ scc_input_crop->in_width = scc_param->otf_input.width;
+ scc_input_crop->in_height = scc_param->otf_input.height;
+ scc_input_crop->out_width = output_crop[2];
+ scc_input_crop->out_height = output_crop[3];
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ (*indexes)++;
+
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ scc_output_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_OUTPUT_CROP);
+ scc_output_crop->cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_output_crop->pos_x = output_crop[0];
+ scc_output_crop->pos_y = output_crop[1];
+ scc_output_crop->crop_width = output_crop[2];
+ scc_output_crop->crop_height = output_crop[3];
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ (*indexes)++;
+
+ scc_dma_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_DMA_OUTPUT);
+ scc_dma_output->cmd = DMA_OUTPUT_COMMAND_ENABLE;
+ scc_dma_output->buffer_number = queue->buf_maxcount;
+ scc_dma_output->plane = queue->framecfg.format.num_planes - 1;
+ scc_dma_output->buffer_address = device->imemory.dvaddr_shared + 447*sizeof(u32);
+ scc_dma_output->width = output_crop[2];
+ scc_dma_output->height = output_crop[3];
+ scc_dma_output->reserved[0] = SCALER_DMA_OUT_SCALED;
+ } else {
+ scc_output_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_OUTPUT_CROP);
+ scc_output_crop->cmd = SCALER_CROP_COMMAND_DISABLE;
+ scc_output_crop->pos_x = output_crop[0];
+ scc_output_crop->pos_y = output_crop[1];
+ scc_output_crop->crop_width = output_crop[2];
+ scc_output_crop->crop_height = output_crop[3];
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ (*indexes)++;
+
+ scc_dma_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_DMA_OUTPUT);
+ scc_dma_output->cmd = DMA_OUTPUT_COMMAND_ENABLE;
+ scc_dma_output->buffer_number = queue->buf_maxcount;
+ scc_dma_output->plane = queue->framecfg.format.num_planes - 1;
+ scc_dma_output->buffer_address = device->imemory.dvaddr_shared + 447*sizeof(u32);
+#ifdef SCALER_PARALLEL_MODE
+ scc_dma_output->width = output_crop[2];
+ scc_dma_output->height = output_crop[3];
+ scc_dma_output->reserved[0] = SCALER_DMA_OUT_SCALED;
+#else
+ scc_dma_output->width = input_crop[2];
+ scc_dma_output->height = input_crop[3];
+ scc_dma_output->reserved[0] = SCALER_DMA_OUT_UNSCALED;
+#endif
+ }
+
+ switch (queue->framecfg.format.pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ scc_dma_output->format = DMA_OUTPUT_FORMAT_YUV422,
+ scc_dma_output->plane = DMA_OUTPUT_PLANE_1;
+ scc_dma_output->order = DMA_OUTPUT_ORDER_CrYCbY;
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV21:
+ scc_dma_output->format = OTF_OUTPUT_FORMAT_YUV420,
+ scc_dma_output->plane = DMA_OUTPUT_PLANE_2;
+ scc_dma_output->order = DMA_OUTPUT_ORDER_CbCr;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV12:
+ scc_dma_output->format = OTF_OUTPUT_FORMAT_YUV420,
+ scc_dma_output->plane = DMA_OUTPUT_PLANE_2;
+ scc_dma_output->order = DMA_OUTPUT_ORDER_CrCb;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ scc_dma_output->format = OTF_OUTPUT_FORMAT_YUV420,
+ scc_dma_output->plane = DMA_OUTPUT_PLANE_3;
+ scc_dma_output->order = DMA_OUTPUT_ORDER_NO;
+ break;
+ default:
+ mwarn("unknown preview pixelformat", device);
+ break;
+ }
+
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ (*indexes)++;
+
+ set_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+ return ret;
+}
+
+static int fimc_is_ischain_scc_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ struct scalerc_param *scc_param,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_dma_output *scc_dma_output;
+ struct param_scaler_input_crop *scc_input_crop;
+ struct param_otf_output *scc_otf_output;
+ struct param_scaler_output_crop *scc_output_crop;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+ scc_dma_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_DMA_OUTPUT);
+ scc_dma_output->cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ (*indexes)++;
+
+ /* If SCC output size is bigger than input,
+ * it takes more time for scale up processing.
+ */
+ scc_input_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_INPUT_CROP);
+ scc_input_crop->out_width = device->chain1_width;
+ scc_input_crop->out_height = device->chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ (*indexes)++;
+
+ /* Even if SCC otf output path is not used,
+ * otf output size should be same with input crop output size.
+ * Otherwise, scaler hang can be induced at digital zoom scenario.
+ */
+ scc_otf_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_OTF_OUTPUT);
+ scc_otf_output->width = device->chain1_width;
+ scc_otf_output->height = device->chain1_height;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ (*indexes)++;
+
+ scc_output_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERC_OUTPUT_CROP);
+ scc_output_crop->cmd = SCALER_CROP_COMMAND_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ (*indexes)++;
+
+ clear_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+ return ret;
+}
+
+static int fimc_is_ischain_scc_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+ struct camera2_scaler_uctl *scalerUd;
+ struct scalerc_param *scc_param;
+ u32 lindex, hindex, indexes;
+ u32 *input_crop, *output_crop;
+ u32 dma_width, dma_height;
+
+ BUG_ON(!device);
+ BUG_ON(!subdev);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!ldr_frame->shot);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("SCC TAG(request %d)\n", device, node->request);
+#endif
+
+ lindex = hindex = indexes = 0;
+ scc_param = &device->is_region->parameter.scalerc;
+ scalerUd = &ldr_frame->shot->uctl.scalerUd;
+ framemgr = GET_SUBDEV_FRAMEMGR(subdev);
+ if (!framemgr) {
+ merr("framemgr is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ queue = GET_SUBDEV_QUEUE(subdev);
+ if (!queue) {
+ merr("queue is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (node->request) {
+ input_crop = node->input.cropRegion;
+ output_crop = node->output.cropRegion;
+
+ if (!input_crop[0] && !input_crop[1] &&
+ !input_crop[2] && !input_crop[3]) {
+ input_crop[0] = scc_param->input_crop.pos_x;
+ input_crop[1] = scc_param->input_crop.pos_y;
+ input_crop[2] = scc_param->input_crop.crop_width;
+ input_crop[3] = scc_param->input_crop.crop_height;
+ }
+
+ if (!output_crop[0] && !output_crop[1] &&
+ !output_crop[2] && !output_crop[3]) {
+ output_crop[0] = scc_param->output_crop.pos_x;
+ output_crop[1] = scc_param->output_crop.pos_y;
+ output_crop[2] = scc_param->output_crop.crop_width;
+ output_crop[3] = scc_param->output_crop.crop_height;
+ }
+
+ if ((input_crop[0] != scc_param->input_crop.pos_x) ||
+ (input_crop[1] != scc_param->input_crop.pos_y) ||
+ (input_crop[2] != scc_param->input_crop.crop_width) ||
+ (input_crop[3] != scc_param->input_crop.crop_height) ||
+ (output_crop[0] != scc_param->output_crop.pos_x) ||
+ (output_crop[1] != scc_param->output_crop.pos_y) ||
+ (output_crop[2] != scc_param->output_crop.crop_width) ||
+ (output_crop[3] != scc_param->output_crop.crop_height) ||
+ (input_crop[2] != scc_param->dma_output.width) ||
+ (input_crop[3] != scc_param->dma_output.height) ||
+ !test_bit(FIMC_IS_SUBDEV_START, &subdev->state) ||
+ device->isp_size_forceset) {
+
+ ret = fimc_is_ischain_scc_start(device,
+ subdev,
+ ldr_frame,
+ queue,
+ scc_param,
+ input_crop,
+ output_crop,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_scc_start is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mdbg_pframe("[SCC] in_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ input_crop[0], input_crop[1], input_crop[2], input_crop[3]);
+ mdbg_pframe("[SCC] ot_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3]);
+ }
+
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) {
+ dma_width = node->output.cropRegion[2];
+ dma_height = node->output.cropRegion[3];
+ } else {
+#ifdef SCALER_PARALLEL_MODE
+ dma_width = node->output.cropRegion[2];
+ dma_height = node->output.cropRegion[3];
+#else
+ /* in scaler serial mode, use input crop w/h for dma size */
+ dma_width = node->input.cropRegion[2];
+ dma_height = node->input.cropRegion[3];
+#endif
+ }
+ /* device address setting */
+ if (fimc_is_ischain_buf_tag(device,
+ subdev,
+ ldr_frame,
+ node,
+ queue,
+ framemgr,
+ dma_width, dma_height,
+ scalerUd->sccTargetAddress,
+ OUT_SCC_FRAME))
+ goto p_err;
+
+ } else {
+ if (test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_scc_stop(device,
+ subdev,
+ ldr_frame,
+ scc_param,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_scc_stop is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ info("[SCC:D:%d] off, %d\n", device->instance, ldr_frame->fcount);
+ }
+
+ scalerUd->sccTargetAddress[0] = 0;
+ scalerUd->sccTargetAddress[1] = 0;
+ scalerUd->sccTargetAddress[2] = 0;
+ node->request = 0;
+ }
+
+ ldr_frame->shot->ctl.entry.lowIndexParam |= lindex;
+ ldr_frame->shot->ctl.entry.highIndexParam |= hindex;
+ ret = fimc_is_itf_s_param(device, ldr_frame, lindex, hindex, 0);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, ldr_frame, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_scp_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ struct fimc_is_queue *queue,
+ struct scalerp_param *scp_param,
+ u32 *input_crop,
+ u32 *output_crop,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ u32 planes, i, j, buf_index;
+ struct param_dma_output *scp_dma_output;
+ struct param_scaler_input_crop *scp_input_crop;
+ struct param_scaler_output_crop *scp_output_crop;
+
+ fimc_is_ischain_scp_adjust_crop(device, scp_param, &output_crop[2], &output_crop[3]);
+
+ planes = queue->framecfg.format.num_planes;
+ for (i = 0; i < queue->buf_maxcount; i++) {
+ for (j = 0; j < planes; j++) {
+ buf_index = i*planes + j;
+ device->is_region->shared[400 + buf_index] = queue->buf_dva[i][j];
+ }
+ }
+
+ mdbgd_ischain("buf_num:%d buf_plane:%d shared[400] : 0x%X\n",
+ device,
+ queue->buf_maxcount,
+ queue->framecfg.format.num_planes,
+ device->imemory.kvaddr_shared + 400 * sizeof(u32));
+
+ scp_input_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_INPUT_CROP);
+ scp_input_crop->cmd = SCALER_CROP_COMMAND_ENABLE;
+ scp_input_crop->pos_x = input_crop[0];
+ scp_input_crop->pos_y = input_crop[1];
+ scp_input_crop->crop_width = input_crop[2];
+ scp_input_crop->crop_height = input_crop[3];
+#ifdef SCALER_PARALLEL_MODE
+ scp_input_crop->in_width = device->bds_width;
+ scp_input_crop->in_height = device->bds_height;
+ scp_input_crop->out_width = output_crop[2];
+ scp_input_crop->out_height = output_crop[3];
+#else
+ scp_input_crop->in_width = scp_param->otf_input.width;
+ scp_input_crop->in_height = scp_param->otf_input.height;
+ scp_input_crop->out_width = scp_param->otf_output.width;
+ scp_input_crop->out_height = scp_param->otf_output.height;
+#endif
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ (*indexes)++;
+
+ /*
+ * scaler can't apply stride to each plane, only y plane.
+ * basically cb, cr plane should be half of y plane,
+ * and it's automatically set
+ *
+ * 3 plane : all plane should be 8 or 16 stride
+ * 2 plane : y plane should be 32, 16 stride, others should be half stride of y
+ * 1 plane : all plane should be 8 stride
+ */
+ /*
+ * limitation of output_crop.pos_x and pos_y
+ * YUV422 3P, YUV420 3P : pos_x and pos_y should be x2
+ * YUV422 1P : pos_x should be x2
+ */
+ scp_output_crop = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_OUTPUT_CROP);
+ scp_output_crop->cmd = SCALER_CROP_COMMAND_ENABLE;
+ scp_output_crop->pos_x = output_crop[0];
+ scp_output_crop->pos_y = output_crop[1];
+ scp_output_crop->crop_width = output_crop[2];
+ scp_output_crop->crop_height = output_crop[3];
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ (*indexes)++;
+
+ scp_dma_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_DMA_OUTPUT);
+ scp_dma_output->cmd = DMA_OUTPUT_COMMAND_ENABLE;
+ scp_dma_output->buffer_number = queue->buf_maxcount;
+ scp_dma_output->plane = queue->framecfg.format.num_planes - 1;
+ scp_dma_output->buffer_address = device->imemory.dvaddr_shared + 400 * sizeof(u32);
+ scp_dma_output->width = output_crop[2];
+ scp_dma_output->height = output_crop[3];
+
+ switch (queue->framecfg.format.pixelformat) {
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ scp_dma_output->format = OTF_OUTPUT_FORMAT_YUV420,
+ scp_dma_output->plane = DMA_OUTPUT_PLANE_3;
+ scp_dma_output->order = DMA_OUTPUT_ORDER_NO;
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV21:
+ scp_dma_output->format = OTF_OUTPUT_FORMAT_YUV420,
+ scp_dma_output->plane = DMA_OUTPUT_PLANE_2;
+ scp_dma_output->order = DMA_OUTPUT_ORDER_CbCr;
+ break;
+ default:
+ mwarn("unknown preview pixelformat", device);
+ break;
+ }
+
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ (*indexes)++;
+
+ set_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+ return ret;
+}
+
+static int fimc_is_ischain_scp_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *frame,
+ struct scalerp_param *scp_param,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct param_dma_output *scp_dma_output;
+
+ mdbgd_ischain("%s\n", device, __func__);
+
+ scp_dma_output = fimc_is_itf_g_param(device, frame, PARAM_SCALERP_DMA_OUTPUT);
+ scp_dma_output->cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ (*indexes)++;
+
+ clear_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+ return ret;
+}
+
+int fimc_is_ischain_scp_s_format(struct fimc_is_device_ischain *device,
+ u32 pixelformat, u32 width, u32 height)
+{
+ int ret = 0;
+
+ /* check scaler size limitation */
+ switch (pixelformat) {
+ /*
+ * YUV422 1P, YUV422 2P : x8
+ * YUV422 3P : x16
+ */
+ case V4L2_PIX_FMT_YUV422P:
+ if (width % 8) {
+ merr("width(%d) of format(%d) is not supported size",
+ device, width, pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ break;
+ /*
+ * YUV420 2P : x8
+ * YUV420 3P : x16
+ */
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ if (width % 8) {
+ merr("width(%d) of format(%d) is not supported size",
+ device, width, pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ if (width % 16) {
+ merr("width(%d) of format(%d) is not supported size",
+ device, width, pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ break;
+ default:
+ merr("format(%d) is not supported", device, pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ break;
+ }
+
+ device->chain1_width = width;
+ device->chain1_height = height;
+ device->chain2_width = width;
+ device->chain2_height = height;
+ device->chain3_width = width;
+ device->chain3_height = height;
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_scp_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+ struct camera2_scaler_uctl *scalerUd;
+ struct scalerp_param *scp_param;
+ u32 lindex, hindex, indexes;
+ u32 *input_crop, *output_crop;
+
+ BUG_ON(!device);
+ BUG_ON(!subdev);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!ldr_frame->shot);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("SCP TAG(request %d)\n", device, node->request);
+#endif
+
+ lindex = hindex = indexes = 0;
+ scp_param = &device->is_region->parameter.scalerp;
+ scalerUd = &ldr_frame->shot->uctl.scalerUd;
+ framemgr = GET_SUBDEV_FRAMEMGR(subdev);
+ if (!framemgr) {
+ merr("framemgr is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ queue = GET_SUBDEV_QUEUE(subdev);
+ if (!queue) {
+ merr("queue is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (node->request) {
+ input_crop = node->input.cropRegion;
+ output_crop = node->output.cropRegion;
+
+ if (!input_crop[0] && !input_crop[1] &&
+ !input_crop[2] && !input_crop[3]) {
+ input_crop[0] = scp_param->input_crop.pos_x;
+ input_crop[1] = scp_param->input_crop.pos_y;
+ input_crop[2] = scp_param->input_crop.crop_width;
+ input_crop[3] = scp_param->input_crop.crop_height;
+ }
+
+ if (!output_crop[0] && !output_crop[1] &&
+ !output_crop[2] && !output_crop[3]) {
+ output_crop[0] = scp_param->output_crop.pos_x;
+ output_crop[1] = scp_param->output_crop.pos_y;
+ output_crop[2] = scp_param->output_crop.crop_width;
+ output_crop[3] = scp_param->output_crop.crop_height;
+ }
+
+ if ((input_crop[0] != scp_param->input_crop.pos_x) ||
+ (input_crop[1] != scp_param->input_crop.pos_y) ||
+ (input_crop[2] != scp_param->input_crop.crop_width) ||
+ (input_crop[3] != scp_param->input_crop.crop_height) ||
+ (output_crop[0] != scp_param->output_crop.pos_x) ||
+ (output_crop[1] != scp_param->output_crop.pos_y) ||
+ (output_crop[2] != scp_param->output_crop.crop_width) ||
+ (output_crop[3] != scp_param->output_crop.crop_height) ||
+ !test_bit(FIMC_IS_SUBDEV_START, &subdev->state) ||
+ device->isp_size_forceset) {
+#ifdef SCALER_PARALLEL_MODE
+ ret = fimc_is_ischain_s_chain2_size(device,
+ ldr_frame,
+ input_crop[2],
+ input_crop[3],
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_s_chain2_size is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_s_chain3_size(device,
+ ldr_frame,
+ output_crop[2],
+ output_crop[3],
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_s_chain3_size is fail(%d)", device, ret);
+ goto p_err;
+ }
+ mrinfo("[SCPX] xx_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3]);
+
+#endif
+ ret = fimc_is_ischain_scp_start(device,
+ subdev,
+ ldr_frame,
+ queue,
+ scp_param,
+ input_crop,
+ output_crop,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_scp_start is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mdbg_pframe("[SCP] in_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ input_crop[0], input_crop[1], input_crop[2], input_crop[3]);
+ mdbg_pframe("[SCP] ot_crop[%d, %d, %d, %d]\n", device, ldr_frame,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3]);
+ }
+
+ /* device address setting */
+ if (fimc_is_ischain_buf_tag(device,
+ subdev,
+ ldr_frame,
+ node,
+ queue,
+ framemgr,
+ output_crop[2], output_crop[3],
+ scalerUd->scpTargetAddress,
+ OUT_SCP_FRAME))
+ goto p_err;
+ } else {
+ if (test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_scp_stop(device,
+ subdev,
+ ldr_frame,
+ scp_param,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_scp_stop is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ info("[SCP:D:%d] off, %d\n", device->instance, ldr_frame->fcount);
+ }
+
+ scalerUd->scpTargetAddress[0] = 0;
+ scalerUd->scpTargetAddress[1] = 0;
+ scalerUd->scpTargetAddress[2] = 0;
+ node->request = 0;
+ }
+
+ ldr_frame->shot->ctl.entry.lowIndexParam |= lindex;
+ ldr_frame->shot->ctl.entry.highIndexParam |= hindex;
+ ret = fimc_is_itf_s_param(device, ldr_frame, lindex, hindex, 0);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, ldr_frame, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_dis_start(struct fimc_is_device_ischain *device,
+ bool bypass)
+{
+ int ret = 0;
+ u32 group_id = 0;
+ struct dis_param *dis_param;
+ u32 chain1_width, chain1_height;
+ u32 indexes, lindex, hindex;
+
+ struct fimc_is_group *group;
+ struct fimc_is_groupmgr *groupmgr;
+
+ mdbgd_ischain("%s()\n", device, __func__);
+
+ BUG_ON(!device);
+
+ chain1_width = device->dis_width;
+ chain1_height = device->dis_height;
+ indexes = lindex = hindex = 0;
+ dis_param = &device->is_region->parameter.dis;
+ group_id |= GROUP_ID(device->group_isp.id);
+ group_id |= GROUP_ID(device->group_dis.id);
+
+ group = &device->group_dis;
+ groupmgr = device->groupmgr;
+
+ mdbgd_ischain("%s() calling fimc_is_group_init\n", device, __func__);
+
+ ret = fimc_is_group_init(groupmgr, group, false, 0);
+ if (ret) {
+ merr("fimc_is_group_init is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_process_stop(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_stop is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_ischain_s_chain1_size(device,
+ chain1_width, chain1_height, &lindex, &hindex, &indexes);
+
+ if (bypass)
+ fimc_is_subdev_dis_bypass(device,
+ dis_param, &lindex, &hindex, &indexes);
+ else
+ fimc_is_subdev_dis_start(device,
+ dis_param, &lindex, &hindex, &indexes);
+
+ ret = fimc_is_itf_s_param(device, NULL, lindex, hindex, indexes);
+ if (ret) {
+ merr("fimc_is_itf_s_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_a_param(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_a_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_process_start(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SUBDEV_START, &device->dis.state);
+ mdbgd_ischain("DIS on\n", device);
+
+ device->chain1_width = chain1_width;
+ device->chain1_height = chain1_height;
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_dis_stop(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ u32 group_id = 0;
+ struct dis_param *dis_param;
+ u32 chain1_width, chain1_height;
+ u32 indexes, lindex, hindex;
+
+ mdbgd_ischain("%s()\n", device, __func__);
+
+ chain1_width = device->chain2_width;
+ chain1_height = device->chain2_height;
+ indexes = lindex = hindex = 0;
+ dis_param = &device->is_region->parameter.dis;
+ group_id |= GROUP_ID(device->group_isp.id);
+ group_id |= GROUP_ID(device->group_dis.id);
+
+ ret = fimc_is_itf_process_stop(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_stop is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_ischain_s_chain1_size(device,
+ chain1_width, chain1_height, &lindex, &hindex, &indexes);
+
+ fimc_is_subdev_dis_bypass(device,
+ dis_param, &lindex, &hindex, &indexes);
+
+ ret = fimc_is_itf_s_param(device, NULL, lindex, hindex, indexes);
+ if (ret) {
+ merr("fimc_is_itf_s_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_a_param(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_a_param is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ group_id = GROUP_ID(device->group_isp.id);
+ ret = fimc_is_itf_process_start(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SUBDEV_START, &device->dis.state);
+ mdbgd_ischain("DIS off\n", device);
+
+ device->chain1_width = chain1_width;
+ device->chain1_height = chain1_height;
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_dis_tag(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_frame *ldr_frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct fimc_is_framemgr *framemgr;
+ struct camera2_scaler_uctl *scalerUd;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!device);
+ BUG_ON(!subdev);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!ldr_frame->shot);
+
+ scalerUd = &ldr_frame->shot->uctl.scalerUd;
+
+ queue = GET_SUBDEV_QUEUE(subdev);
+ if (!queue) {
+ merr("queue is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr = GET_SUBDEV_FRAMEMGR(subdev);
+ if (!framemgr) {
+ merr("framemgr is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (node->request) {
+ if (!test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_dis_start(device,
+ ldr_frame->shot_ext->dis_bypass);
+ if (ret) {
+ merr("vdisc_start is fail", device);
+ goto p_err;
+ }
+ }
+
+ /* device address setting */
+ if (fimc_is_ischain_buf_tag(device,
+ subdev,
+ ldr_frame,
+ node,
+ queue,
+ framemgr,
+ device->chain1_width, device->chain1_height,
+ scalerUd->disTargetAddress,
+ OUT_DIS_FRAME))
+ goto p_err;
+ } else {
+ if (test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ ret = fimc_is_ischain_dis_stop(device);
+ if (ret) {
+ merr("vdisc_stop is fail", device);
+ goto p_err;
+ }
+ }
+
+ scalerUd->disTargetAddress[0] = 0;
+ scalerUd->disTargetAddress[1] = 0;
+ scalerUd->disTargetAddress[2] = 0;
+ node->request = 0;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_vdc_s_format(struct fimc_is_device_ischain *device,
+ u32 width, u32 height)
+{
+ int ret = 0;
+
+ device->dis_width = width;
+ device->dis_height = height;
+
+ return ret;
+}
+
+int fimc_is_ischain_vdo_open(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_dis;
+
+ ret = fimc_is_group_open(groupmgr, group, GROUP_ID_DIS,
+ device->instance, vctx, device, fimc_is_ischain_dis_callback);
+ if (ret)
+ merr("fimc_is_group_open is fail", device);
+
+ return ret;
+}
+
+int fimc_is_ischain_vdo_close(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!device);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_dis;
+ leader = &group->leader;
+ queue = GET_SRC_QUEUE(vctx);
+
+ ret = fimc_is_ischain_vdo_stop(device, leader, queue);
+ if (ret)
+ merr("fimc_is_ischain_vdo_stop is fail", device);
+
+ ret = fimc_is_group_close(groupmgr, group);
+ if (ret)
+ merr("fimc_is_group_close is fail", device);
+
+ return ret;
+}
+
+int fimc_is_ischain_vdo_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!leader);
+ BUG_ON(!queue);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_dis;
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ merr("already start", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_group_process_start(groupmgr, group, queue);
+ if (ret) {
+ merr("fimc_is_group_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SUBDEV_START, &leader->state);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_vdo_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!leader);
+ BUG_ON(!queue);
+
+ groupmgr = device->groupmgr;
+ group = &device->group_dis;
+
+ if (!test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ mwarn("already stop", device);
+ goto p_err;
+ }
+
+ ret = fimc_is_group_process_stop(groupmgr, group, queue);
+ if (ret) {
+ merr("fimc_is_group_process_start is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_process_stop(device, GROUP_ID_DIS);
+ if (ret) {
+ merr("fimc_is_itf_process_stop is fail", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SUBDEV_START, &leader->state);
+
+p_err:
+ info("[DIS:D:%d] %s(%d, %d)\n", device->instance, __func__,
+ ret, atomic_read(&group->scount));
+ return ret;
+}
+
+int fimc_is_ischain_vdo_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height)
+{
+ int ret = 0;
+
+ return ret;
+}
+
+int fimc_is_ischain_vdo_buffer_queue(struct fimc_is_device_ischain *device,
+ struct fimc_is_queue *queue,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+ BUG_ON(!test_bit(FIMC_IS_ISCHAIN_OPEN, &device->state));
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s\n", device, __func__);
+#endif
+
+ groupmgr = device->groupmgr;
+ group = &device->group_dis;
+
+ ret = fimc_is_group_buffer_queue(groupmgr, group, queue, index);
+ if (ret) {
+ merr("fimc_is_group_buffer_queue is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ischain_vdo_buffer_finish(struct fimc_is_device_ischain *device,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+
+ BUG_ON(!device);
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s\n", device, __func__);
+#endif
+
+ groupmgr = device->groupmgr;
+ group = &device->group_dis;
+
+ ret = fimc_is_group_buffer_finish(groupmgr, group, index);
+ if (ret)
+ merr("fimc_is_group_buffer_finish is fail(%d)", device, ret);
+
+ return ret;
+}
+
+const struct fimc_is_queue_ops fimc_is_ischain_vdo_ops = {
+ .start_streaming = fimc_is_ischain_vdo_start,
+ .stop_streaming = fimc_is_ischain_vdo_stop
+};
+
+int fimc_is_ischain_g_capability(struct fimc_is_device_ischain *this,
+ u32 user_ptr)
+{
+ int ret = 0;
+
+ ret = copy_to_user((void *)user_ptr, &this->capability,
+ sizeof(struct camera2_sm));
+
+ return ret;
+}
+
+int fimc_is_ischain_print_status(struct fimc_is_device_ischain *device)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_subdev *isp;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_interface *itf;
+
+ isp = &device->group_isp.leader;
+ vctx = isp->vctx;
+ framemgr = GET_SRC_FRAMEMGR(vctx);
+ itf = device->interface;
+
+ fimc_is_frame_print_free_list(framemgr);
+ fimc_is_frame_print_request_list(framemgr);
+ fimc_is_frame_print_process_list(framemgr);
+ fimc_is_frame_print_complete_list(framemgr);
+
+ return ret;
+}
+
+int fimc_is_ischain_3aa_callback(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *check_frame)
+{
+ int ret = 0;
+ u32 capture_id, group_id;
+ unsigned long flags;
+ struct fimc_is_group *group;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ struct fimc_is_subdev *leader, *taac, *taap, *scc, *dis, *scp;
+ struct camera2_node *node, *leader_node;
+
+#ifdef ENABLE_FAST_SHOT
+ uint32_t af_trigger_bk;
+ enum aa_capture_intent captureIntent_bk;
+#endif
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s()\n", device, __func__);
+#endif
+
+ BUG_ON(!device);
+ BUG_ON(!check_frame);
+
+ group = &device->group_3aa;
+ group_id = GROUP_ID(group->id);
+ leader = &group->leader;
+ framemgr = GET_LEADER_FRAMEMGR(leader);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+
+ if (unlikely(!frame)) {
+ merr("frame is NULL", device);
+ return -EINVAL;
+ }
+
+ if (unlikely(frame != check_frame)) {
+ merr("frame checking is fail(%X != %X)", device,
+ (u32)frame, (u32)check_frame);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (unlikely(!frame->shot)) {
+ merr("frame->shot is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (unlikely(!test_bit(FRAME_MAP_MEM, &frame->memory))) {
+ fimc_is_itf_map(device, group_id, frame->dvaddr_shot, frame->shot_size);
+ set_bit(FRAME_MAP_MEM, &frame->memory);
+ }
+
+ frame->shot->ctl.entry.lowIndexParam = 0;
+ frame->shot->ctl.entry.highIndexParam = 0;
+ frame->shot->dm.entry.lowIndexParam = 0;
+ frame->shot->dm.entry.highIndexParam = 0;
+ leader_node = &frame->shot_ext->node_group.leader;
+
+#ifdef ENABLE_SETFILE
+ if (frame->shot_ext->setfile != device->setfile) {
+ unsigned int setfile = frame->shot_ext->setfile;
+ ret = fimc_is_ischain_chg_setfile(device, setfile);
+ if (ret) {
+ err("fimc_is_ischain_chg_setfile is fail");
+ goto p_err;
+ }
+ }
+#endif
+
+#ifdef ENABLE_FAST_SHOT
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ af_trigger_bk = frame->shot->ctl.aa.afTrigger;
+ captureIntent_bk = frame->shot->ctl.aa.captureIntent;
+ memcpy(&frame->shot->ctl.aa, &group->fast_ctl.aa,
+ sizeof(struct camera2_aa_ctl));
+ memcpy(&frame->shot->ctl.scaler, &group->fast_ctl.scaler,
+ sizeof(struct camera2_scaler_ctl));
+ frame->shot->ctl.aa.afTrigger = af_trigger_bk;
+ frame->shot->ctl.aa.captureIntent = captureIntent_bk;
+ }
+#endif
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ enum aa_capture_intent captureIntent;
+ captureIntent = group->intent_ctl.aa.captureIntent;
+
+ if (captureIntent != AA_CAPTURE_INTENT_CUSTOM) {
+ frame->shot->ctl.aa.captureIntent = captureIntent;
+ group->intent_ctl.aa.captureIntent = AA_CAPTURE_INTENT_CUSTOM;
+ }
+ }
+
+ ret = fimc_is_ischain_3aa_tag(device, leader, frame, leader_node);
+ if (ret) {
+ merr("fimc_is_ischain_3aa_tag is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ for (capture_id = 0; capture_id < CAPTURE_NODE_MAX; ++capture_id) {
+ node = &frame->shot_ext->node_group.capture[capture_id];
+ taac = taap = scc = dis = scp = NULL;
+
+ switch (node->vid) {
+ case 0:
+ break;
+ case FIMC_IS_VIDEO_3A0C_NUM:
+ case FIMC_IS_VIDEO_3A1C_NUM:
+ taac = group->subdev[ENTRY_3AAC];
+ break;
+ case FIMC_IS_VIDEO_3A0P_NUM:
+ case FIMC_IS_VIDEO_3A1P_NUM:
+ taap = group->subdev[ENTRY_3AAP];
+ break;
+ case FIMC_IS_VIDEO_SCC_NUM:
+ scc = group->subdev[ENTRY_SCALERC];
+ break;
+ case FIMC_IS_VIDEO_VDC_NUM:
+ dis = group->subdev[ENTRY_DIS];
+ break;
+ case FIMC_IS_VIDEO_SCP_NUM:
+ scp = group->subdev[ENTRY_SCALERP];
+ break;
+ default:
+ merr("capture0 vid(%d) is invalid", device, node->vid);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (taac) {
+ ret = fimc_is_ischain_3aac_tag(device, taac, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_3aac_tag is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ if (taap) {
+ ret = fimc_is_ischain_3aap_tag(device, taap, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_3aap_tag is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ if (scc) {
+ ret = fimc_is_ischain_scc_tag(device, scc, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_scc_tag fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ if (dis) {
+ ret = fimc_is_ischain_dis_tag(device, dis, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_dis_tag fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ if (scp) {
+ ret = fimc_is_ischain_scp_tag(device, scp, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_scp_tag fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+ }
+
+p_err:
+ if (ret) {
+ merr("3aa shot(index : %d) is skipped(error : %d)", device,
+ frame->index, ret);
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ set_bit(REQ_3AA_SHOT, &frame->req_flag);
+ fimc_is_itf_grp_shot(device, group, frame);
+ }
+
+ return ret;
+}
+
+int fimc_is_ischain_isp_callback(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *check_frame)
+{
+ int ret = 0;
+ u32 capture_id, group_id;
+ unsigned long flags;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ struct fimc_is_subdev *leader, *scc, *dis, *dnr, *scp, *fd;
+ struct camera2_node *node, *leader_node;
+
+ BUG_ON(!device);
+ BUG_ON(!check_frame);
+ BUG_ON(device->instance_sensor >= FIMC_IS_MAX_NODES);
+
+#ifdef DBG_STREAMING
+ mdbgd_isp("%s\n", device, __func__);
+#endif
+
+ groupmgr = device->groupmgr;
+ group = &device->group_isp;
+ group_id = GROUP_ID(group->id);
+ leader = &group->leader;
+ dnr = group->subdev[ENTRY_TDNR];
+ fd = group->subdev[ENTRY_LHFD];
+ framemgr = GET_LEADER_FRAMEMGR(leader);
+
+ /*
+ BE CAREFUL WITH THIS
+ 1. buffer queue, all compoenent stop, so it's good
+ 2. interface callback, all component will be stop until new one is came
+ therefore, i expect lock object is not necessary in here
+ */
+
+ BUG_ON(!framemgr);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+
+ if (unlikely(!frame)) {
+ merr("frame is NULL", device);
+ return -EINVAL;
+ }
+
+ if (unlikely(frame != check_frame)) {
+ merr("frame checking is fail(%X != %X)", device,
+ (u32)frame, (u32)check_frame);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (unlikely(!frame->shot)) {
+ merr("frame->shot is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* HACK */
+ if ((GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0) &&
+ (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0))
+ group_id = GROUP_ID(GROUP_ID_3A0);
+
+ if (unlikely(!test_bit(FRAME_MAP_MEM, &frame->memory))) {
+ fimc_is_itf_map(device, group_id, frame->dvaddr_shot, frame->shot_size);
+ set_bit(FRAME_MAP_MEM, &frame->memory);
+ }
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0) {
+ frame->shot->uctl.scalerUd.taapTargetAddress[0] =
+ frame->dvaddr_buffer[0];
+ frame->shot->uctl.scalerUd.taapTargetAddress[1] = 0;
+ frame->shot->uctl.scalerUd.taapTargetAddress[2] = 0;
+ }
+
+ frame->shot->ctl.entry.lowIndexParam = 0;
+ frame->shot->ctl.entry.highIndexParam = 0;
+ frame->shot->dm.entry.lowIndexParam = 0;
+ frame->shot->dm.entry.highIndexParam = 0;
+ leader_node = &frame->shot_ext->node_group.leader;
+
+#ifdef ENABLE_SETFILE
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0) {
+ if (frame->shot_ext->setfile != device->setfile) {
+ unsigned int setfile = frame->shot_ext->setfile;
+ ret = fimc_is_ischain_chg_setfile(device, setfile);
+ if (ret) {
+ err("fimc_is_ischain_chg_setfile is fail");
+ goto p_err;
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_DRC
+ if (frame->shot_ext->drc_bypass) {
+ if (test_bit(FIMC_IS_SUBDEV_START, &device->drc.state)) {
+ ret = fimc_is_ischain_drc_bypass(device, frame, true);
+ if (ret) {
+ err("fimc_is_ischain_drc_bypass(1) is fail");
+ goto p_err;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_SUBDEV_START, &device->drc.state)) {
+ ret = fimc_is_ischain_drc_bypass(device, frame, false);
+ if (ret) {
+ err("fimc_is_ischain_drc_bypass(0) is fail");
+ goto p_err;
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_TDNR
+ if (dnr) {
+ if (frame->shot_ext->dnr_bypass) {
+ if (test_bit(FIMC_IS_SUBDEV_START, &dnr->state)) {
+ ret = fimc_is_ischain_dnr_bypass(device, frame, true);
+ if (ret) {
+ merr("dnr_bypass(1) is fail", device);
+ goto p_err;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_SUBDEV_START, &dnr->state)) {
+ ret = fimc_is_ischain_dnr_bypass(device, frame, false);
+ if (ret) {
+ merr("dnr_bypass(0) is fail", device);
+ goto p_err;
+ }
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_FD
+ if (fd) {
+ if (frame->shot_ext->fd_bypass) {
+ if (test_bit(FIMC_IS_SUBDEV_START, &fd->state)) {
+ ret = fimc_is_ischain_fd_bypass(device, true);
+ if (ret) {
+ merr("fd_bypass(1) is fail", device);
+ goto p_err;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_SUBDEV_START, &fd->state)) {
+ ret = fimc_is_ischain_fd_bypass(device, false);
+ if (ret) {
+ merr("fd_bypass(0) is fail", device);
+ goto p_err;
+ }
+ }
+ }
+ }
+#endif
+
+#ifdef SCALER_CROP_DZOOM
+ crop_width = frame->shot->ctl.scaler.cropRegion[2];
+ /* Digital zoom is not supported in multiple sensor mode */
+ if (crop_width && (crop_width != device->dzoom_width)) {
+ ret = fimc_is_ischain_s_dzoom(device,
+ frame->shot->ctl.scaler.cropRegion[0],
+ frame->shot->ctl.scaler.cropRegion[1],
+ frame->shot->ctl.scaler.cropRegion[2]);
+ if (ret) {
+ err("fimc_is_ischain_s_dzoom(%d, %d, %d) is fail",
+ frame->shot->ctl.scaler.cropRegion[0],
+ frame->shot->ctl.scaler.cropRegion[1],
+ frame->shot->ctl.scaler.cropRegion[2]);
+ goto exit;
+ }
+ }
+#endif
+
+ if (!GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)) {
+ ret = fimc_is_ischain_3aa_tag(device, leader, frame, leader_node);
+ if (ret) {
+ merr("fimc_is_ischain_3aa_tag is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ ret = fimc_is_ischain_isp_tag(device, leader, frame, leader_node);
+ if (ret) {
+ merr("fimc_is_ischain_isp_tag is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ for (capture_id = 0; capture_id < CAPTURE_NODE_MAX; ++capture_id) {
+ node = &frame->shot_ext->node_group.capture[capture_id];
+ scc = dis = scp = NULL;
+
+ switch (node->vid) {
+ case 0:
+ break;
+ case FIMC_IS_VIDEO_SCC_NUM:
+ scc = group->subdev[ENTRY_SCALERC];
+ break;
+ case FIMC_IS_VIDEO_VDC_NUM:
+ dis = group->subdev[ENTRY_DIS];
+ break;
+ case FIMC_IS_VIDEO_SCP_NUM:
+ scp = group->subdev[ENTRY_SCALERP];
+ break;
+ case FIMC_IS_VIDEO_3A0C_NUM:
+ case FIMC_IS_VIDEO_3A1C_NUM:
+ case FIMC_IS_VIDEO_3A0P_NUM:
+ case FIMC_IS_VIDEO_3A1P_NUM:
+ default:
+ merr("capture0 vid(%d) is invalid", device, node->vid);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (scc) {
+ ret = fimc_is_ischain_scc_tag(device, scc, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_scc_tag fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ if (dis) {
+ ret = fimc_is_ischain_dis_tag(device, dis, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_dis_tag fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ if (scp) {
+ ret = fimc_is_ischain_scp_tag(device, scp, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_scp_tag fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+ }
+
+#ifdef PRINT_PARAM
+ if (frame->fcount == 1) {
+ fimc_is_hw_memdump(device->interface,
+ (u32) &device->is_region->parameter,
+ (u32) &device->is_region->parameter + sizeof(device->is_region->parameter));
+ }
+#endif
+
+p_err:
+ if (ret) {
+ merr("isp shot(index : %d) is skipped(error : %d)",
+ device, frame->index, ret);
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ set_bit(REQ_ISP_SHOT, &frame->req_flag);
+ fimc_is_itf_grp_shot(device, group, frame);
+ }
+
+ return ret;
+}
+
+int fimc_is_ischain_dis_callback(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *check_frame)
+{
+ int ret = 0;
+ unsigned long flags;
+ u32 capture_id;
+ bool dis_req, scp_req;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_group *group;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ struct fimc_is_subdev *leader, *dnr, *scp, *fd;
+ struct camera2_node *node;
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s()\n", device, __func__);
+#endif
+
+ BUG_ON(!device);
+ BUG_ON(!check_frame);
+
+ group = &device->group_dis;
+ vctx = group->leader.vctx;
+ framemgr = GET_SRC_FRAMEMGR(vctx);
+ dis_req = scp_req = false;
+ leader = &group->leader;
+ dnr = group->subdev[ENTRY_TDNR];
+ fd = group->subdev[ENTRY_LHFD];
+
+ fimc_is_frame_request_head(framemgr, &frame);
+
+ if (frame != check_frame) {
+ merr("grp_frame is invalid(%X != %X)", device,
+ (u32)frame, (u32)check_frame);
+ return -EINVAL;
+ }
+
+ frame->shot->ctl.entry.lowIndexParam = 0;
+ frame->shot->ctl.entry.highIndexParam = 0;
+ frame->shot->dm.entry.lowIndexParam = 0;
+ frame->shot->dm.entry.highIndexParam = 0;
+
+#ifdef ENABLE_TDNR
+ if (dnr) {
+ if (frame->shot_ext->dnr_bypass) {
+ if (test_bit(FIMC_IS_SUBDEV_START, &dnr->state)) {
+ ret = fimc_is_ischain_dnr_bypass(device, frame, true);
+ if (ret) {
+ merr("dnr_bypass(1) is fail", device);
+ goto p_err;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_SUBDEV_START, &dnr->state)) {
+ ret = fimc_is_ischain_dnr_bypass(device, frame, false);
+ if (ret) {
+ merr("dnr_bypass(0) is fail", device);
+ goto p_err;
+ }
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_FD
+ if (fd) {
+ if (frame->shot_ext->fd_bypass) {
+ if (test_bit(FIMC_IS_SUBDEV_START, &fd->state)) {
+ ret = fimc_is_ischain_fd_bypass(device, true);
+ if (ret) {
+ merr("fd_bypass(1) is fail", device);
+ goto p_err;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_SUBDEV_START, &fd->state)) {
+ ret = fimc_is_ischain_fd_bypass(device, false);
+ if (ret) {
+ merr("fd_bypass(0) is fail", device);
+ goto p_err;
+ }
+ }
+ }
+ }
+#endif
+
+ for (capture_id = 0; capture_id < CAPTURE_NODE_MAX; ++capture_id) {
+ node = &frame->shot_ext->node_group.capture[capture_id];
+ scp = NULL;
+
+ switch (node->vid) {
+ case 0:
+ break;
+ case FIMC_IS_VIDEO_SCP_NUM:
+ scp = group->subdev[ENTRY_SCALERP];
+ break;
+ case FIMC_IS_VIDEO_SCC_NUM:
+ case FIMC_IS_VIDEO_VDC_NUM:
+ case FIMC_IS_VIDEO_3A0C_NUM:
+ case FIMC_IS_VIDEO_3A1C_NUM:
+ case FIMC_IS_VIDEO_3A0P_NUM:
+ case FIMC_IS_VIDEO_3A1P_NUM:
+ default:
+ merr("capture0 vid(%d) is invalid", device, node->vid);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (scp) {
+ ret = fimc_is_ischain_scp_tag(device, scp, frame, node);
+ if (ret) {
+ merr("fimc_is_ischain_scp_tag fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+ }
+
+p_err:
+ if (ret) {
+ err("dis shot(index : %d) is skipped(error : %d)",
+ frame->index, ret);
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ set_bit(REQ_DIS_SHOT, &frame->req_flag);
+ fimc_is_itf_grp_shot(device, group, frame);
+ }
+
+ return ret;
+}
+
+int fimc_is_ischain_camctl(struct fimc_is_device_ischain *this,
+ struct fimc_is_frame *frame,
+ u32 fcount)
+{
+ int ret = 0;
+#ifdef ENABLE_SENSOR_DRIVER
+ struct fimc_is_interface *itf;
+ struct camera2_uctl *applied_ctl;
+
+ struct camera2_sensor_ctl *isp_sensor_ctl;
+ struct camera2_lens_ctl *isp_lens_ctl;
+ struct camera2_flash_ctl *isp_flash_ctl;
+
+ u32 index;
+
+#ifdef DBG_STREAMING
+ mdbgd_ischain("%s()\n", device, __func__);
+#endif
+
+ itf = this->interface;
+ isp_sensor_ctl = &itf->isp_peri_ctl.sensorUd.ctl;
+ isp_lens_ctl = &itf->isp_peri_ctl.lensUd.ctl;
+ isp_flash_ctl = &itf->isp_peri_ctl.flashUd.ctl;
+
+ /*lens*/
+ index = (fcount + 0) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->lensUd.ctl.focusDistance = isp_lens_ctl->focusDistance;
+
+ /*sensor*/
+ index = (fcount + 1) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->sensorUd.ctl.exposureTime = isp_sensor_ctl->exposureTime;
+ applied_ctl->sensorUd.ctl.frameDuration = isp_sensor_ctl->frameDuration;
+ applied_ctl->sensorUd.ctl.sensitivity = isp_sensor_ctl->sensitivity;
+
+ /*flash*/
+ index = (fcount + 0) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->flashUd.ctl.flashMode = isp_flash_ctl->flashMode;
+ applied_ctl->flashUd.ctl.firingPower = isp_flash_ctl->firingPower;
+ applied_ctl->flashUd.ctl.firingTime = isp_flash_ctl->firingTime;
+#endif
+ return ret;
+}
+
+int fimc_is_ischain_tag(struct fimc_is_device_ischain *ischain,
+ struct fimc_is_frame *frame)
+{
+ int ret = 0;
+#ifdef ENABLE_SENSOR_DRIVER
+ struct camera2_uctl *applied_ctl;
+ struct timeval curtime;
+ u32 fcount;
+
+ fcount = frame->fcount;
+ applied_ctl = &ischain->peri_ctls[fcount & SENSOR_MAX_CTL_MASK];
+
+ do_gettimeofday(&curtime);
+
+ /* Request */
+ frame->shot->dm.request.frameCount = fcount;
+
+ /* Lens */
+ frame->shot->dm.lens.focusDistance =
+ applied_ctl->lensUd.ctl.focusDistance;
+
+ /* Sensor */
+ frame->shot->dm.sensor.exposureTime =
+ applied_ctl->sensorUd.ctl.exposureTime;
+ frame->shot->dm.sensor.sensitivity =
+ applied_ctl->sensorUd.ctl.sensitivity;
+ frame->shot->dm.sensor.frameDuration =
+ applied_ctl->sensorUd.ctl.frameDuration;
+ frame->shot->dm.sensor.timeStamp =
+ (uint64_t)curtime.tv_sec*1000000 + curtime.tv_usec;
+
+ /* Flash */
+ frame->shot->dm.flash.flashMode =
+ applied_ctl->flashUd.ctl.flashMode;
+ frame->shot->dm.flash.firingPower =
+ applied_ctl->flashUd.ctl.firingPower;
+ frame->shot->dm.flash.firingTime =
+ applied_ctl->flashUd.ctl.firingTime;
+#else
+ struct timespec curtime;
+
+ do_posix_clock_monotonic_gettime(&curtime);
+
+ frame->shot->dm.request.frameCount = frame->fcount;
+ frame->shot->dm.sensor.timeStamp = fimc_is_get_timestamp();
+#endif
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_ISCHAIN_H
+#define FIMC_IS_DEVICE_ISCHAIN_H
+
+#include <linux/pm_qos.h>
+
+#include "fimc-is-mem.h"
+#include "fimc-is-subdev-ctrl.h"
+#include "fimc-is-groupmgr.h"
+#include "fimc-is-resourcemgr.h"
+
+#define SENSOR_MAX_CTL 0x10
+#define SENSOR_MAX_CTL_MASK (SENSOR_MAX_CTL-1)
+
+#define REPROCESSING_FLAG 0x80000000
+#define REPROCESSING_MASK 0xF0000000
+#define REPROCESSING_SHIFT 28
+#define OTF_3AA_MASK 0x0F000000
+#define OTF_3AA_SHIFT 24
+#define SSX_VINDEX_MASK 0x00FF0000
+#define SSX_VINDEX_SHIFT 16
+#define TAX_VINDEX_MASK 0x0000FF00
+#define TAX_VINDEX_SHIFT 8
+#define MODULE_MASK 0x000000FF
+
+#define FIMC_IS_SETFILE_MASK 0x0000FFFF
+#define FIMC_IS_ISP_CRANGE_MASK 0x0F000000
+#define FIMC_IS_ISP_CRANGE_SHIFT 24
+#define FIMC_IS_SCC_CRANGE_MASK 0x00F00000
+#define FIMC_IS_SCC_CRANGE_SHIFT 20
+#define FIMC_IS_SCP_CRANGE_MASK 0x000F0000
+#define FIMC_IS_SCP_CRANGE_SHIFT 16
+#define FIMC_IS_CRANGE_FULL 0
+#define FIMC_IS_CRANGE_LIMITED 1
+
+#if defined(CONFIG_SOC_EXYNOS5422)
+#define FIMC_IS_SPI_PINNAME "14000000.pinctrl"
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+#define FIMC_IS_SPI_PINNAME "14cc0000.pinctrl"
+#endif
+#define FIMC_IS_SPI_OUTPUT 1
+#define FIMC_IS_SPI_FUNC 2
+
+/*global state*/
+enum fimc_is_ischain_state {
+ FIMC_IS_ISCHAIN_OPEN,
+ FIMC_IS_ISCHAIN_LOADED,
+ FIMC_IS_ISCHAIN_POWER_ON,
+ FIMC_IS_ISCHAIN_OPEN_SENSOR,
+ FIMC_IS_ISHCAIN_START,
+ FIMC_IS_ISCHAIN_REPROCESSING,
+};
+
+enum fimc_is_camera_device {
+ CAMERA_SINGLE_REAR,
+ CAMERA_SINGLE_FRONT,
+};
+
+#ifdef CONFIG_COMPANION_USE
+enum fimc_is_companion_sensor {
+ COMPANION_SENSOR_2P2 = 1,
+ COMPANION_SENSOR_IMX240 = 2,
+};
+#endif
+
+struct fimc_is_from_info {
+ u32 bin_start_addr;
+ u32 bin_end_addr;
+ u32 oem_start_addr;
+ u32 oem_end_addr;
+ u32 awb_start_addr;
+ u32 awb_end_addr;
+ u32 shading_start_addr;
+ u32 shading_end_addr;
+ u32 setfile_start_addr;
+ u32 setfile_end_addr;
+#ifdef CONFIG_COMPANION_USE
+ u32 concord_master_setfile_start_addr;
+ u32 concord_master_setfile_end_addr;
+ u32 concord_mode_setfile_start_addr;
+ u32 concord_mode_setfile_end_addr;
+ u32 lsc_gain_start_addr;
+ u32 lsc_gain_end_addr;
+ u32 pdaf_start_addr;
+ u32 pdaf_end_addr;
+ u32 coefficient_cal_start_addr;
+ u32 coefficient_cal_end_addr;
+ u32 pdaf_cal_start_addr;
+ u32 pdaf_cal_end_addr;
+ u32 concord_cal_start_addr;
+ u32 concord_cal_end_addr;
+ u32 concord_bin_start_addr;
+ u32 concord_bin_end_addr;
+ u32 lsc_i0_gain_addr;
+ u32 lsc_j0_gain_addr;
+ u32 lsc_a_gain_addr;
+ u32 lsc_k4_gain_addr;
+ u32 lsc_scale_gain_addr;
+ u32 wcoefficient1_addr;
+ u32 coef1_start;
+ u32 coef1_end;
+ u32 coef2_start;
+ u32 coef2_end;
+ u32 coef3_start;
+ u32 coef3_end;
+ u32 coef4_start;
+ u32 coef4_end;
+ u32 coef5_start;
+ u32 coef5_end;
+ u32 coef6_start;
+ u32 coef6_end;
+ u32 af_inf_addr;
+ u32 af_macro_addr;
+ u32 lsc_gain_crc_addr;
+ u32 pdaf_crc_addr;
+ u32 coef1_crc_addr;
+ u32 coef2_crc_addr;
+ u32 coef3_crc_addr;
+ u32 coef4_crc_addr;
+ u32 coef5_crc_addr;
+ u32 coef6_crc_addr;
+ char concord_header_ver[12];
+ bool is_c1_caldata_read;
+ char load_c1_fw_name[50];
+ char load_c1_mastersetf_name[50];
+ char load_c1_modesetf_name[50];
+ int sensor_id;
+#endif
+ char header_ver[12];
+ char cal_map_ver[4];
+ char setfile_ver[7];
+ char oem_ver[12];
+ char awb_ver[12];
+ char shading_ver[12];
+ char load_fw_name[50];
+ char load_setfile_name[50];
+ char project_name[9];
+ bool is_caldata_read;
+};
+
+#ifdef CONFIG_OIS_USE
+struct fimc_is_ois_info {
+ char header_ver[7];
+ char load_fw_name[50];
+};
+#endif
+
+struct fimc_is_ishcain_mem {
+ /* buffer base */
+ dma_addr_t base;
+ /* total length */
+ size_t size;
+ /* buffer base */
+ dma_addr_t vaddr_base;
+ /* current addr */
+ dma_addr_t vaddr_curr;
+ void *fw_cookie;
+
+ /* fw memory base */
+ u32 dvaddr;
+ u32 kvaddr;
+ /* debug part of fw memory */
+ u32 dvaddr_debug;
+ u32 kvaddr_debug;
+ /* is region part of fw memory */
+ u32 offset_region;
+ u32 dvaddr_region;
+ u32 kvaddr_region;
+ /* shared part of is region */
+ u32 offset_shared;
+ u32 dvaddr_shared;
+ u32 kvaddr_shared;
+ /* internal memory for ODC */
+ u32 dvaddr_odc;
+ u32 kvaddr_odc;
+ /* internal memory for DIS */
+ u32 dvaddr_dis;
+ u32 kvaddr_dis;
+ /* internal memory for 3DNR */
+ u32 dvaddr_3dnr;
+ u32 kvaddr_3dnr;
+
+ struct is_region *is_region;
+};
+
+struct fimc_is_device_ischain {
+ struct platform_device *pdev;
+ struct exynos_platform_fimc_is *pdata;
+ void __iomem *regs;
+
+ struct fimc_is_resourcemgr *resourcemgr;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_interface *interface;
+ struct fimc_is_mem *mem;
+
+ u32 instance;
+ u32 instance_sensor;
+ u32 module;
+ struct fimc_is_ishcain_mem imemory;
+ struct fimc_is_from_info finfo;
+ struct fimc_is_from_info pinfo;
+ struct is_region *is_region;
+
+ bool force_down;
+ unsigned long state;
+ struct mutex mutex_state;
+
+ u32 dzoom_width;
+ u32 bds_width;
+ u32 bds_height;
+ u32 setfile;
+ u32 color_range;
+
+ struct camera2_sm capability;
+ struct camera2_uctl cur_peri_ctl;
+ struct camera2_uctl peri_ctls[SENSOR_MAX_CTL];
+
+ /*isp margin*/
+ u32 margin_left;
+ u32 margin_right;
+ u32 margin_width;
+ u32 margin_top;
+ u32 margin_bottom;
+ u32 margin_height;
+
+ /* chain0 : isp ~ scc */
+ struct fimc_is_group group_3aa;
+ struct fimc_is_subdev taac;
+ struct fimc_is_subdev taap;
+
+ u32 taa_size_forceset;
+ u32 taa_size_changed_fcount;
+
+ struct fimc_is_group group_isp;
+ u32 chain0_width;
+ u32 chain0_height;
+ struct fimc_is_subdev drc;
+
+ u32 isp_size_forceset;
+ u32 isp_size_changed_fcount;
+
+ /* chain1 : scc ~ dis */
+ struct fimc_is_subdev scc;
+ u32 chain1_width;
+ u32 chain1_height;
+ u32 crop_x;
+ u32 crop_y;
+ u32 crop_width;
+ u32 crop_height;
+ struct fimc_is_subdev dis;
+ u32 dis_width;
+ u32 dis_height;
+
+ /* chain2 : dis ~ scp */
+ struct fimc_is_group group_dis;
+ u32 chain2_width;
+ u32 chain2_height;
+ struct fimc_is_subdev dnr;
+
+ /* chain3 : scp ~ fd */
+ struct fimc_is_subdev scp;
+ u32 chain3_width;
+ u32 chain3_height;
+ struct fimc_is_subdev fd;
+
+ u32 private_data;
+ struct fimc_is_device_sensor *sensor;
+ struct pm_qos_request user_qos;
+};
+
+/*global function*/
+int fimc_is_ischain_probe(struct fimc_is_device_ischain *device,
+ struct fimc_is_interface *interface,
+ struct fimc_is_resourcemgr *resourcemgr,
+ struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_mem *mem,
+ struct platform_device *pdev,
+ u32 instance,
+ u32 regs);
+int fimc_is_ischain_open(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx,
+ struct fimc_is_minfo *minfo);
+int fimc_is_ischain_close(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx);
+int fimc_is_ischain_init_wrap(struct fimc_is_device_ischain *device,
+ u32 input);
+int fimc_is_ischain_g_capability(struct fimc_is_device_ischain *this,
+ u32 user_ptr);
+int fimc_is_ischain_print_status(struct fimc_is_device_ischain *this);
+void fimc_is_ischain_meta_invalid(struct fimc_is_frame *frame);
+
+/* 3AA subdev */
+int fimc_is_ischain_3aa_open(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx);
+int fimc_is_ischain_3aa_close(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx);
+int fimc_is_ischain_3aa_s_input(struct fimc_is_device_ischain *device,
+ u32 input);
+int fimc_is_ischain_3aa_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+int fimc_is_ischain_3aa_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+int fimc_is_ischain_3aa_reqbufs(struct fimc_is_device_ischain *device,
+ u32 count);
+int fimc_is_ischain_3aa_s_format(struct fimc_is_device_ischain *device,
+ u32 width, u32 height);
+int fimc_is_ischain_3aa_buffer_queue(struct fimc_is_device_ischain *device,
+ struct fimc_is_queue *queue,
+ u32 index);
+int fimc_is_ischain_3aa_buffer_finish(struct fimc_is_device_ischain *device,
+ u32 index);
+
+/* isp subdev */
+int fimc_is_ischain_isp_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+int fimc_is_ischain_isp_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+int fimc_is_ischain_isp_reqbufs(struct fimc_is_device_ischain *device,
+ u32 count);
+int fimc_is_ischain_isp_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height);
+int fimc_is_ischain_isp_s_input(struct fimc_is_device_ischain *this,
+ u32 input);
+int fimc_is_ischain_isp_buffer_queue(struct fimc_is_device_ischain *device,
+ struct fimc_is_queue *queue,
+ u32 index);
+int fimc_is_ischain_isp_buffer_finish(struct fimc_is_device_ischain *this,
+ u32 index);
+
+/*scc subdev*/
+/*scp subdev*/
+int fimc_is_ischain_scp_s_format(struct fimc_is_device_ischain *device,
+ u32 pixelformat, u32 width, u32 height);
+
+/* vdisc subdev */
+int fimc_is_ischain_dis_start(struct fimc_is_device_ischain *this,
+ bool bypass);
+int fimc_is_ischain_dis_stop(struct fimc_is_device_ischain *this);
+int fimc_is_ischain_vdc_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height);
+
+/* vdiso subdev */
+int fimc_is_ischain_vdo_open(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx);
+int fimc_is_ischain_vdo_close(struct fimc_is_device_ischain *device,
+ struct fimc_is_video_ctx *vctx);
+int fimc_is_ischain_vdo_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue);
+int fimc_is_ischain_vdo_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *leader,
+ struct fimc_is_queue *queue);
+int fimc_is_ischain_vdo_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height);
+int fimc_is_ischain_vdo_buffer_queue(struct fimc_is_device_ischain *device,
+ struct fimc_is_queue *queue,
+ u32 index);
+int fimc_is_ischain_vdo_buffer_finish(struct fimc_is_device_ischain *this,
+ u32 index);
+
+/*special api for sensor*/
+int fimc_is_ischain_3aa_callback(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame);
+int fimc_is_ischain_isp_callback(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame);
+int fimc_is_ischain_dis_callback(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame);
+int fimc_is_ischain_camctl(struct fimc_is_device_ischain *this,
+ struct fimc_is_frame *frame,
+ u32 fcount);
+int fimc_is_ischain_tag(struct fimc_is_device_ischain *ischain,
+ struct fimc_is_frame *frame);
+
+int fimc_is_itf_stream_on(struct fimc_is_device_ischain *this);
+int fimc_is_itf_stream_off(struct fimc_is_device_ischain *this);
+int fimc_is_itf_process_start(struct fimc_is_device_ischain *device,
+ u32 group);
+int fimc_is_itf_process_stop(struct fimc_is_device_ischain *device,
+ u32 group);
+int fimc_is_itf_force_stop(struct fimc_is_device_ischain *device,
+ u32 group);
+int fimc_is_itf_map(struct fimc_is_device_ischain *device,
+ u32 group, u32 shot_addr, u32 shot_size);
+int fimc_is_itf_i2c_lock(struct fimc_is_device_ischain *this,
+ int i2c_clk, bool lock);
+
+extern const struct fimc_is_queue_ops fimc_is_ischain_3aa_ops;
+extern const struct fimc_is_queue_ops fimc_is_ischain_isp_ops;
+extern const struct fimc_is_queue_ops fimc_is_ischain_vdo_ops;
+extern const struct fimc_is_queue_ops fimc_is_ischain_sub_ops;
+
+int fimc_is_itf_power_down(struct fimc_is_interface *interface);
+int fimc_is_ischain_power(struct fimc_is_device_ischain *this, int on);
+void fimc_is_ischain_savefirm(struct fimc_is_device_ischain *this);
+
+#define IS_ISCHAIN_OTF(device) \
+ (test_bit(FIMC_IS_GROUP_OTF_INPUT, &(device)->group_3aa.state))
+#define IS_EQUAL_COORD(i, o) \
+ (((i)[0] != (o)[0]) || ((i)[1] != (o)[1]) || \
+ ((i)[2] != (o)[2]) || ((i)[3] != (o)[3]))
+#define IS_NULL_COORD(c) \
+ (!(c)[0] && !(c)[1] && !(c)[2] && !(c)[3])
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <mach/exynos-fimc-is-sensor.h>
+#include <mach/pinctrl-samsung.h>
+#ifdef CONFIG_OIS_FW_UPDATE_THREAD_USE
+#include <linux/kthread.h>
+#endif
+
+#include "fimc-is-core.h"
+#include "fimc-is-interface.h"
+#include "fimc-is-sec-define.h"
+#include "fimc-is-device-ischain.h"
+#include "fimc-is-dt.h"
+#include "fimc-is-device-ois.h"
+#ifdef CONFIG_AF_HOST_CONTROL
+#include "fimc-is-device-af.h"
+#endif
+
+#define FIMC_IS_OIS_SDCARD_PATH "/data/media/0/"
+#define FIMC_IS_OIS_DEV_NAME "exynos-fimc-is-ois"
+#define FIMC_OIS_FW_NAME_SEC "fimc_is_ois_63B.bin"
+#define FIMC_OIS_FW_NAME_DOM "fimc_is_ois_63A.bin"
+#define OIS_BOOT_FW_SIZE (1024 * 4)
+#define OIS_PROG_FW_SIZE (1024 * 24)
+#define FW_GYRO_SENSOR 0
+#define FW_DRIVER_IC 1
+#define FW_CORE_VERSION 2
+#define FW_RELEASE_MONTH 3
+#define FW_RELEASE_COUNT 4
+#define FW_TRANS_SIZE 256
+#define OIS_VER_OFFSET 14
+#define OIS_BIN_LEN 28672
+#define OIS_BIN_HEADER 28658
+#define OIS_FW_HEADER_SIZE 6
+static u8 bootCode[OIS_BOOT_FW_SIZE] = {0,};
+static u8 progCode[OIS_PROG_FW_SIZE] = {0,};
+
+static struct fimc_is_ois_info ois_minfo;
+static struct fimc_is_ois_info ois_pinfo;
+static struct fimc_is_ois_info ois_uinfo;
+static struct fimc_is_ois_exif ois_exif_data;
+static bool fw_sdcard;
+static bool not_crc_bin;
+#ifdef CONFIG_OIS_FW_UPDATE_THREAD_USE
+static struct task_struct *ois_ts;
+#endif
+
+static void fimc_is_ois_i2c_config(struct i2c_client *client, bool onoff)
+{
+ struct pinctrl *pinctrl_i2c = NULL;
+ struct device *i2c_dev = client->dev.parent->parent;
+ struct fimc_is_device_ois *ois_device = i2c_get_clientdata(client);
+
+ if (ois_device->ois_hsi2c_status != onoff) {
+ info("%s : ois_hsi2c_stauts(%d),onoff(%d)\n",__func__,
+ ois_device->ois_hsi2c_status, onoff);
+
+ if (onoff) {
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 0));
+
+ pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "on_i2c");
+ if (IS_ERR_OR_NULL(pinctrl_i2c)) {
+ printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__);
+ } else {
+ devm_pinctrl_put(pinctrl_i2c);
+ }
+ } else {
+ pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "off_i2c");
+ if (IS_ERR_OR_NULL(pinctrl_i2c)) {
+ printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__);
+ } else {
+ devm_pinctrl_put(pinctrl_i2c);
+ }
+
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 2));
+ }
+ ois_device->ois_hsi2c_status = onoff;
+ }
+}
+
+int fimc_is_ois_i2c_read(struct i2c_client *client, u16 addr, u8 *data)
+{
+ int err;
+ u8 txbuf[2], rxbuf[1];
+ struct i2c_msg msg[2];
+
+ *data = 0;
+ txbuf[0] = (addr & 0xff00) >> 8;
+ txbuf[1] = (addr & 0xff);
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = txbuf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = rxbuf;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (unlikely(err != 2)) {
+ err("%s: register read fail err = %d\n", __func__, err);
+ return -EIO;
+ }
+
+ *data = rxbuf[0];
+ return 0;
+}
+
+int fimc_is_ois_i2c_write(struct i2c_client *client ,u16 addr, u8 data)
+{
+ int retries = I2C_RETRY_COUNT;
+ int ret = 0, err = 0;
+ u8 buf[3] = {0,};
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 3,
+ .buf = buf,
+ };
+
+ buf[0] = (addr & 0xff00) >> 8;
+ buf[1] = addr & 0xff;
+ buf[2] = data;
+
+#if 0
+ pr_info("%s : W(0x%02X%02X %02X)\n",__func__, buf[0], buf[1], buf[2]);
+#endif
+
+ do {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (likely(ret == 1))
+ break;
+
+ usleep_range(10000,11000);
+ err = ret;
+ } while (--retries > 0);
+
+ /* Retry occured */
+ if (unlikely(retries < I2C_RETRY_COUNT)) {
+ err("i2c_write: error %d, write (%04X, %04X), retry %d\n",
+ err, addr, data, I2C_RETRY_COUNT - retries);
+ }
+
+ if (unlikely(ret != 1)) {
+ err("I2C does not work\n\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int fimc_is_ois_i2c_write_multi(struct i2c_client *client ,u16 addr, u8 *data, size_t size)
+{
+ int retries = I2C_RETRY_COUNT;
+ int ret = 0, err = 0, i = 0;
+ u8 buf[258] = {0,};
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = size,
+ .buf = buf,
+ };
+
+ buf[0] = (addr & 0xFF00) >> 8;
+ buf[1] = addr & 0xFF;
+
+ for (i = 0; i < size - 2; i++) {
+ buf[i + 2] = *(data + i);
+ }
+#if 0
+ pr_info("OISLOG %s : W(0x%02X%02X%02X)\n", __func__, buf[0], buf[1], buf[2]);
+#endif
+ do {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (likely(ret == 1))
+ break;
+
+ usleep_range(10000,11000);
+ err = ret;
+ } while (--retries > 0);
+
+ /* Retry occured */
+ if (unlikely(retries < I2C_RETRY_COUNT)) {
+ err("i2c_write: error %d, write (%04X, %04X), retry %d\n",
+ err, addr, *data, I2C_RETRY_COUNT - retries);
+ }
+
+ if (unlikely(ret != 1)) {
+ err("I2C does not work\n\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fimc_is_ois_i2c_read_multi(struct i2c_client *client, u16 addr, u8 *data, size_t size)
+{
+ int err;
+ u8 rxbuf[256], txbuf[2];
+ struct i2c_msg msg[2];
+
+ txbuf[0] = (addr & 0xff00) >> 8;
+ txbuf[1] = (addr & 0xff);
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = txbuf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = size;
+ msg[1].buf = rxbuf;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (unlikely(err != 2)) {
+ pr_err("%s: register read fail\n", __func__);
+ return -EIO;
+ }
+
+ memcpy(data, rxbuf, size);
+ return 0;
+}
+
+int fimc_is_ois_gpio_on(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (!pdata->gpio_cfg) {
+ err("gpio_cfg is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->gpio_cfg(device->pdev, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON);
+ if (ret) {
+ err("gpio_cfg is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_ois_gpio_off(struct fimc_is_device_companion *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (!pdata->gpio_cfg) {
+ err("gpio_cfg is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->gpio_cfg(device->pdev, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF);
+ if (ret) {
+ err("gpio_cfg is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+void fimc_is_ois_enable(struct fimc_is_core *core)
+{
+ int ret = 0;
+
+ pr_info("%s : E\n", __FUNCTION__);
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x02, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x00, 0x01);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+ pr_info("%s : X\n", __FUNCTION__);
+}
+
+int fimc_is_ois_sine_mode(struct fimc_is_core *core, int mode)
+{
+ int ret = 0;
+
+ pr_info("%s : E\n", __FUNCTION__);
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ if (mode == OPTICAL_STABILIZATION_MODE_SINE_X) {
+ ret = fimc_is_ois_i2c_write(core->client1, 0x18, 0x01);
+ } else if (mode == OPTICAL_STABILIZATION_MODE_SINE_Y) {
+ ret = fimc_is_ois_i2c_write(core->client1, 0x18, 0x02);
+ }
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x19, 0x01);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x1A, 0x1E);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x02, 0x03);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ msleep(20);
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x00, 0x01);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+ pr_info("%s : X\n", __FUNCTION__);
+
+ return ret;
+}
+EXPORT_SYMBOL(fimc_is_ois_sine_mode);
+
+void fimc_is_ois_version(struct fimc_is_core *core)
+{
+ int ret = 0;
+ u8 val_c = 0, val_d = 0;
+ u16 version = 0;
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x00FC, &val_c);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x00FD, &val_d);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ version = (val_d << 8) | val_c;
+ pr_info("OIS version = 0x%04x\n", version);
+}
+
+void fimc_is_ois_offset_test(struct fimc_is_core *core, long *raw_data_x, long *raw_data_y)
+{
+ int ret = 0, i = 0;
+ u8 val = 0, x = 0, y = 0;
+ int x_sum = 0, y_sum = 0, sum = 0;
+ int retries = 0, avg_count = 20;
+
+ pr_info("%s : E\n", __FUNCTION__);
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x0014, 0x01);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ retries = avg_count;
+ do {
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0014, &val);
+ if (ret != 0) {
+ break;
+ }
+ msleep(10);
+ if (--retries < 0) {
+ err("Read register failed!!!!, data = 0x%04x\n", val);
+ break;
+ }
+ } while (val);
+
+ sum = 0;
+ retries = avg_count;
+ for (i = 0; i < retries; retries--) {
+ fimc_is_ois_i2c_read(core->client1, 0x0248, &val);
+ x = val;
+ fimc_is_ois_i2c_read(core->client1, 0x0249, &val);
+ x_sum = (val << 8) | x;
+ if (x_sum > 0x7FFF) {
+ x_sum = -((x_sum ^ 0xFFFF) + 1);
+ }
+ sum += x_sum;
+ }
+ sum = sum * 10 / avg_count;
+ *raw_data_x = sum * 1000 / 175 / 10;
+
+ retries = avg_count;
+ for (i = 0; i < retries; retries--) {
+ fimc_is_ois_i2c_read(core->client1, 0x024A, &val);
+ y = val;
+ fimc_is_ois_i2c_read(core->client1, 0x024B, &val);
+ y_sum = (val << 8) | y;
+ if (y_sum > 0x7FFF) {
+ y_sum = -((y_sum ^ 0xFFFF) + 1);
+ }
+ sum += y_sum;
+ }
+ sum = sum * 10 / avg_count;
+ *raw_data_y = sum * 1000 / 175 / 10;
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ fimc_is_ois_version(core);
+ pr_info("%s : X\n", __FUNCTION__);
+ return;
+}
+
+void fimc_is_ois_get_offset_data(struct fimc_is_core *core, long *raw_data_x, long *raw_data_y)
+{
+ int i = 0;
+ u8 val = 0, x = 0, y = 0;
+ int x_sum = 0, y_sum = 0, sum = 0;
+ int retries = 0, avg_count = 20;
+
+ pr_info("%s : E\n", __FUNCTION__);
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ retries = avg_count;
+ for (i = 0; i < retries; retries--) {
+ fimc_is_ois_i2c_read(core->client1, 0x0248, &val);
+ x = val;
+ fimc_is_ois_i2c_read(core->client1, 0x0249, &val);
+ x_sum = (val << 8) | x;
+ if (x_sum > 0x7FFF) {
+ x_sum = -((x_sum ^ 0xFFFF) + 1);
+ }
+ sum += x_sum;
+ }
+ sum = sum * 10 / avg_count;
+ *raw_data_x = sum * 1000 / 175 / 10;
+
+ sum = 0;
+ retries = avg_count;
+ for (i = 0; i < retries; retries--) {
+ fimc_is_ois_i2c_read(core->client1, 0x024A, &val);
+ y = val;
+ fimc_is_ois_i2c_read(core->client1, 0x024B, &val);
+ y_sum = (val << 8) | y;
+ if (y_sum > 0x7FFF) {
+ y_sum = -((y_sum ^ 0xFFFF) + 1);
+ }
+ sum += y_sum;
+ }
+ sum = sum * 10 / avg_count;
+ *raw_data_y = sum * 1000 / 175 / 10;
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ fimc_is_ois_version(core);
+ pr_info("%s : X\n", __FUNCTION__);
+ return;
+}
+
+int fimc_is_ois_self_test(struct fimc_is_core *core)
+{
+ int ret = 0;
+ u8 val = 0;
+ int retries = 20;
+
+ pr_info("%s : E\n", __FUNCTION__);
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x0014, 0x08);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ do {
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0014, &val);
+ if (ret != 0) {
+ val = -EIO;
+ break;
+ }
+ msleep(10);
+ if (--retries < 0) {
+ err("Read register failed!!!!, data = 0x%04x\n", val);
+ break;
+ }
+ } while (val);
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0004, &val);
+ if (ret != 0) {
+ val = -EIO;
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ pr_info("%s(%d) : X\n", __FUNCTION__, val);
+ return (int)val;
+}
+
+bool fimc_is_ois_diff_test(struct fimc_is_core *core, int *x_diff, int *y_diff)
+{
+ int ret = 0;
+ u8 val = 0, x = 0, y = 0;
+ u16 x_min = 0, y_min = 0, x_max = 0, y_max = 0;
+ int retries = 20, default_diff = 1100;
+ u8 read_x[2], read_y[2];
+
+ pr_info("(%s) : E\n", __FUNCTION__);
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+#ifdef CONFIG_AF_HOST_CONTROL
+ fimc_is_af_move_lens(core);
+ msleep(30);
+#endif
+ ret = fimc_is_ois_i2c_read_multi(core->client1, 0x021A, read_x, 2);
+ ret |= fimc_is_ois_i2c_read_multi(core->client1, 0x021C, read_y, 2);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_write_multi(core->client1, 0x0022, read_x, 4);
+ ret |= fimc_is_ois_i2c_write_multi(core->client1, 0x0024, read_y, 4);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0002, 0x02);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0000, 0x01);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+ msleep(400);
+ pr_info("(%s) : OIS Position = Center\n", __FUNCTION__);
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x0000, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ do {
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0001, &val);
+ if (ret != 0) {
+ break;
+ }
+ msleep(10);
+ if (--retries < 0) {
+ err("Read register failed!!!!, data = 0x%04x\n", val);
+ break;
+ }
+ } while (val != 1);
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x0034, 0x64);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0230, 0x64);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0231, 0x00);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0232, 0x64);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0233, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0034, &val);
+ err("OIS[read_val_0x0034::0x%04x]\n", val);
+ ret |= fimc_is_ois_i2c_read(core->client1, 0x0230, &val);
+ err("OIS[read_val_0x0230::0x%04x]\n", val);
+ ret |= fimc_is_ois_i2c_read(core->client1, 0x0231, &val);
+ err("OIS[read_val_0x0231::0x%04x]\n", val);
+ ret |= fimc_is_ois_i2c_read(core->client1, 0x0232, &val);
+ err("OIS[read_val_0x0232::0x%04x]\n", val);
+ ret |= fimc_is_ois_i2c_read(core->client1, 0x0233, &val);
+ err("OIS[read_val_0x0233::0x%04x]\n", val);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_write(core->client1, 0x020E, 0x00);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x020F, 0x00);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0210, 0x50);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0211, 0x50);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+ ret = fimc_is_ois_i2c_write(core->client1, 0x0013, 0x01);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+#if 0
+ ret = fimc_is_ois_i2c_write(core->client1, 0x0012, 0x01);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ retries = 30;
+ do { //polarity check
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0012, &val);
+ if (ret != 0) {
+ break;
+ }
+ msleep(100);
+ if (--retries < 0) {
+ err("Polarity check is not done or not [read_val_0x0012::0x%04x]\n", val);
+ break;
+ }
+ } while (val);
+ fimc_is_ois_i2c_read(core->client1, 0x0200, &val);
+ err("OIS[read_val_0x0200::0x%04x]\n", val);
+#endif
+
+ retries = 120;
+ do {
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0013, &val);
+ if (ret != 0) {
+ break;
+ }
+ msleep(100);
+ if (--retries < 0) {
+ err("Read register failed!!!!, data = 0x%04x\n", val);
+ break;
+ }
+ } while (val);
+
+ fimc_is_ois_i2c_read(core->client1, 0x0212, &val);
+ x = val;
+ fimc_is_ois_i2c_read(core->client1, 0x0213, &val);
+ x_max = (val << 8) | x;
+ fimc_is_ois_i2c_read(core->client1, 0x0214, &val);
+ x = val;
+ fimc_is_ois_i2c_read(core->client1, 0x0215, &val);
+ x_min = (val << 8) | x;
+
+ fimc_is_ois_i2c_read(core->client1, 0x0216, &val);
+ y = val;
+ fimc_is_ois_i2c_read(core->client1, 0x0217, &val);
+ y_max = (val << 8) | y;
+ fimc_is_ois_i2c_read(core->client1, 0x0218, &val);
+ y = val;
+ fimc_is_ois_i2c_read(core->client1, 0x0219, &val);
+ y_min = (val << 8) | y;
+
+ *x_diff = abs(x_max - x_min);
+ *y_diff = abs(y_max - y_min);
+
+ pr_info("(%s) : X (default_diff:%d)(%d,%d)\n", __FUNCTION__,
+ default_diff, *x_diff, *y_diff);
+
+ ret = fimc_is_ois_i2c_read_multi(core->client1, 0x021A, read_x, 2);
+ ret |= fimc_is_ois_i2c_read_multi(core->client1, 0x021C, read_y, 2);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_write_multi(core->client1, 0x0022, read_x, 4);
+ ret |= fimc_is_ois_i2c_write_multi(core->client1, 0x0024, read_y, 4);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0002, 0x02);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0000, 0x01);
+ msleep(400);
+ ret |= fimc_is_ois_i2c_write(core->client1, 0x0000, 0x00);
+ if (ret) {
+ err("i2c write fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ if (*x_diff > default_diff && *y_diff > default_diff) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+u16 fimc_is_ois_calc_checksum(u8 *data, int size)
+{
+ int i = 0;
+ u16 result = 0;
+
+ for(i = 0; i < size; i += 2) {
+ result = result + (0xFFFF & (((*(data + i + 1)) << 8) | (*(data + i))));
+ }
+
+ return result;
+}
+
+void fimc_is_ois_exif_data(struct fimc_is_core *core)
+{
+ int ret = 0;
+ u8 error_reg[2], status_reg;
+ u16 error_sum;
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0004, &error_reg[0]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0005, &error_reg[1]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ error_sum = (error_reg[1] << 8) | error_reg[0];
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0001, &status_reg);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ ois_exif_data.error_data = error_sum;
+ ois_exif_data.status_data = status_reg;
+
+ return;
+}
+
+int fimc_is_ois_get_exif_data(struct fimc_is_ois_exif **exif_info)
+{
+ *exif_info = &ois_exif_data;
+ return 0;
+}
+
+void fimc_is_ois_fw_version(struct fimc_is_core *core)
+{
+ int ret = 0;
+ char version[7] = {0, };
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x00F9, &version[0]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x00F8, &version[1]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x007C, &version[2]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x007D, &version[3]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x007E, &version[4]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x007F, &version[5]);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ memcpy(ois_minfo.header_ver, version, 6);
+ core->ois_ver_read = true;
+
+ return;
+}
+
+int fimc_is_ois_get_module_version(struct fimc_is_ois_info **minfo)
+{
+ *minfo = &ois_minfo;
+ return 0;
+}
+
+int fimc_is_ois_get_phone_version(struct fimc_is_ois_info **pinfo)
+{
+ *pinfo = &ois_pinfo;
+ return 0;
+}
+
+int fimc_is_ois_get_user_version(struct fimc_is_ois_info **uinfo)
+{
+ *uinfo = &ois_uinfo;
+ return 0;
+}
+
+
+int fimc_is_ois_fw_revision(char *fw_ver)
+{
+ int revision = 0;
+ revision = revision + ((int)fw_ver[FW_RELEASE_MONTH] - 64) * 100;
+ revision = revision + ((int)fw_ver[FW_RELEASE_COUNT] - 48) * 10;
+ revision = revision + (int)fw_ver[FW_RELEASE_COUNT + 1] - 48;
+
+ return revision;
+}
+
+bool fimc_is_ois_version_compare(char *fw_ver1, char *fw_ver2, char *fw_ver3)
+{
+ if (fw_ver1[FW_GYRO_SENSOR] != fw_ver2[FW_GYRO_SENSOR]
+ || fw_ver1[FW_DRIVER_IC] != fw_ver2[FW_DRIVER_IC]
+ || fw_ver1[FW_CORE_VERSION] != fw_ver2[FW_CORE_VERSION]) {
+ return false;
+ }
+
+ if (fw_ver2[FW_GYRO_SENSOR] != fw_ver3[FW_GYRO_SENSOR]
+ || fw_ver2[FW_DRIVER_IC] != fw_ver3[FW_DRIVER_IC]
+ || fw_ver2[FW_CORE_VERSION] != fw_ver3[FW_CORE_VERSION]) {
+ return false;
+ }
+
+ return true;
+}
+
+bool fimc_is_ois_version_compare_default(char *fw_ver1, char *fw_ver2)
+{
+ if (fw_ver1[FW_GYRO_SENSOR] != fw_ver2[FW_GYRO_SENSOR]
+ || fw_ver1[FW_DRIVER_IC] != fw_ver2[FW_DRIVER_IC]
+ || fw_ver1[FW_CORE_VERSION] != fw_ver2[FW_CORE_VERSION]) {
+ return false;
+ }
+
+ return true;
+}
+
+bool fimc_is_ois_read_userdata(struct fimc_is_core *core)
+{
+ u8 SendData[2], RcvData[256];
+ struct i2c_client *client = core->client1;
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ fimc_is_ois_i2c_write(client ,0x000F, 0x40);
+ SendData[0] = 0x00;
+ SendData[1] = 0x00;
+ fimc_is_ois_i2c_write_multi(client, 0x0010, SendData, 4);
+ fimc_is_ois_i2c_write(client ,0x000E, 0x04);
+
+ fimc_is_ois_i2c_read(client, 0x000E, &RcvData[0]);
+ if (RcvData[0] == 0x14) {
+ fimc_is_ois_i2c_read_multi(client, 0x0100, RcvData, FW_TRANS_SIZE);
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+ memcpy(ois_uinfo.header_ver, RcvData, 6);
+ return true;
+ } else {
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+ return false;
+ }
+}
+
+int fimc_is_ois_open_fw(struct fimc_is_core *core, char *name, u8 **buf)
+{
+ int ret = 0;
+ u32 size = 0;
+ const struct firmware *fw_blob = NULL;
+ static char fw_name[100];
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long nread;
+ int fw_requested = 1;
+ int retry_count = 0;
+
+ fw_sdcard = false;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ snprintf(fw_name, sizeof(fw_name), "%s%s", FIMC_IS_OIS_SDCARD_PATH, name);
+ fp = filp_open(fw_name, O_RDONLY, 0);
+ if (IS_ERR_OR_NULL(fp)) {
+ err("failed to open SDCARD fw!!!");
+ goto request_fw;
+ }
+
+ fw_requested = 0;
+ size = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start read sdcard, file path %s, size %d Bytes\n", fw_name, size);
+
+ *buf = vmalloc(size);
+ if (!(*buf)) {
+ err("failed to allocate memory");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ nread = vfs_read(fp, (char __user *)(*buf), size, &fp->f_pos);
+ if (nread != size) {
+ err("failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto p_err;
+ }
+
+ memcpy(ois_pinfo.header_ver, *buf + OIS_BIN_HEADER, OIS_FW_HEADER_SIZE);
+ memcpy(bootCode, *buf, OIS_BOOT_FW_SIZE);
+ memcpy(progCode, *buf + OIS_BIN_LEN - OIS_PROG_FW_SIZE, OIS_PROG_FW_SIZE);
+ fw_sdcard = true;
+ if (OIS_BIN_LEN >= nread) {
+ not_crc_bin = true;
+ err("ois fw binary size = %ld.\n", nread);
+ }
+
+request_fw:
+ if (fw_requested) {
+ snprintf(fw_name, sizeof(fw_name), "%s", name);
+ set_fs(old_fs);
+ retry_count = 3;
+ ret = request_firmware(&fw_blob, fw_name, &core->companion->pdev->dev);
+ while (--retry_count && ret == -EAGAIN) {
+ err("request_firmware retry(count:%d)", retry_count);
+ ret = request_firmware(&fw_blob, fw_name, &core->companion->pdev->dev);
+ }
+
+ if (ret) {
+ err("request_firmware is fail(ret:%d)", ret);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!fw_blob) {
+ err("fw_blob is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!fw_blob->data) {
+ err("fw_blob->data is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ size = fw_blob->size;
+
+ *buf = vmalloc(size);
+ if (!(*buf)) {
+ err("failed to allocate memory");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+ memcpy((void *)(*buf), fw_blob->data, size);
+ memcpy(ois_pinfo.header_ver, *buf + OIS_BIN_HEADER, OIS_FW_HEADER_SIZE);
+ memcpy(bootCode, *buf, OIS_BOOT_FW_SIZE);
+ memcpy(progCode, *buf + OIS_BIN_LEN - OIS_PROG_FW_SIZE, OIS_PROG_FW_SIZE);
+ if (OIS_BIN_LEN >= size) {
+ not_crc_bin = true;
+ err("ois fw binary size = 0x%08x.\n", size);
+ }
+ pr_info("OIS firmware is loaded from Phone binary.\n");
+ }
+
+p_err:
+ if (!fw_requested) {
+ if (!IS_ERR_OR_NULL(fp)) {
+ filp_close(fp, current->files);
+ }
+ set_fs(old_fs);
+ } else {
+ if (!IS_ERR_OR_NULL(fw_blob)) {
+ release_firmware(fw_blob);
+ }
+ }
+
+ return ret;
+}
+
+void fimc_is_ois_check_fw(struct fimc_is_core *core)
+{
+ u8 *buf = NULL;
+ int ret = 0;
+
+ fimc_is_ois_fw_version(core);
+ fimc_is_ois_read_userdata(core);
+
+ if (ois_minfo.header_ver[2] == 'A') {
+ ret = fimc_is_ois_open_fw(core, FIMC_OIS_FW_NAME_DOM, &buf);
+ } else if (ois_minfo.header_ver[2] == 'B') {
+ ret = fimc_is_ois_open_fw(core, FIMC_OIS_FW_NAME_SEC, &buf);
+ }
+ if (ret) {
+ err("fimc_is_ois_open_fw failed(%d)\n", ret);
+ }
+
+ if (buf) {
+ vfree(buf);
+ }
+
+ return;
+}
+
+u8 fimc_is_ois_read_status(struct fimc_is_core *core)
+{
+ int ret = 0;
+ u8 status = 0;
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0006, &status);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ return status;
+}
+
+u8 fimc_is_ois_read_cal_checksum(struct fimc_is_core *core)
+{
+ int ret = 0;
+ u8 status = 0;
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ ret = fimc_is_ois_i2c_read(core->client1, 0x0005, &status);
+ if (ret) {
+ err("i2c read fail\n");
+ }
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ return status;
+}
+
+void fimc_is_ois_fw_status(struct fimc_is_core *core, u8 *checksum, u8 *caldata)
+{
+ *checksum = fimc_is_ois_read_status(core);
+ *caldata = fimc_is_ois_read_cal_checksum(core);
+
+ return;
+}
+
+bool fimc_is_ois_crc_check(struct fimc_is_core *core, char *buf)
+{
+ u8 check_8[4] = {0, };
+ u32 *buf32 = NULL;
+ u32 checksum;
+ u32 checksum_bin;
+
+ if (not_crc_bin) {
+ err("ois binary does not conatin crc checksum.\n");
+ return false;
+ }
+
+ if (buf == NULL) {
+ err("buf is NULL. CRC check failed.");
+ return false;
+ }
+
+ buf32 = (u32 *)buf;
+
+ memcpy(check_8, buf + OIS_BIN_LEN, 4);
+ checksum_bin = (check_8[3] << 24) | (check_8[2] << 16) | (check_8[1] << 8) | (check_8[0]);
+
+ checksum = getCRC((u16 *)&buf32[0], OIS_BIN_LEN / 2, NULL, NULL);
+ if (checksum != checksum_bin) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void fimc_is_ois_fw_update(struct fimc_is_core *core)
+{
+ u8 SendData[256], RcvData;
+ u16 RcvDataShort = 0;
+ u8 data[2] = {0, };
+ int block, i, position = 0;
+ u16 checkSum;
+ u8 *buf = NULL;
+ int ret = 0, sum_size = 0, retry_count = 3;
+ int module_ver = 0, binary_ver = 0;
+ u8 error_status = 0;
+ bool forced_update = false, crc_result = false;
+ bool need_reset = false;
+ struct i2c_client *client = core->client1;
+
+ /* OIS Status Check */
+ error_status = fimc_is_ois_read_status(core);
+ if (error_status == 0x01) {
+ forced_update = true;
+ }
+
+ fimc_is_ois_fw_version(core);
+ fimc_is_ois_read_userdata(core);
+ if (ois_minfo.header_ver[2] == 'A') {
+ ret = fimc_is_ois_open_fw(core, FIMC_OIS_FW_NAME_DOM, &buf);
+ } else if (ois_minfo.header_ver[2] == 'B') {
+ ret = fimc_is_ois_open_fw(core, FIMC_OIS_FW_NAME_SEC, &buf);
+ }
+ if (ret) {
+ err("fimc_is_ois_open_fw failed(%d)", ret);
+ goto p_err;
+ }
+
+ if (buf == NULL) {
+ err("buf is NULL. OIS FW Update failed.");
+ return;
+ }
+
+ if (!forced_update) {
+ if (ois_uinfo.header_ver[0] == 0xFF && ois_uinfo.header_ver[1] == 0xFF &&
+ ois_uinfo.header_ver[2] == 0xFF) {
+ err("OIS userdata is not valid.");
+ goto p_err;
+ }
+ }
+
+ /*Update OIS FW when Gyro sensor/Driver IC/ Core version is same*/
+ if (!forced_update) {
+ if (!fimc_is_ois_version_compare(ois_minfo.header_ver, ois_pinfo.header_ver,
+ ois_uinfo.header_ver)) {
+ err("Does not update ois fw. OIS module ver = %s, binary ver = %s, userdata ver = %s",
+ ois_minfo.header_ver, ois_pinfo.header_ver, ois_uinfo.header_ver);
+ goto p_err;
+ }
+ } else {
+ if (!fimc_is_ois_version_compare_default(ois_minfo.header_ver, ois_pinfo.header_ver)) {
+ err("Does not update ois fw. OIS module ver = %s, binary ver = %s",
+ ois_minfo.header_ver, ois_pinfo.header_ver);
+ goto p_err;
+ }
+ }
+
+ crc_result = fimc_is_ois_crc_check(core, buf);
+ if (crc_result == false) {
+ err("OIS CRC32 error.\n");
+ goto p_err;
+ }
+
+ if (!fw_sdcard && !forced_update) {
+ module_ver = fimc_is_ois_fw_revision(ois_minfo.header_ver);
+ binary_ver = fimc_is_ois_fw_revision(ois_pinfo.header_ver);
+ if (binary_ver <= module_ver) {
+ err("OIS module ver = %d, binary ver = %d", module_ver, binary_ver);
+ goto p_err;
+ }
+ }
+ info("OIS fw update started. module ver = %s, binary ver = %s, userdata ver = %s\n",
+ ois_minfo.header_ver, ois_pinfo.header_ver, ois_uinfo.header_ver);
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+retry:
+ if (need_reset) {
+ fimc_is_ois_gpio_off(core->companion);
+ msleep(30);
+ fimc_is_ois_gpio_on(core->companion);
+ msleep(150);
+ }
+
+ fimc_is_ois_i2c_read(client, 0x01, &RcvData); /* OISSTS Read */
+
+ if (RcvData != 0x01) {/* OISSTS != IDLE */
+ err("RCV data return!!");
+ goto p_err;
+ }
+
+ /* Update a Boot Program */
+ /* SET FWUP_CTRL REG */
+ fimc_is_ois_i2c_write(client ,0x000C, 0x0B);
+ msleep(20);
+
+ position = 0;
+ /* Write Boot Data */
+ for (block = 4; block < 8; block++) { /* 0x1000 - 0x1FFF */
+ for (i = 0; i < 4; i++) {
+ memcpy(SendData, bootCode + position, FW_TRANS_SIZE);
+ fimc_is_ois_i2c_write_multi(client, 0x0100, SendData, FW_TRANS_SIZE + 2);
+ position += FW_TRANS_SIZE;
+ if (i == 0 ) {
+ msleep(20);
+ } else if ((i == 1) || (i == 2)) { /* Wait Erase and Write process */
+ msleep(10); /* Wait Write process */
+ } else {
+ msleep(15); /* Wait Write and Verify process */
+ }
+ }
+ }
+
+ /* CHECKSUM (Boot) */
+ sum_size = OIS_BOOT_FW_SIZE;
+ checkSum = fimc_is_ois_calc_checksum(&bootCode[0], sum_size);
+ SendData[0] = (checkSum & 0x00FF);
+ SendData[1] = (checkSum & 0xFF00) >> 8;
+ SendData[2] = 0x00;
+ SendData[3] = 0x00;
+ fimc_is_ois_i2c_write_multi(client, 0x08, SendData, 6);
+ msleep(10); /* (RUMBA Self Reset) */
+
+ fimc_is_ois_i2c_read_multi(client, 0x06, data, 2); /* Error Status read */
+ info("%s: OISSTS Read = 0x%02x%02x\n", __func__, data[1], data[0]);
+
+ if (data[1] == 0x00 && data[0] == 0x01) { /* Boot F/W Update Error check */
+ /* Update a User Program */
+ /* SET FWUP_CTRL REG */
+ position = 0;
+ SendData[0] = 0x09; /* FWUP_DSIZE=256Byte, FWUP_MODE=PROG, FWUPEN=Start */
+ fimc_is_ois_i2c_write(client, 0x0C, SendData[0]); /* FWUPCTRL REG(0x000C) 1Byte Send */
+
+ /* Write UserProgram Data */
+ for (block = 4; block <= 27; block++) { /* 0x1000 -0x 6FFF (RUMBA-SA)*/
+ for (i = 0; i < 4; i++) {
+ memcpy(SendData, &progCode[position], (size_t)FW_TRANS_SIZE);
+ fimc_is_ois_i2c_write_multi(client, 0x100, SendData, FW_TRANS_SIZE + 2); /* FLS_DATA REG(0x0100) 256Byte Send */
+ position += FW_TRANS_SIZE;
+ if (i ==0 ) {
+ msleep(20); /* Wait Erase and Write process */
+ } else if ((i==1) || (i==2)) {
+ msleep(10); /* Wait Write process */
+ } else {
+ msleep(15); /* Wait Write and Verify process */
+ }
+ }
+ }
+
+ /* CHECKSUM (Program) */
+ sum_size = OIS_PROG_FW_SIZE;
+ checkSum = fimc_is_ois_calc_checksum(&progCode[0], sum_size);
+ SendData[0] = (checkSum & 0x00FF);
+ SendData[1] = (checkSum & 0xFF00) >> 8;
+ SendData[2] = 0; /* Don't Care */
+ SendData[3] = 0x80; /* Self Reset Request */
+
+ fimc_is_ois_i2c_write_multi(client, 0x08, SendData, 6); /* FWUP_CHKSUM REG(0x0008) 4Byte Send */
+ msleep(20); /* (Wait RUMBA Self Reset) */
+ fimc_is_ois_i2c_read(client, 0x6, (u8*)&RcvDataShort); /* Error Status read */
+
+ if (RcvDataShort == 0x0000) {
+ /* F/W Update Success Process */
+ info("%s: OISLOG OIS program update success", __func__);
+ } else {
+ /* Retry Process */
+ if (retry_count > 0) {
+ err("OISLOG OIS program update fail, retry update. count = %d", retry_count);
+ retry_count--;
+ need_reset = true;
+ goto retry;
+ }
+
+ /* F/W Update Error Process */
+ err("OISLOG OIS program update fail");
+ goto p_err;
+ }
+ } else {
+ /* Retry Process */
+ if (retry_count > 0) {
+ err("OISLOG OIS boot update fail, retry update. count = %d", retry_count);
+ retry_count--;
+ need_reset = true;
+ goto retry;
+ }
+
+ /* Error Process */
+ err("CAN'T process OIS program update");
+ goto p_err;
+ }
+
+ /* S/W Reset */
+ fimc_is_ois_i2c_write(client ,0x000D, 0x01);
+ fimc_is_ois_i2c_write(client ,0x000E, 0x06);
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ msleep(30);
+ fimc_is_ois_fw_version(core);
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, true);
+ }
+
+ if (!fimc_is_ois_version_compare_default(ois_minfo.header_ver, ois_pinfo.header_ver)) {
+ err("After update ois fw is not correct. OIS module ver = %s, binary ver = %s",
+ ois_minfo.header_ver, ois_pinfo.header_ver);
+ goto p_err;
+ }
+
+ /* Param init - Flash to Rumba */
+ fimc_is_ois_i2c_write(client ,0x0036, 0x03);
+ msleep(30);
+
+p_err:
+ info("OIS module ver = %s, binary ver = %s, userdata ver = %s\n",
+ ois_minfo.header_ver, ois_pinfo.header_ver, ois_uinfo.header_ver);
+
+ if (core->use_ois_hsi2c) {
+ fimc_is_ois_i2c_config(core->client1, false);
+ }
+
+ if (buf) {
+ vfree(buf);
+ }
+ return;
+}
+
+#ifdef CONFIG_OIS_FW_UPDATE_THREAD_USE
+int fimc_is_ois_thread(void *data)
+{
+ struct fimc_is_core *core = data;
+
+ fimc_is_ois_gpio_on(core->companion);
+ msleep(150);
+ fimc_is_ois_fw_update(core);
+ fimc_is_ois_gpio_off(core->companion);
+
+ return 0;
+}
+
+void fimc_is_ois_init_thread(struct fimc_is_core *core)
+{
+ pr_info("OIS fimc_is_ois_init_thread\n");
+
+ ois_ts = kthread_run(fimc_is_ois_thread, core, "ois_thread");
+ if (IS_ERR_OR_NULL(ois_ts))
+ err("failed to create a thread for ois fw update\n");
+
+ return;
+}
+#endif /* CONFIG_OIS_FW_UPDATE_THREAD_USE */
+
+static int fimc_is_ois_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fimc_is_device_ois *device;
+ struct ois_i2c_platform_data *pdata;
+ struct fimc_is_core *core;
+ struct device *i2c_dev;
+ struct pinctrl *pinctrl_i2c = NULL;
+
+ if (fimc_is_dev == NULL) {
+ warn("fimc_is_dev is not yet probed");
+ client->dev.init_name = FIMC_IS_OIS_DEV_NAME;
+ return -EPROBE_DEFER;
+ }
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core)
+ return -EINVAL;
+
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct ois_i2c_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ err("Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ } else {
+ pdata = client->dev.platform_data;
+ }
+
+ if (pdata == NULL) {
+ err("%s : ois probe fail\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ err("No I2C functionality found\n");
+ devm_kfree(&client->dev, pdata);
+ return -ENODEV;
+ }
+
+ device = kzalloc(sizeof(struct fimc_is_device_ois), GFP_KERNEL);
+ if (!device) {
+ err("fimc_is_device_companion is NULL");
+ devm_kfree(&client->dev, pdata);
+ return -ENOMEM;
+ }
+
+ device->ois_hsi2c_status = false;
+ core->client1 = client;
+ i2c_set_clientdata(client, device);
+ fw_sdcard = false;
+ core->ois_ver_read = false;
+ not_crc_bin = false;
+
+ /* Initial i2c pin */
+ i2c_dev = client->dev.parent->parent;
+ pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "off_i2c");
+ if (IS_ERR_OR_NULL(pinctrl_i2c)) {
+ printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__);
+ } else {
+ devm_pinctrl_put(pinctrl_i2c);
+ }
+
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_FUNC, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-2",
+ PINCFG_PACK(PINCFG_TYPE_PUD, 0));
+ pin_config_set(FIMC_IS_SPI_PINNAME, "gpc2-3",
+ PINCFG_PACK(PINCFG_TYPE_PUD, 0));
+
+ return 0;
+}
+
+static int fimc_is_ois_remove(struct i2c_client *client)
+{
+#ifdef CONFIG_OIS_FW_UPDATE_THREAD_USE
+ if (ois_ts) {
+ kthread_stop(ois_ts);
+ ois_ts = NULL;
+ }
+#endif
+
+ return 0;
+}
+
+static const struct i2c_device_id ois_id[] = {
+ {FIMC_IS_OIS_DEV_NAME, 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ois_id);
+
+#ifdef CONFIG_OF
+static struct of_device_id ois_dt_ids[] = {
+ { .compatible = "rumba,ois",},
+ {},
+};
+#endif
+
+static struct i2c_driver ois_i2c_driver = {
+ .driver = {
+ .name = FIMC_IS_OIS_DEV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = ois_dt_ids,
+#endif
+ },
+ .probe = fimc_is_ois_probe,
+ .remove = fimc_is_ois_remove,
+ .id_table = ois_id,
+};
+module_i2c_driver(ois_i2c_driver);
+
+MODULE_DESCRIPTION("OIS driver for Rumba");
+MODULE_AUTHOR("kyoungho yun <kyoungho.yun@samsung.com>");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS OIS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+struct fimc_is_device_ois {
+ struct v4l2_device v4l2_dev;
+ struct platform_device *pdev;
+ unsigned long state;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct i2c_client *client;
+ int ois_en;
+ bool ois_hsi2c_status;
+};
+
+struct ois_i2c_platform_data {
+ int ois_en;
+};
+
+struct fimc_is_ois_exif {
+ int error_data;
+ int status_data;
+};
+
+int fimc_is_ois_i2c_read(struct i2c_client *client, u16 addr, u8 *data);
+int fimc_is_ois_i2c_write(struct i2c_client *client ,u16 addr, u8 data);
+void fimc_is_ois_enable(struct fimc_is_core *core);
+void fimc_is_ois_offset_test(struct fimc_is_core *core, long *raw_data_x, long *raw_data_y);
+int fimc_is_ois_self_test(struct fimc_is_core *core);
+int fimc_is_ois_gpio_on(struct fimc_is_device_companion *device);
+int fimc_is_ois_gpio_off(struct fimc_is_device_companion *device);
+void fimc_is_ois_fw_update(struct fimc_is_core *core);
+void fimc_is_ois_fw_version(struct fimc_is_core *core);
+int fimc_is_ois_get_module_version(struct fimc_is_ois_info **minfo);
+int fimc_is_ois_get_phone_version(struct fimc_is_ois_info **minfo);
+int fimc_is_ois_get_user_version(struct fimc_is_ois_info **uinfo);
+void fimc_is_ois_get_offset_data(struct fimc_is_core *core, long *raw_data_x, long *raw_data_y);
+void fimc_is_ois_check_fw(struct fimc_is_core *core);
+bool fimc_is_ois_diff_test(struct fimc_is_core *core, int *x_diff, int *y_diff);
+#ifdef CONFIG_OIS_FW_UPDATE_THREAD_USE
+void fimc_is_ois_init_thread(struct fimc_is_core *core);
+#endif
+bool fimc_is_ois_read_userdata(struct fimc_is_core *core);
+void fimc_is_ois_exif_data(struct fimc_is_core *core);
+int fimc_is_ois_get_exif_data(struct fimc_is_ois_exif **exif_info);
+void fimc_is_ois_fw_status(struct fimc_is_core *core, u8 *checksum, u8 *caldata);
\ No newline at end of file
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+#include <linux/i2c.h>
+
+#include <mach/map.h>
+#include <mach/devfreq.h>
+#include <mach/regs-clock.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-dt.h"
+#include "fimc-is-dvfs.h"
+
+#include "sensor/fimc-is-device-6b2.h"
+#include "sensor/fimc-is-device-imx134.h"
+#include "sensor/fimc-is-device-imx135.h"
+#include "fimc-is-device-sensor.h"
+#ifdef CONFIG_COMPANION_USE
+#include "fimc-is-companion-dt.h"
+#endif
+
+extern struct device *camera_front_dev;
+extern struct device *camera_rear_dev;
+int fimc_is_sensor_runtime_resume(struct device *dev);
+int fimc_is_sensor_runtime_suspend(struct device *dev);
+
+extern int fimc_is_sen_video_probe(void *data);
+struct pm_qos_request exynos_sensor_qos_cam;
+struct pm_qos_request exynos_sensor_qos_int;
+struct pm_qos_request exynos_sensor_qos_mem;
+
+extern u32 __iomem *notify_fcount_sen0;
+extern u32 __iomem *notify_fcount_sen1;
+extern u32 __iomem *notify_fcount_sen2;
+u32 notify_fcount_sen0_fw;
+u32 notify_fcount_sen1_fw;
+u32 notify_fcount_sen2_fw;
+u32 notify_fcount_dummy;
+
+#define BINNING(x, y) roundup((x) * 1000 / (y), 250)
+
+int fimc_is_sensor_read8(struct i2c_client *client,
+ u16 addr, u8 *val)
+{
+ int ret = 0;
+ struct i2c_msg msg[2];
+ u8 wbuf[2];
+
+ if (!client->adapter) {
+ err("Could not find adapter!\n");
+ ret = -ENODEV;
+ goto p_err;
+ }
+
+ /* 1. I2C operation for writing. */
+ msg[0].addr = client->addr;
+ msg[0].flags = 0; /* write : 0, read : 1 */
+ msg[0].len = 2;
+ msg[0].buf = wbuf;
+ /* TODO : consider other size of buffer */
+ wbuf[0] = (addr & 0xFF00) >> 8;
+ wbuf[1] = (addr & 0xFF);
+
+ /* 2. I2C operation for reading data. */
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = val;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ err("i2c treansfer fail");
+ goto p_err;
+ }
+
+#ifdef PRINT_I2CCMD
+ info("I2CR08(%d) [0x%04X] : 0x%04X\n", client->addr, addr, *val);
+#endif
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_read16(struct i2c_client *client,
+ u16 addr, u16 *val)
+{
+ int ret = 0;
+ struct i2c_msg msg[2];
+ u8 wbuf[2], rbuf[2];
+
+ if (!client->adapter) {
+ err("Could not find adapter!\n");
+ ret = -ENODEV;
+ goto p_err;
+ }
+
+ /* 1. I2C operation for writing. */
+ msg[0].addr = client->addr;
+ msg[0].flags = 0; /* write : 0, read : 1 */
+ msg[0].len = 2;
+ msg[0].buf = wbuf;
+ /* TODO : consider other size of buffer */
+ wbuf[0] = (addr & 0xFF00) >> 8;
+ wbuf[1] = (addr & 0xFF);
+
+ /* 2. I2C operation for reading data. */
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = rbuf;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ err("i2c treansfer fail");
+ goto p_err;
+ }
+
+ *val = ((rbuf[0] << 8) | rbuf[1]);
+
+#ifdef PRINT_I2CCMD
+ info("I2CR16(%d) [0x%04X] : 0x%04X\n", client->addr, addr, *val);
+#endif
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_write(struct i2c_client *client,
+ u8 *buf, u32 size)
+{
+ int ret = 0;
+ int retry_count = 5;
+ struct i2c_msg msg = {client->addr, 0, size, buf};
+
+ do {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (likely(ret == 1))
+ break;
+ msleep(10);
+ } while (retry_count-- > 0);
+
+ if (ret != 1) {
+ dev_err(&client->dev, "%s: I2C is not working.\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int fimc_is_sensor_write8(struct i2c_client *client,
+ u16 addr, u8 val)
+{
+ int ret = 0;
+ struct i2c_msg msg[1];
+ u8 wbuf[3];
+
+ if (!client->adapter) {
+ err("Could not find adapter!\n");
+ ret = -ENODEV;
+ goto p_err;
+ }
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 3;
+ msg->buf = wbuf;
+ wbuf[0] = (addr & 0xFF00) >> 8;
+ wbuf[1] = (addr & 0xFF);
+ wbuf[2] = val;
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret < 0) {
+ err("i2c treansfer fail(%d)", ret);
+ goto p_err;
+ }
+
+#ifdef PRINT_I2CCMD
+ info("I2CW08(%d) [0x%04X] : 0x%04X\n", client->addr, addr, val);
+#endif
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_write16(struct i2c_client *client,
+ u16 addr, u16 val)
+{
+ int ret = 0;
+ struct i2c_msg msg[1];
+ u8 wbuf[4];
+
+ if (!client->adapter) {
+ err("Could not find adapter!\n");
+ ret = -ENODEV;
+ goto p_err;
+ }
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 4;
+ msg->buf = wbuf;
+ wbuf[0] = (addr & 0xFF00) >> 8;
+ wbuf[1] = (addr & 0xFF);
+ wbuf[2] = (val & 0xFF00) >> 8;
+ wbuf[3] = (val & 0xFF);
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret < 0) {
+ err("i2c treansfer fail(%d)", ret);
+ goto p_err;
+ }
+
+#ifdef PRINT_I2CCMD
+ info("I2CW16(%d) [0x%04X] : 0x%04X\n", client->addr, addr, val);
+#endif
+
+p_err:
+ return ret;
+}
+
+#if defined(CONFIG_PM_DEVFREQ)
+inline static void fimc_is_sensor_set_qos_init(struct fimc_is_device_sensor *device, bool on)
+{
+ int cam_qos = 0;
+ int int_qos = 0;
+ int mif_qos = 0;
+ struct fimc_is_core *core =
+ (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+
+ cam_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CAM, START_DVFS_LEVEL);
+#if 0 /* For vision of L_version */
+ int_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_INT, START_DVFS_LEVEL);
+#endif
+ if (on) {
+ /* DEVFREQ lock */
+ if (cam_qos > 0) {
+ if (device->request_cam_qos == false) {
+ pm_qos_add_request(&exynos_sensor_qos_cam, PM_QOS_CAM_THROUGHPUT, cam_qos);
+ device->request_cam_qos = true;
+ } else {
+ err("Adding sensor cam_qos is not allowed");
+ }
+ }
+
+ if (int_qos > 0) {
+ if (device->request_int_qos == false) {
+ pm_qos_add_request(&exynos_sensor_qos_int, PM_QOS_DEVICE_THROUGHPUT, int_qos);
+ device->request_int_qos = true;
+ } else {
+ err("Adding sensor int_qos is not allowed");
+ }
+ }
+
+ if (mif_qos > 0) {
+ if (device->request_mif_qos == false) {
+ pm_qos_add_request(&exynos_sensor_qos_mem, PM_QOS_BUS_THROUGHPUT, mif_qos);
+ device->request_mif_qos = true;
+ } else {
+ err("Adding sensor mif_qos is not allowed");
+ }
+ }
+ minfo("[SEN:D] %s: QoS LOCK [INT(%d), MIF(%d), CAM(%d)]\n", device,
+ __func__, int_qos, mif_qos, cam_qos);
+ } else {
+ /* DEVFREQ unlock */
+ if (cam_qos > 0) {
+ if (device->request_cam_qos == true) {
+ pm_qos_remove_request(&exynos_sensor_qos_cam);
+ device->request_cam_qos = false;
+ } else {
+ err("Removing sensor cam_qos is not allowed");
+ }
+ }
+
+ if (int_qos > 0) {
+ if (device->request_int_qos == true) {
+ pm_qos_remove_request(&exynos_sensor_qos_int);
+ device->request_int_qos = false;
+ } else {
+ err("Removing sensor int_qos is not allowed");
+ }
+ }
+
+ if (mif_qos > 0) {
+ if (device->request_mif_qos == true) {
+ pm_qos_remove_request(&exynos_sensor_qos_mem);
+ device->request_mif_qos = false;
+ } else {
+ err("Removing sensor mif_qos is not allowed");
+ }
+ }
+ minfo("[SEN:D] %s: QoS UNLOCK\n", device, __func__);
+ }
+}
+
+inline static void fimc_is_sensor_set_qos_update(struct fimc_is_device_sensor *device, u32 scenario)
+{
+ int cam_qos = 0;
+ int int_qos = 0;
+ int mif_qos = 0;
+ struct fimc_is_core *core =
+ (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+
+ /* HACK: This is considerated only front camera vision scenario. */
+ if (scenario == SENSOR_SCENARIO_VISION) {
+ cam_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CAM, FIMC_IS_SN_FRONT_PREVIEW);
+ int_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_INT, FIMC_IS_SN_FRONT_PREVIEW);
+ }
+
+ /* DEVFREQ update */
+ if (cam_qos > 0)
+ pm_qos_update_request(&exynos_sensor_qos_cam, cam_qos);
+ if (int_qos > 0)
+ pm_qos_update_request(&exynos_sensor_qos_int, int_qos);
+ if (mif_qos > 0)
+ pm_qos_update_request(&exynos_sensor_qos_mem, mif_qos);
+
+ minfo("[SEN:D] %s: QoS UPDATE(%d) [INT(%d), MIF(%d), CAM(%d)]\n", device,
+ __func__, scenario, int_qos, mif_qos, cam_qos);
+}
+#endif
+
+static int get_sensor_mode(struct fimc_is_sensor_cfg *cfg,
+ u32 cfgs, u32 width, u32 height, u32 framerate)
+{
+ int mode = -1;
+ int idx = -1;
+ u32 i;
+
+ /* find sensor mode by w/h and fps range */
+ for (i = 0; i < cfgs; i++) {
+ if ((cfg[i].width == width) &&
+ (cfg[i].height == height)) {
+ if (cfg[i].framerate == framerate) {
+ /* You don't need to find another sensor mode */
+ mode = cfg[i].mode;
+ idx = i;
+ break;
+ } else if (cfg[i].framerate > framerate) {
+ /* try to find framerate smaller than previous */
+ if (mode < 0) {
+ mode = cfg[i].mode;
+ idx = i;
+ } else {
+ /* try to compare previous with current */
+ if (cfg[idx].framerate > cfg[i].framerate) {
+ mode = cfg[i].mode;
+ idx = i;
+ }
+ }
+ }
+ }
+ }
+
+ if (idx < 0)
+ err("could not find proper sensor mode: %dx%d@%dfps",
+ width, height, framerate);
+ else
+ pr_info("sensor mode(%dx%d@%d) = %d\n",
+ cfg[idx].width,
+ cfg[idx].height,
+ cfg[idx].framerate,
+ cfg[idx].mode);
+
+ return mode;
+}
+
+static int fimc_is_sensor_mclk_on(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (test_bit(FIMC_IS_SENSOR_MCLK_ON, &device->state)) {
+ merr("%s : already clk on", device, __func__);
+ goto p_err;
+ }
+
+ if (!pdata->mclk_on) {
+ merr("mclk_on is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->mclk_on(device->pdev, pdata->scenario, pdata->mclk_ch);
+ if (ret) {
+ merr("mclk_on is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SENSOR_MCLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_mclk_off(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_SENSOR_MCLK_ON, &device->state)) {
+ merr("%s : already clk off", device, __func__);
+ goto p_err;
+ }
+
+ if (!pdata->mclk_off) {
+ merr("mclk_off is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->mclk_off(device->pdev, pdata->scenario, pdata->mclk_ch);
+ if (ret) {
+ merr("mclk_off is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SENSOR_MCLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_iclk_on(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_core *core;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+ BUG_ON(!device->private_data);
+
+ core = device->private_data;
+ pdata = device->pdata;
+
+ if (test_bit(FIMC_IS_SENSOR_ICLK_ON, &device->state)) {
+ merr("%s : already clk on", device, __func__);
+ goto p_err;
+ }
+
+ if (!pdata->iclk_cfg) {
+ merr("iclk_cfg is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!pdata->iclk_on) {
+ merr("iclk_on is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->iclk_cfg(core->pdev, pdata->scenario, pdata->csi_ch);
+ if (ret) {
+ merr("iclk_cfg is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = pdata->iclk_on(core->pdev, pdata->scenario, pdata->csi_ch);
+ if (ret) {
+ merr("iclk_on is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SENSOR_ICLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_iclk_off(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_core *core;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+ BUG_ON(!device->private_data);
+
+ core = device->private_data;
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_SENSOR_ICLK_ON, &device->state)) {
+ merr("%s : already clk off", device, __func__);
+ goto p_err;
+ }
+
+ if (!pdata->iclk_off) {
+ merr("iclk_off is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->iclk_off(core->pdev, pdata->scenario, pdata->csi_ch);
+ if (ret) {
+ merr("iclk_off is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SENSOR_ICLK_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_gpio_on(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (test_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state)) {
+ merr("%s : already gpio on", device, __func__);
+ goto p_err;
+ }
+
+ if (!pdata->gpio_cfg) {
+ merr("gpio_cfg is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (pdata->id == 0) {
+ core->running_rear_camera = true;
+ } else {
+ core->running_front_camera = true;
+ }
+
+ ret = pdata->gpio_cfg(device->pdev, pdata->scenario, GPIO_SCENARIO_ON);
+ if (ret) {
+ merr("gpio_cfg is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_gpio_off(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state)) {
+ merr("%s : already gpio off", device, __func__);
+ goto p_err;
+ }
+
+ if (!pdata->gpio_cfg) {
+ merr("gpio_cfg is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->gpio_cfg(device->pdev, pdata->scenario, GPIO_SCENARIO_OFF);
+ if (ret) {
+ merr("gpio_cfg is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state);
+
+p_err:
+ if (pdata->id == 0) {
+ core->running_rear_camera = false;
+ } else {
+ core->running_front_camera = false;
+ }
+ return ret;
+}
+
+#ifdef ENABLE_DTP
+static void fimc_is_sensor_dtp(unsigned long data)
+{
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_sensor *device = (struct fimc_is_device_sensor *)data;
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ unsigned long flags;
+ u32 i;
+
+ BUG_ON(!device);
+
+ err("forcely reset due to 0x%08lx", device->force_stop);
+ device->force_stop = 0;
+
+ set_bit(FIMC_IS_SENSOR_FRONT_DTP_STOP, &device->state);
+ set_bit(FIMC_IS_SENSOR_BACK_NOWAIT_STOP, &device->state);
+
+ if (device->ischain) {
+ set_bit(FIMC_IS_GROUP_FORCE_STOP, &device->ischain->group_3aa.state);
+ set_bit(FIMC_IS_GROUP_FORCE_STOP, &device->ischain->group_isp.state);
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &device->ischain->group_3aa.state))
+ up(&device->ischain->group_3aa.smp_trigger);
+ }
+
+ vctx = device->vctx;
+ if (!vctx) {
+ err("vctx is NULL");
+ return;
+ }
+
+ queue = GET_DST_QUEUE(vctx);
+ framemgr = &queue->framemgr;
+ if ((framemgr->frame_cnt == 0) || (framemgr->frame_cnt > FRAMEMGR_MAX_REQUEST)) {
+ err("frame count of framemgr is invalid(%d)", framemgr->frame_cnt);
+ return;
+ }
+
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ for (i = 0; i < framemgr->frame_cnt; i++) {
+ frame = &framemgr->frame[i];
+ if (frame->state == FIMC_IS_FRAME_STATE_REQUEST) {
+ err("buffer done1!!!! %d", i);
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ queue_done(vctx, queue, i, VB2_BUF_STATE_ERROR);
+ } else if (frame->state == FIMC_IS_FRAME_STATE_PROCESS) {
+ err("buffer done2!!!! %d", i);
+ fimc_is_frame_trans_pro_to_com(framemgr, frame);
+ queue_done(vctx, queue, i, VB2_BUF_STATE_ERROR);
+ }
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+}
+#endif
+
+static int fimc_is_sensor_start(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ BUG_ON(!device);
+
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state)) {
+ struct v4l2_subdev *subdev;
+
+ subdev = device->subdev_module;
+ if (!subdev) {
+ merr("subdev is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ ret = v4l2_subdev_call(subdev, video, s_stream, true);
+ if (ret) {
+ merr("v4l2_subdev_call(s_stream) is fail(%d)", device, ret);
+ goto p_err;
+ }
+ } else {
+ struct fimc_is_device_ischain *ischain;
+
+ ischain = device->ischain;
+ if (!ischain) {
+ merr("ischain is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_itf_stream_on(ischain);
+ if (ret) {
+ merr("fimc_is_itf_stream_on is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_stop(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+
+ BUG_ON(!device);
+
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state)) {
+ struct v4l2_subdev *subdev;
+
+ subdev = device->subdev_module;
+ if (!subdev) {
+ merr("subdev is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ ret = v4l2_subdev_call(subdev, video, s_stream, false);
+ if (ret) {
+ merr("v4l2_subdev_call(s_stream) is fail(%d)", device, ret);
+ goto p_err;
+ }
+ } else {
+ struct fimc_is_device_ischain *ischain;
+
+ ischain = device->ischain;
+ if (!ischain) {
+ merr("ischain is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ ret = fimc_is_itf_stream_off(ischain);
+ if (ret) {
+ merr("fimc_is_itf_stream_off is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_tag(struct fimc_is_device_sensor *device,
+ struct fimc_is_frame *frame)
+{
+ int ret = 0;
+ frame->shot->dm.request.frameCount = frame->fcount;
+ frame->shot->dm.sensor.timeStamp = fimc_is_get_timestamp();
+
+ return ret;
+}
+
+static void fimc_is_sensor_control(struct work_struct *data)
+{
+/*
+ * HAL can't send meta data for vision
+ * We accepted vision control by s_ctrl
+ */
+#if 0
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct camera2_sensor_ctl *rsensor_ctl;
+ struct camera2_sensor_ctl *csensor_ctl;
+ struct fimc_is_device_sensor *device;
+
+ device = container_of(data, struct fimc_is_device_sensor, control_work);
+ subdev_module = device->subdev_module;
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ return;
+ }
+
+ module = v4l2_get_subdevdata(subdev_module);
+ rsensor_ctl = &device->control_frame->shot->ctl.sensor;
+ csensor_ctl = &device->sensor_ctl;
+
+ if (rsensor_ctl->exposureTime != csensor_ctl->exposureTime) {
+ CALL_MOPS(module, s_exposure, subdev_module, rsensor_ctl->exposureTime);
+ csensor_ctl->exposureTime = rsensor_ctl->exposureTime;
+ }
+
+ if (rsensor_ctl->frameDuration != csensor_ctl->frameDuration) {
+ CALL_MOPS(module, s_duration, subdev_module, rsensor_ctl->frameDuration);
+ csensor_ctl->frameDuration = rsensor_ctl->frameDuration;
+ }
+
+ if (rsensor_ctl->sensitivity != csensor_ctl->sensitivity) {
+ CALL_MOPS(module, s_again, subdev_module, rsensor_ctl->sensitivity);
+ csensor_ctl->sensitivity = rsensor_ctl->sensitivity;
+ }
+#endif
+}
+
+static int fimc_is_sensor_notify_by_fstr(struct fimc_is_device_sensor *device, void *arg)
+{
+ int ret = 0;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!device);
+ BUG_ON(!arg);
+
+ device->fcount = *(u32 *)arg;
+ framemgr = GET_DST_FRAMEMGR(device->vctx);
+
+ if (device->instant_cnt) {
+ device->instant_cnt--;
+ if (device->instant_cnt == 0)
+ wake_up(&device->instant_wait);
+ }
+
+ framemgr_e_barrier(framemgr, 0);
+
+ fimc_is_frame_process_head(framemgr, &frame);
+ if (frame) {
+#ifdef MEASURE_TIME
+#ifdef EXTERNAL_TIME
+ do_gettimeofday(&frame->tzone[TM_FLITE_STR]);
+#endif
+#endif
+ if (frame->has_fcount) {
+ struct list_head *temp;
+ struct fimc_is_frame *next_frame;
+ bool finded = false;
+
+ list_for_each(temp, &framemgr->frame_process_head) {
+ next_frame = list_entry(temp, struct fimc_is_frame, list);
+ if (next_frame->has_fcount) {
+ continue;
+ } else {
+ finded = true;
+ break;
+ }
+ }
+
+ if (finded) {
+ /* finded frame in processing frame list */
+ next_frame->has_fcount = true;
+ next_frame->fcount = device->fcount;
+ fimc_is_sensor_tag(device, next_frame);
+ }
+ } else {
+ frame->fcount = device->fcount;
+ fimc_is_sensor_tag(device, frame);
+ frame->has_fcount = true;
+ }
+ }
+#ifdef TASKLET_MSG
+ if (!frame) {
+ merr("[SEN] process is empty", device);
+ fimc_is_frame_print_all(framemgr);
+ }
+#endif
+
+ framemgr_x_barrier(framemgr, 0);
+
+ return ret;
+}
+
+static int fimc_is_sensor_notify_by_fend(struct fimc_is_device_sensor *device, void *arg)
+{
+ int ret = 0;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!device);
+ BUG_ON(!device->vctx);
+
+#ifdef ENABLE_DTP
+ if (device->dtp_check) {
+ device->dtp_check = false;
+ del_timer(&device->dtp_timer);
+ }
+
+ if (device->force_stop)
+ fimc_is_sensor_dtp((unsigned long)device);
+#endif
+
+ frame = (struct fimc_is_frame *)arg;
+ if (frame) {
+ frame->has_fcount = false;
+ buffer_done(device->vctx, frame->index);
+
+ /* device driving */
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state)) {
+ device->control_frame = frame;
+ schedule_work(&device->control_work);
+ }
+ }
+
+ return ret;
+}
+
+static void fimc_is_sensor_notify(struct v4l2_subdev *subdev,
+ unsigned int notification,
+ void *arg)
+{
+ int ret = 0;
+ struct fimc_is_device_sensor *device;
+
+ BUG_ON(!subdev);
+
+ device = v4l2_get_subdev_hostdata(subdev);
+
+ switch(notification) {
+ case FLITE_NOTIFY_FSTART:
+ ret = fimc_is_sensor_notify_by_fstr(device, arg);
+ if (ret)
+ merr("fimc_is_sensor_notify_by_fstr is fail(%d)", device, ret);
+ break;
+ case FLITE_NOTIFY_FEND:
+ ret = fimc_is_sensor_notify_by_fend(device, arg);
+ if (ret)
+ merr("fimc_is_sensor_notify_by_fend is fail(%d)", device, ret);
+ break;
+ }
+}
+
+static void fimc_is_sensor_instanton(struct work_struct *data)
+{
+ int ret = 0;
+ u32 instant_cnt;
+ struct fimc_is_device_sensor *device;
+
+ BUG_ON(!data);
+
+ device = container_of(data, struct fimc_is_device_sensor, instant_work);
+ instant_cnt = device->instant_cnt;
+
+ clear_bit(FIMC_IS_SENSOR_FRONT_DTP_STOP, &device->state);
+ clear_bit(FIMC_IS_SENSOR_BACK_NOWAIT_STOP, &device->state);
+
+ ret = fimc_is_sensor_start(device);
+ if (ret) {
+ merr("fimc_is_sensor_start is fail(%d)\n", device, ret);
+ goto p_err;
+ }
+ set_bit(FIMC_IS_SENSOR_FRONT_START, &device->state);
+
+#ifdef ENABLE_DTP
+ if (device->dtp_check) {
+ setup_timer(&device->dtp_timer, fimc_is_sensor_dtp, (unsigned long)device);
+ mod_timer(&device->dtp_timer, jiffies + msecs_to_jiffies(300));
+ info("DTP checking...\n");
+ }
+#endif
+
+ if (instant_cnt) {
+ u32 timetowait, timetoelapse, timeout;
+
+ timeout = FIMC_IS_FLITE_STOP_TIMEOUT + msecs_to_jiffies(instant_cnt*60);
+ timetowait = wait_event_timeout(device->instant_wait,
+ (device->instant_cnt == 0),
+ timeout);
+ if (!timetowait) {
+ merr("wait_event_timeout is invalid", device);
+ ret = -ETIME;
+ }
+
+ fimc_is_sensor_front_stop(device);
+
+ timetoelapse = (jiffies_to_msecs(timeout) - jiffies_to_msecs(timetowait));
+ info("[FRT:D:%d] instant off(fcount : %d, time : %dms)", device->instance,
+ device->instant_cnt,
+ timetoelapse);
+ }
+
+p_err:
+ device->instant_ret = ret;
+}
+
+static int fimc_is_sensor_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ u32 instance = -1;
+ atomic_t device_id;
+ struct fimc_is_core *core;
+ struct fimc_is_device_sensor *device;
+ struct device *dev;
+ void *pdata;
+
+ BUG_ON(!pdev);
+
+ if (fimc_is_dev == NULL) {
+ warn("fimc_is_dev is not yet probed");
+ pdev->dev.init_name = FIMC_IS_SENSOR_DEV_NAME;
+ return -EPROBE_DEFER;
+ }
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is NULL");
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_OF
+#ifdef CONFIG_COMPANION_USE
+ ret = fimc_is_sensor_parse_dt_with_companion(pdev);
+ if (ret) {
+ err("parsing device tree is fail(%d)", ret);
+ goto p_err;
+ }
+#else
+ ret = fimc_is_sensor_parse_dt(pdev);
+ if (ret) {
+ err("parsing device tree is fail(%d)", ret);
+ goto p_err;
+ }
+#endif /* CONFIG_COMPANION_USE */
+#endif /* CONFIG_OF */
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ err("pdata is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* 1. get device */
+ atomic_set(&device_id, pdev->id);
+ device = &core->sensor[pdev->id];
+
+ /* v4l2 device and device init */
+ memset(&device->v4l2_dev, 0, sizeof(struct v4l2_device));
+ instance = v4l2_device_set_name(&device->v4l2_dev, FIMC_IS_SENSOR_DEV_NAME, &device_id);
+ device->v4l2_dev.notify = fimc_is_sensor_notify;
+ device->instance = instance;
+ device->resourcemgr = &core->resourcemgr;
+ device->pdev = pdev;
+ device->private_data = core;
+ device->pdata = pdata;
+ platform_set_drvdata(pdev, device);
+ init_waitqueue_head(&device->instant_wait);
+ INIT_WORK(&device->instant_work, fimc_is_sensor_instanton);
+ INIT_WORK(&device->control_work, fimc_is_sensor_control);
+ spin_lock_init(&device->slock_state);
+ device_init_wakeup(&pdev->dev, true);
+
+ /* 3. state init*/
+ clear_bit(FIMC_IS_SENSOR_OPEN, &device->state);
+ clear_bit(FIMC_IS_SENSOR_MCLK_ON, &device->state);
+ clear_bit(FIMC_IS_SENSOR_ICLK_ON, &device->state);
+ clear_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state);
+ clear_bit(FIMC_IS_SENSOR_DRIVING, &device->state);
+ clear_bit(FIMC_IS_SENSOR_FRONT_START, &device->state);
+ clear_bit(FIMC_IS_SENSOR_FRONT_DTP_STOP, &device->state);
+ clear_bit(FIMC_IS_SENSOR_BACK_START, &device->state);
+ clear_bit(FIMC_IS_SENSOR_BACK_NOWAIT_STOP, &device->state);
+
+#ifdef ENABLE_DTP
+ device->dtp_check = false;
+#endif
+
+ ret = fimc_is_mem_probe(&device->mem, device->pdev);
+ if (ret) {
+ merr("fimc_is_mem_probe is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (device->mem.alloc_ctx)
+ vb2_ion_attach_iommu(device->mem.alloc_ctx);
+#endif
+#endif
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_enable(&pdev->dev);
+#endif
+
+ ret = v4l2_device_register(&pdev->dev, &device->v4l2_dev);
+ if (ret) {
+ merr("v4l2_device_register is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_csi_probe(device, device->pdata->csi_ch);
+ if (ret) {
+ merr("fimc_is_csi_probe is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_flite_probe(device, device->pdata->flite_ch);
+ if (ret) {
+ merr("fimc_is_flite_probe is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_sen_video_probe(device);
+ if (ret) {
+ merr("fimc_is_sensor_video_probe is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ dev = pdev->id ? camera_front_dev : camera_rear_dev;
+ if (dev)
+ dev_set_drvdata(dev, device->pdata);
+
+p_err:
+ info("[%d][SEN:D] %s(%d)\n", instance, __func__, ret);
+ return ret;
+}
+
+static int fimc_is_sensor_remove(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ info("%s\n", __func__);
+
+ return ret;
+}
+
+int fimc_is_sensor_open(struct fimc_is_device_sensor *device,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_csi);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (test_bit(FIMC_IS_SENSOR_OPEN, &device->state)) {
+ merr("already open", device);
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SENSOR_MCLK_ON, &device->state);
+ clear_bit(FIMC_IS_SENSOR_ICLK_ON, &device->state);
+ clear_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state);
+ clear_bit(FIMC_IS_SENSOR_DRIVING, &device->state);
+ clear_bit(FIMC_IS_SENSOR_FRONT_START, &device->state);
+ clear_bit(FIMC_IS_SENSOR_FRONT_DTP_STOP, &device->state);
+ clear_bit(FIMC_IS_SENSOR_BACK_START, &device->state);
+ set_bit(FIMC_IS_SENSOR_BACK_NOWAIT_STOP, &device->state);
+
+ device->vctx = vctx;
+ device->fcount = 0;
+ device->instant_cnt = 0;
+ device->instant_ret = 0;
+ device->ischain = NULL;
+ device->subdev_module = NULL;
+ device->exposure_time = 0;
+ device->frame_duration = 0;
+ device->force_stop = 0;
+ device->request_cam_qos = 0;
+ device->request_int_qos = 0;
+ device->request_mif_qos = 0;
+ memset(&device->sensor_ctl, 0, sizeof(struct camera2_sensor_ctl));
+ memset(&device->lens_ctl, 0, sizeof(struct camera2_lens_ctl));
+ memset(&device->flash_ctl, 0, sizeof(struct camera2_flash_ctl));
+
+ if (pdata->id == 0) {
+ core->running_rear_camera = true;
+ core->id = SENSOR_POSITION_REAR;
+ } else {
+ core->running_front_camera = true;
+ core->id = SENSOR_POSITION_FRONT;
+ }
+
+ /* for mediaserver force close */
+ ret = fimc_is_resource_get(device->resourcemgr, device->instance);
+ if (ret) {
+ merr("fimc_is_resource_get is fail", device);
+ goto p_err;
+ }
+
+ ret = fimc_is_csi_open(device->subdev_csi);
+ if (ret) {
+ merr("fimc_is_csi_open is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_flite_open(device->subdev_flite, GET_DST_FRAMEMGR(vctx));
+ if (ret) {
+ merr("fimc_is_flite_open is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_get_sync(&device->pdev->dev);
+#else
+ fimc_is_sensor_runtime_resume(&device->pdev->dev);
+#endif
+
+#ifdef ENABLE_DTP
+ device->dtp_check = true;
+#endif
+
+ set_bit(FIMC_IS_SENSOR_OPEN, &device->state);
+
+p_err:
+ info("[SEN:D:%d] %s(%d)\n", device->instance, __func__, ret);
+ return ret;
+}
+
+int fimc_is_sensor_close(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_group *group_3aa;
+ struct fimc_is_core *core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_SENSOR_OPEN, &device->state)) {
+ merr("already close", device);
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+ /* for mediaserver force close */
+ ischain = device->ischain;
+ if (ischain) {
+ group_3aa = &ischain->group_3aa;
+ if (test_bit(FIMC_IS_GROUP_READY, &group_3aa->state)) {
+ info("media server is dead, 3ax forcely done\n");
+ set_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &group_3aa->state);
+ }
+ }
+
+ ret = fimc_is_sensor_back_stop(device);
+ if (ret)
+ merr("fimc_is_sensor_back_stop is fail(%d)", device, ret);
+
+ ret = fimc_is_sensor_front_stop(device);
+ if (ret)
+ merr("fimc_is_sensor_front_stop is fail(%d)", device, ret);
+
+ ret = fimc_is_csi_close(device->subdev_csi);
+ if (ret)
+ merr("fimc_is_flite_close is fail(%d)", device, ret);
+
+ ret = fimc_is_flite_close(device->subdev_flite);
+ if (ret)
+ merr("fimc_is_flite_close is fail(%d)", device, ret);
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(&device->pdev->dev);
+#else
+ fimc_is_sensor_runtime_suspend(&device->pdev->dev);
+#endif
+
+ /* cancel a work and wait for it to finish */
+ cancel_work_sync(&device->control_work);
+ cancel_work_sync(&device->instant_work);
+
+ if (device->subdev_module) {
+ v4l2_device_unregister_subdev(device->subdev_module);
+ device->subdev_module = NULL;
+ }
+
+ /* for mediaserver force close */
+ ret = fimc_is_resource_put(device->resourcemgr, device->instance);
+ if (ret)
+ merr("fimc_is_resource_put is fail", device);
+
+ clear_bit(FIMC_IS_SENSOR_OPEN, &device->state);
+ set_bit(FIMC_IS_SENSOR_BACK_NOWAIT_STOP, &device->state);
+
+p_err:
+ if (pdata->id == 0) {
+ core->running_rear_camera = false;
+ } else {
+ core->running_front_camera = false;
+ }
+ info("[SEN:D:%d] %s(%d)\n", device->instance, __func__, ret);
+ return ret;
+}
+
+int fimc_is_sensor_s_input(struct fimc_is_device_sensor *device,
+ u32 input,
+ u32 scenario)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_module;
+ struct v4l2_subdev *subdev_csi;
+ struct v4l2_subdev *subdev_flite;
+ struct fimc_is_module_enum *module = NULL;
+ u32 sensor_ch, actuator_ch;
+#if defined(CONFIG_OIS_USE)
+ u32 ois_ch, ois_addr;
+#endif
+ u32 sensor_addr, actuator_addr;
+ u32 i = 0;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdata);
+ BUG_ON(!device->subdev_csi);
+ BUG_ON(input >= SENSOR_NAME_END);
+
+ for (i = 0; i < SENSOR_MAX_ENUM; i++) {
+ if (&device->module_enum[i] &&
+ device->module_enum[i].id == input) {
+ module = &device->module_enum[i];
+
+ /*
+ * If it is not normal scenario,
+ * try to find proper sensor module which has a i2c client
+ */
+ if (scenario != SENSOR_SCENARIO_NORMAL &&
+ module->client == NULL)
+ continue;
+ else
+ break;
+ }
+ }
+
+ if (i >= SENSOR_MAX_ENUM) {
+ merr("module is not probed", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ subdev_module = module->subdev;
+ if (!subdev_module) {
+ merr("module is not probed", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* change i2c channel info */
+ if (module->ext.sensor_con.peri_type == SE_I2C) {
+ sensor_ch = device->pdata->i2c_ch & SENSOR_I2C_CH_MASK;
+ sensor_ch >>= SENSOR_I2C_CH_SHIFT;
+ sensor_addr = device->pdata->i2c_addr & SENSOR_I2C_ADDR_MASK;
+ sensor_addr >>= SENSOR_I2C_ADDR_SHIFT;
+ module->ext.sensor_con.peri_setting.i2c.channel = sensor_ch;
+ module->ext.sensor_con.peri_setting.i2c.slave_address = sensor_addr;
+ }
+
+ if (module->ext.actuator_con.peri_type == SE_I2C) {
+ actuator_ch = device->pdata->i2c_ch & ACTUATOR_I2C_CH_MASK;
+ actuator_ch >>= ACTUATOR_I2C_CH_SHIFT;
+ actuator_addr = device->pdata->i2c_addr & ACTUATOR_I2C_ADDR_MASK;
+ actuator_addr >>= ACTUATOR_I2C_ADDR_SHIFT;
+ module->ext.actuator_con.peri_setting.i2c.channel = actuator_ch;
+ module->ext.actuator_con.peri_setting.i2c.slave_address = actuator_addr;
+ }
+
+#if defined(CONFIG_OIS_USE)
+ if (module->ext.ois_con.peri_type == SE_I2C) {
+ ois_ch = device->pdata->i2c_ch & OIS_I2C_CH_MASK;
+ ois_ch >>= OIS_I2C_CH_SHIFT;
+ ois_addr = device->pdata->i2c_addr & OIS_I2C_ADDR_MASK;
+ ois_addr >>= OIS_I2C_ADDR_SHIFT;
+ module->ext.ois_con.peri_setting.i2c.channel = ois_ch;
+ module->ext.ois_con.peri_setting.i2c.slave_address = ois_addr;
+ }
+#endif
+
+ /* send csi chennel to FW */
+ module->ext.sensor_con.csi_ch = device->pdata->csi_ch;
+ module->ext.sensor_con.csi_ch |= 0x0100;
+
+ module->ext.flash_con.peri_setting.gpio.first_gpio_port_no = device->pdata->flash_first_gpio;
+ module->ext.flash_con.peri_setting.gpio.second_gpio_port_no = device->pdata->flash_second_gpio;
+
+#ifdef CONFIG_COMPANION_USE
+ /* Data Type For Comapnion:
+ * Companion use user defined data type.
+ */
+ if (module->ext.companion_con.product_name &&
+ module->ext.companion_con.product_name != COMPANION_NAME_NOTHING)
+ device->image.format.field = V4L2_FIELD_INTERLACED;
+#endif
+
+ subdev_csi = device->subdev_csi;
+ subdev_flite = device->subdev_flite;
+ device->image.framerate = min_t(u32, SENSOR_DEFAULT_FRAMERATE, module->max_framerate);
+ device->image.window.width = module->pixel_width;
+ device->image.window.height = module->pixel_height;
+ device->image.window.o_width = device->image.window.width;
+ device->image.window.o_height = device->image.window.height;
+
+ if (scenario) {
+ device->pdata->scenario = scenario;
+ set_bit(FIMC_IS_SENSOR_DRIVING, &device->state);
+ } else {
+ device->pdata->scenario = SENSOR_SCENARIO_NORMAL;
+ clear_bit(FIMC_IS_SENSOR_DRIVING, &device->state);
+ }
+
+ if (device->subdev_module) {
+ mwarn("subdev_module is already registered", device);
+ v4l2_device_unregister_subdev(device->subdev_module);
+ }
+
+ ret = v4l2_device_register_subdev(&device->v4l2_dev, subdev_module);
+ if (ret) {
+ merr("v4l2_device_register_subdev is fail(%d)", device, ret);
+ goto p_err;
+ } else {
+ device->subdev_module = subdev_module;
+ }
+
+#if defined(CONFIG_PM_DEVFREQ)
+ /* DEVFREQ set */
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state))
+ fimc_is_sensor_set_qos_init(device, true);
+#endif
+
+ /* configuration clock control */
+ ret = fimc_is_sensor_iclk_on(device);
+ if (ret) {
+ merr("fimc_is_sensor_iclk_on is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+#if defined(CONFIG_PM_DEVFREQ)
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state))
+ fimc_is_sensor_set_qos_update(device, device->pdata->scenario);
+#endif
+
+ /* Sensor power on */
+ ret = fimc_is_sensor_gpio_on(device);
+ if (ret) {
+ merr("fimc_is_sensor_gpio_on is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = v4l2_subdev_call(subdev_flite, core, init, device->pdata->csi_ch);
+ if (ret) {
+ merr("v4l2_flite_call(init) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = v4l2_subdev_call(subdev_csi, core, init, (u32)module);
+ if (ret) {
+ merr("v4l2_csi_call(init) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state)) {
+ ret = v4l2_subdev_call(subdev_module, core, init, 0);
+ if (ret) {
+ merr("v4l2_module_call(init) is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+
+ minfo("[SEN:D] %s(%d, %d, %d)\n", device, __func__, input, scenario, ret);
+ return ret;
+}
+
+int fimc_is_sensor_s_format(struct fimc_is_device_sensor *device,
+ struct fimc_is_fmt *format,
+ u32 width,
+ u32 height)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_module;
+ struct v4l2_subdev *subdev_csi;
+ struct v4l2_subdev *subdev_flite;
+ struct fimc_is_module_enum *module;
+ struct v4l2_mbus_framefmt subdev_format;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_module);
+ BUG_ON(!device->subdev_csi);
+ BUG_ON(!device->subdev_flite);
+ BUG_ON(!device->subdev_module);
+ BUG_ON(!format);
+
+ subdev_module = device->subdev_module;
+ subdev_csi = device->subdev_csi;
+ subdev_flite = device->subdev_flite;
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev_module);
+ if (!module) {
+ merr("module is NULL", device);
+ goto p_err;
+ }
+
+ /* Data Type For Comapnion:
+ * Companion use user defined data type.
+ */
+ if (device->image.format.field == V4L2_FIELD_INTERLACED)
+ format->field = V4L2_FIELD_INTERLACED;
+
+ device->image.format = *format;
+ device->image.window.offs_h = 0;
+ device->image.window.offs_v = 0;
+ device->image.window.width = width;
+ device->image.window.o_width = width;
+ device->image.window.height = height;
+ device->image.window.o_height = height;
+
+ subdev_format.code = format->pixelformat;
+ subdev_format.field = format->field;
+ subdev_format.width = width;
+ subdev_format.height = height;
+
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state)) {
+ ret = v4l2_subdev_call(subdev_module, video, s_mbus_fmt, &subdev_format);
+ if (ret) {
+ merr("v4l2_module_call(s_format) is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ ret = v4l2_subdev_call(subdev_csi, video, s_mbus_fmt, &subdev_format);
+ if (ret) {
+ merr("v4l2_csi_call(s_format) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = v4l2_subdev_call(subdev_flite, video, s_mbus_fmt, &subdev_format);
+ if (ret) {
+ merr("v4l2_flite_call(s_format) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ /* if sensor is driving mode, skip finding sensor mode */
+ if (!test_bit(FIMC_IS_SENSOR_DRIVING, &device->state))
+ device->mode = get_sensor_mode(module->cfg, module->cfgs,
+ device->image.window.width, device->image.window.height,
+ device->image.framerate);
+ else
+ device->mode = 0;
+
+ /* can't find proper sensor mode */
+ if (device->mode < 0) {
+ ret = -EINVAL;
+ goto p_err;
+ }
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_s_framerate(struct fimc_is_device_sensor *device,
+ struct v4l2_streamparm *param)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_module;
+ struct v4l2_subdev *subdev_csi;
+ struct fimc_is_module_enum *module;
+ struct v4l2_captureparm *cp;
+ struct v4l2_fract *tpf;
+ u32 framerate = 0;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_module);
+ BUG_ON(!device->subdev_csi);
+ BUG_ON(!param);
+
+ cp = ¶m->parm.capture;
+ tpf = &cp->timeperframe;
+
+ if (!tpf->numerator) {
+ merr("numerator is 0", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framerate = tpf->denominator / tpf->numerator;
+ subdev_module = device->subdev_module;
+ subdev_csi = device->subdev_csi;
+
+ if (framerate == 0) {
+ mwarn("frame rate 0 request is ignored", device);
+ goto p_err;
+ }
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev_module);
+ if (!module) {
+ merr("module is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) {
+ merr("front is already stream on", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ merr("type is invalid(%d)", device, param->type);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (framerate > module->max_framerate) {
+ merr("framerate is invalid(%d > %d)", device, framerate, module->max_framerate);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = v4l2_subdev_call(subdev_csi, video, s_parm, param);
+ if (ret) {
+ merr("v4l2_csi_call(s_param) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state)) {
+ ret = v4l2_subdev_call(subdev_module, video, s_parm, param);
+ if (ret) {
+ merr("v4l2_module_call(s_param) is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+
+ device->image.framerate = framerate;
+
+ device->mode = get_sensor_mode(module->cfg, module->cfgs,
+ device->image.window.width, device->image.window.height,
+ framerate);
+
+ info("[SEN:D:%d] framerate: req@%dfps, cur@%dfps\n", device->instance,
+ framerate, device->image.framerate);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_s_ctrl(struct fimc_is_device_sensor *device,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_module;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_module);
+ BUG_ON(!device->subdev_csi);
+ BUG_ON(!ctrl);
+
+ subdev_module = device->subdev_module;
+
+ ret = v4l2_subdev_call(subdev_module, core, s_ctrl, ctrl);
+ if (ret) {
+ err("s_ctrl is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_s_bns(struct fimc_is_device_sensor *device,
+ u32 ratio)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_flite;
+ u32 sensor_width, sensor_height;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_flite);
+
+ subdev_flite = device->subdev_flite;
+
+ sensor_width = fimc_is_sensor_g_width(device);
+ sensor_height = fimc_is_sensor_g_height(device);
+ if (!sensor_width || !sensor_height) {
+ merr("Sensor size is zero. Sensor set_format first.\n", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device->image.window.otf_width
+ = rounddown((sensor_width * 1000 / ratio), 4);
+ device->image.window.otf_height
+ = rounddown((sensor_height * 1000 / ratio), 2);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_s_frame_duration(struct fimc_is_device_sensor *device,
+ u32 framerate)
+{
+ int ret = 0;
+ u64 frame_duration;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!device);
+
+ subdev_module = device->subdev_module;
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ module = v4l2_get_subdevdata(subdev_module);
+ if (!module) {
+ err("module is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* unit : nano */
+ frame_duration = (1000 * 1000 * 1000) / framerate;
+ if (frame_duration <= 0) {
+ err("it is wrong frame duration(%lld)", frame_duration);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (device->frame_duration != frame_duration) {
+ CALL_MOPS(module, s_duration, subdev_module, frame_duration);
+ device->frame_duration = frame_duration;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_s_exposure_time(struct fimc_is_device_sensor *device,
+ u32 exposure_time)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!device);
+
+ subdev_module = device->subdev_module;
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ module = v4l2_get_subdevdata(subdev_module);
+ if (!module) {
+ err("module is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (exposure_time <= 0) {
+ err("it is wrong exposure time (%d)", exposure_time);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (device->exposure_time != exposure_time) {
+ CALL_MOPS(module, s_exposure, subdev_module, exposure_time);
+ device->exposure_time = exposure_time;
+ }
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_g_ctrl(struct fimc_is_device_sensor *device,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_module;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_module);
+ BUG_ON(!device->subdev_csi);
+ BUG_ON(!ctrl);
+
+ subdev_module = device->subdev_module;
+
+ ret = v4l2_subdev_call(subdev_module, core, g_ctrl, ctrl);
+ if (ret) {
+ err("g_ctrl is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+
+int fimc_is_sensor_g_instance(struct fimc_is_device_sensor *device)
+{
+ BUG_ON(!device);
+ return device->instance;
+}
+
+int fimc_is_sensor_g_fcount(struct fimc_is_device_sensor *device)
+{
+ BUG_ON(!device);
+ return device->fcount;
+}
+
+int fimc_is_sensor_g_framerate(struct fimc_is_device_sensor *device)
+{
+ BUG_ON(!device);
+ return device->image.framerate;
+}
+
+int fimc_is_sensor_g_width(struct fimc_is_device_sensor *device)
+{
+ BUG_ON(!device);
+ return device->image.window.width;
+}
+
+int fimc_is_sensor_g_height(struct fimc_is_device_sensor *device)
+{
+ BUG_ON(!device);
+ return device->image.window.height;
+}
+
+int fimc_is_sensor_g_bns_width(struct fimc_is_device_sensor *device)
+{
+ BUG_ON(!device);
+
+ if (device->image.window.otf_width)
+ return device->image.window.otf_width;
+
+ return device->image.window.width;
+}
+
+int fimc_is_sensor_g_bns_height(struct fimc_is_device_sensor *device)
+{
+ BUG_ON(!device);
+ if (device->image.window.otf_height)
+ return device->image.window.otf_height;
+
+ return device->image.window.height;
+}
+
+int fimc_is_sensor_g_bns_ratio(struct fimc_is_device_sensor *device)
+{
+ int binning = 0;
+ u32 sensor_width, sensor_height;
+ u32 bns_width, bns_height;
+
+ BUG_ON(!device);
+
+ sensor_width = fimc_is_sensor_g_width(device);
+ sensor_height = fimc_is_sensor_g_height(device);
+ bns_width = fimc_is_sensor_g_bns_width(device);
+ bns_height = fimc_is_sensor_g_bns_height(device);
+
+ binning = min(BINNING(sensor_width, bns_width),
+ BINNING(sensor_height, bns_height));
+
+ return binning;
+}
+
+int fimc_is_sensor_g_bratio(struct fimc_is_device_sensor *device)
+{
+ int binning = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_module);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(device->subdev_module);
+ if (!module) {
+ merr("module is NULL", device);
+ goto p_err;
+ }
+
+ binning = min(BINNING(module->active_width, device->image.window.width),
+ BINNING(module->active_height, device->image.window.height));
+
+p_err:
+ return binning;
+}
+
+int fimc_is_sensor_g_module(struct fimc_is_device_sensor *device,
+ struct fimc_is_module_enum **module)
+{
+ int ret = 0;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_module);
+
+ *module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(device->subdev_module);
+ if (!*module) {
+ merr("module is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_buffer_queue(struct fimc_is_device_sensor *device,
+ u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame *frame;
+ struct fimc_is_framemgr *framemgr;
+
+ if (index >= FRAMEMGR_MAX_REQUEST) {
+ err("index(%d) is invalid", index);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr = &device->vctx->q_dst->framemgr;
+ if (framemgr == NULL) {
+ err("framemgr is null\n");
+ ret = EINVAL;
+ goto p_err;
+ }
+
+ frame = &framemgr->frame[index];
+ if (frame == NULL) {
+ err("frame is null\n");
+ ret = EINVAL;
+ goto p_err;
+ }
+
+ if (unlikely(!test_bit(FRAME_INI_MEM, &frame->memory))) {
+ err("frame %d is NOT init", index);
+ ret = EINVAL;
+ goto p_err;
+ }
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_2 + index, flags);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_FREE) {
+ fimc_is_frame_trans_fre_to_req(framemgr, frame);
+ } else {
+ err("frame(%d) is not free state(%d)", index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_2 + index, flags);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_buffer_finish(struct fimc_is_device_sensor *device,
+ u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame *frame;
+ struct fimc_is_framemgr *framemgr;
+
+ if (index >= FRAMEMGR_MAX_REQUEST) {
+ err("index(%d) is invalid", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ framemgr = &device->vctx->q_dst->framemgr;
+ frame = &framemgr->frame[index];
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_3 + index, flags);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_COMPLETE) {
+ if (!frame->shot->dm.request.frameCount)
+ err("request.frameCount is 0\n");
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+
+ frame->shot_ext->free_cnt = framemgr->frame_fre_cnt;
+ frame->shot_ext->request_cnt = framemgr->frame_req_cnt;
+ frame->shot_ext->process_cnt = framemgr->frame_pro_cnt;
+ frame->shot_ext->complete_cnt = framemgr->frame_com_cnt;
+ } else {
+ err("frame(%d) is not com state(%d)", index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_3 + index, flags);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_back_start(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ int enable;
+ struct v4l2_subdev *subdev_flite;
+ struct fimc_is_device_flite *flite;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_flite);
+
+ subdev_flite = device->subdev_flite;
+ enable = FLITE_ENABLE_FLAG;
+
+ if (test_bit(FIMC_IS_SENSOR_BACK_START, &device->state)) {
+ err("already back start");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ flite = (struct fimc_is_device_flite *)v4l2_get_subdevdata(subdev_flite);
+ if (!flite) {
+ merr("flite is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* to determine flite buffer done mode (early/normal) when not vision mode */
+ if (!test_bit(FIMC_IS_SENSOR_DRIVING, &device->state) && flite->chk_early_buf_done) {
+ flite->chk_early_buf_done(flite, device->image.framerate,
+ device->pdev->id);
+ }
+
+ ret = v4l2_subdev_call(subdev_flite, video, s_stream, enable);
+ if (ret) {
+ merr("v4l2_flite_call(s_stream) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_SENSOR_BACK_START, &device->state);
+
+p_err:
+ minfo("[SEN:D] %s(%dx%d, %d)\n", device, __func__,
+ device->image.window.width, device->image.window.height, ret);
+ return ret;
+}
+
+int fimc_is_sensor_back_stop(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ int enable;
+ struct v4l2_subdev *subdev_flite;
+
+ BUG_ON(!device);
+ BUG_ON(!device->subdev_flite);
+
+ enable = 0;
+ subdev_flite = device->subdev_flite;
+
+ if (!test_bit(FIMC_IS_SENSOR_BACK_START, &device->state)) {
+ warn("already back stop");
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SENSOR_BACK_NOWAIT_STOP, &device->state)) {
+ warn("fimc_is_flite_stop, no waiting...");
+ enable = FLITE_NOWAIT_FLAG << FLITE_NOWAIT_SHIFT;
+ }
+
+ ret = v4l2_subdev_call(subdev_flite, video, s_stream, enable);
+ if (ret) {
+ merr("v4l2_flite_call(s_stream) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SENSOR_BACK_START, &device->state);
+
+p_err:
+ minfo("[BAK:D] %s(%d)\n", device, __func__, ret);
+ return ret;
+}
+
+int fimc_is_sensor_front_start(struct fimc_is_device_sensor *device,
+ u32 instant_cnt,
+ u32 nonblock)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_module;
+ struct v4l2_subdev *subdev_csi;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdata);
+ BUG_ON(!device->subdev_csi);
+
+ if (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) {
+ merr("already front start", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device->instant_cnt = instant_cnt;
+ subdev_csi = device->subdev_csi;
+ subdev_module = device->subdev_module;
+ if (!subdev_module) {
+ merr("subdev_module is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev_module);
+ if (!module) {
+ merr("module is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = v4l2_subdev_call(subdev_csi, video, s_stream, IS_ENABLE_STREAM);
+ if (ret) {
+ merr("v4l2_csi_call(s_stream) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ mdbgd_sensor("%s(snesor id : %d, csi ch : %d, size : %d x %d)\n", device,
+ __func__,
+ module->id,
+ device->pdata->csi_ch,
+ device->image.window.width,
+ device->image.window.height);
+
+ if (nonblock) {
+ schedule_work(&device->instant_work);
+ } else {
+ fimc_is_sensor_instanton(&device->instant_work);
+ if (device->instant_ret) {
+ merr("fimc_is_sensor_instanton is fail(%d)", device, device->instant_ret);
+ ret = device->instant_ret;
+ goto p_err;
+ }
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_sensor_front_stop(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct v4l2_subdev *subdev_csi;
+
+ BUG_ON(!device);
+
+ if (!test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) {
+ warn("already front stop");
+ goto p_err;
+ }
+
+ subdev_csi = device->subdev_csi;
+
+ ret = fimc_is_sensor_stop(device);
+ if (ret)
+ merr("sensor stream off is failed(%d)\n", device, ret);
+
+ ret = v4l2_subdev_call(subdev_csi, video, s_stream, IS_DISABLE_STREAM);
+ if (ret)
+ merr("v4l2_csi_call(s_stream) is fail(%d)", device, ret);
+
+ set_bit(FIMC_IS_SENSOR_BACK_NOWAIT_STOP, &device->state);
+ clear_bit(FIMC_IS_SENSOR_FRONT_START, &device->state);
+
+p_err:
+ minfo("[FRT:D] %s(%d)\n", device, __func__, ret);
+ return ret;
+}
+
+int fimc_is_sensor_gpio_off_softlanding(struct fimc_is_device_sensor *device)
+{
+ int ret = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+
+ BUG_ON(!device);
+ BUG_ON(!device->pdev);
+ BUG_ON(!device->pdata);
+
+ pdata = device->pdata;
+
+ if (!test_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state)) {
+ merr("%s : already gpio off", device, __func__);
+ goto p_err;
+ }
+
+ if (!pdata->gpio_cfg) {
+ merr("gpio_cfg is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = pdata->gpio_cfg(device->pdev, pdata->scenario, GPIO_SCENARIO_OFF);
+ if (ret) {
+ merr("gpio_cfg is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ clear_bit(FIMC_IS_SENSOR_GPIO_ON, &device->state);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sensor_suspend(struct device *dev)
+{
+ int ret = 0;
+
+ info("%s\n", __func__);
+
+ return ret;
+}
+
+static int fimc_is_sensor_resume(struct device *dev)
+{
+ int ret = 0;
+
+ info("%s\n", __func__);
+
+ return ret;
+}
+
+int fimc_is_sensor_runtime_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_device_sensor *device;
+ struct v4l2_subdev *subdev_csi;
+
+ info("%s\n", __func__);
+
+ BUG_ON(!pdev);
+
+ device = (struct fimc_is_device_sensor *)platform_get_drvdata(pdev);
+ if (!device) {
+ err("device is NULL");
+ return -EINVAL;
+ }
+
+#if !(defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433))
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (device->mem.alloc_ctx)
+ vb2_ion_detach_iommu(device->mem.alloc_ctx);
+#endif
+#endif
+
+ subdev_csi = device->subdev_csi;
+ if (!subdev_csi)
+ mwarn("subdev_csi is NULL", device);
+
+ /* gpio uninit */
+ if(device->pdata->is_softlanding == false) {
+ ret = fimc_is_sensor_gpio_off(device);
+ if (ret) {
+ mwarn("fimc_is_sensor_gpio_off is fail(%d)", device, ret);
+ }
+ }
+
+ /* GSCL internal clock off */
+ ret = fimc_is_sensor_iclk_off(device);
+ if (ret)
+ mwarn("fimc_is_sensor_iclk_off is fail(%d)", device, ret);
+
+ /* Sensor clock on */
+ ret = fimc_is_sensor_mclk_off(device);
+ if (ret)
+ mwarn("fimc_is_sensor_mclk_off is fail(%d)", device, ret);
+
+ ret = v4l2_subdev_call(subdev_csi, core, s_power, 0);
+ if (ret)
+ mwarn("v4l2_csi_call(s_power) is fail(%d)", device, ret);
+
+#if defined(CONFIG_PM_DEVFREQ)
+ /* DEVFREQ set */
+ if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state))
+ fimc_is_sensor_set_qos_init(device, false);
+#endif
+
+ info("[SEN:D:%d] %s(%d)\n", device->instance, __func__, ret);
+ return 0;
+}
+
+int fimc_is_sensor_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_device_sensor *device;
+ struct v4l2_subdev *subdev_csi;
+
+ device = (struct fimc_is_device_sensor *)platform_get_drvdata(pdev);
+ if (!device) {
+ err("device is NULL");
+ return -EINVAL;
+ }
+
+ subdev_csi = device->subdev_csi;
+ if (!subdev_csi) {
+ merr("subdev_csi is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+/* HACK */
+/* at xyref 4415, when runtime_suspend operating, isp0 power is off thoroughly
+ so it needs to power on operation at sensor_runtime_resume operation */
+#if defined(CONFOG_SOC_EXYNOS4415) && !defined(CONFIG_PM_RUNTIME)
+ {
+ u32 val;
+ /* ISP0 */
+ /* 1. set feedback mode */
+ val = __raw_readl(PMUREG_ISP0_OPTION);
+ val = (val & ~(0x3<< 0)) | (0x2 << 0);
+ __raw_writel(val, PMUREG_ISP0_OPTION);
+
+ /* 2. power on isp0 */
+ val = __raw_readl(PMUREG_ISP0_CONFIGURATION);
+ val = (val & ~(0x7 << 0)) | (0x7 << 0);
+ __raw_writel(val, PMUREG_ISP0_CONFIGURATION);
+ }
+#endif
+
+ /* 1. Enable MIPI */
+ ret = v4l2_subdev_call(subdev_csi, core, s_power, 1);
+ if (ret) {
+ merr("v4l2_csi_call(s_power) is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ /* 2. Sensor clock on */
+ ret = fimc_is_sensor_mclk_on(device);
+ if (ret) {
+ merr("fimc_is_sensor_mclk_on is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+#if !(defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433))
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (device->mem.alloc_ctx)
+ vb2_ion_attach_iommu(device->mem.alloc_ctx);
+ pr_debug("FIMC_IS runtime resume - ion attach complete\n");
+#endif
+#endif
+
+p_err:
+ info("[SEN:D:%d] %s(%d)\n", device->instance, __func__, ret);
+ return ret;
+}
+
+static const struct dev_pm_ops fimc_is_sensor_pm_ops = {
+ .suspend = fimc_is_sensor_suspend,
+ .resume = fimc_is_sensor_resume,
+ .runtime_suspend = fimc_is_sensor_runtime_suspend,
+ .runtime_resume = fimc_is_sensor_runtime_resume,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_fimc_is_sensor_match[] = {
+ {
+ .compatible = "samsung,exynos5-fimc-is-sensor",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_fimc_is_sensor_match);
+
+static struct platform_driver fimc_is_sensor_driver = {
+ .probe = fimc_is_sensor_probe,
+ .remove = fimc_is_sensor_remove,
+ .driver = {
+ .name = FIMC_IS_SENSOR_DEV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_sensor_pm_ops,
+ .of_match_table = exynos_fimc_is_sensor_match,
+ }
+};
+
+module_platform_driver(fimc_is_sensor_driver);
+#else
+static struct platform_device_id fimc_is_sensor_driver_ids[] = {
+ {
+ .name = FIMC_IS_SENSOR_DEV_NAME,
+ .driver_data = 0,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, fimc_is_sensor_driver_ids);
+
+static struct platform_driver fimc_is_sensor_driver = {
+ .probe = fimc_is_sensor_probe,
+ .remove = __devexit_p(fimc_is_sensor_remove),
+ .id_table = fimc_is_sensor_driver_ids,
+ .driver = {
+ .name = FIMC_IS_SENSOR_DEV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_sensor_pm_ops,
+ }
+};
+
+static int __init fimc_is_sensor_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_register(&fimc_is_sensor_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+
+ return ret;
+}
+
+static void __exit fimc_is_sensor_exit(void)
+{
+ platform_driver_unregister(&fimc_is_sensor_driver);
+}
+module_init(fimc_is_sensor_init);
+module_exit(fimc_is_sensor_exit);
+#endif
+
+MODULE_AUTHOR("Gilyeon lim<kilyeon.im@samsung.com>");
+MODULE_DESCRIPTION("Exynos FIMC_IS_SENSOR driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 fimc_is_device_sensor_H
+#define fimc_is_device_sensor_H
+
+#include <mach/exynos-fimc-is-sensor.h>
+#include "fimc-is-mem.h"
+#include "fimc-is-video.h"
+#include "fimc-is-resourcemgr.h"
+#include "fimc-is-device-flite.h"
+#include "fimc-is-device-csi.h"
+
+struct fimc_is_video_ctx;
+struct fimc_is_device_ischain;
+
+#define SENSOR_MAX_ENUM 20
+#define SENSOR_DEFAULT_FRAMERATE 30
+
+#define SENSOR_SCENARIO_MASK 0xF0000000
+#define SENSOR_SCENARIO_SHIFT 28
+#define SENSOR_MODULE_MASK 0x0FFFFFFF
+#define SENSOR_MODULE_SHIFT 0
+
+#define SENSOR_SSTREAM_MASK 0x0000000F
+#define SENSOR_SSTREAM_SHIFT 0
+#define SENSOR_INSTANT_MASK 0x0FFF0000
+#define SENSOR_INSTANT_SHIFT 16
+#define SENSOR_NOBLOCK_MASK 0xF0000000
+#define SENSOR_NOBLOCK_SHIFT 28
+
+#define SENSOR_I2C_CH_MASK 0xFF
+#define SENSOR_I2C_CH_SHIFT 0
+#define ACTUATOR_I2C_CH_MASK 0xFF00
+#define ACTUATOR_I2C_CH_SHIFT 8
+#define OIS_I2C_CH_MASK 0xFF0000
+#define OIS_I2C_CH_SHIFT 16
+
+#define SENSOR_I2C_ADDR_MASK 0xFF
+#define SENSOR_I2C_ADDR_SHIFT 0
+#define ACTUATOR_I2C_ADDR_MASK 0xFF00
+#define ACTUATOR_I2C_ADDR_SHIFT 8
+#define OIS_I2C_ADDR_MASK 0xFF0000
+#define OIS_I2C_ADDR_SHIFT 16
+
+#define FIMC_IS_SENSOR_CFG(w, h, f, s, m) { \
+ .width = w, \
+ .height = h, \
+ .framerate = f, \
+ .settle = s, \
+ .mode = m, \
+}
+
+enum fimc_is_sensor_output_entity {
+ FIMC_IS_SENSOR_OUTPUT_NONE = 0,
+ FIMC_IS_SENSOR_OUTPUT_FRONT,
+};
+
+enum fimc_is_sensor_force_stop {
+ FIMC_IS_BAD_FRAME_STOP = 0,
+ FIMC_IS_MIF_THROTTLING_STOP = 1,
+ FIMC_IS_FLITE_OVERFLOW_STOP = 2
+};
+
+struct fimc_is_sensor_cfg {
+ u32 width;
+ u32 height;
+ u32 framerate;
+ u32 settle;
+ int mode;
+};
+
+struct fimc_is_sensor_ops {
+ int (*stream_on)(struct v4l2_subdev *subdev);
+ int (*stream_off)(struct v4l2_subdev *subdev);
+
+ int (*s_duration)(struct v4l2_subdev *subdev, u64 duration);
+ int (*g_min_duration)(struct v4l2_subdev *subdev);
+ int (*g_max_duration)(struct v4l2_subdev *subdev);
+
+ int (*s_exposure)(struct v4l2_subdev *subdev, u64 exposure);
+ int (*g_min_exposure)(struct v4l2_subdev *subdev);
+ int (*g_max_exposure)(struct v4l2_subdev *subdev);
+
+ int (*s_again)(struct v4l2_subdev *subdev, u64 sensivity);
+ int (*g_min_again)(struct v4l2_subdev *subdev);
+ int (*g_max_again)(struct v4l2_subdev *subdev);
+
+ int (*s_dgain)(struct v4l2_subdev *subdev);
+ int (*g_min_dgain)(struct v4l2_subdev *subdev);
+ int (*g_max_dgain)(struct v4l2_subdev *subdev);
+};
+
+struct fimc_is_module_enum {
+ u32 id;
+ struct v4l2_subdev *subdev; /* connected module subdevice */
+ u32 device; /* connected sensor device */
+ u32 pixel_width;
+ u32 pixel_height;
+ u32 active_width;
+ u32 active_height;
+ u32 max_framerate;
+ u32 position;
+ u32 mode;
+ u32 lanes;
+ u32 vcis; /* vci is valid only if mode is vc mode */
+ struct fimc_is_vci *vci;
+ u32 cfgs;
+ struct fimc_is_sensor_cfg *cfg;
+ struct i2c_client *client;
+ struct sensor_open_extended ext;
+ struct fimc_is_sensor_ops *ops;
+ char *sensor_maker;
+ char *sensor_name;
+ char *setfile_name;
+ void *private_data;
+ int (*power_setpin)(struct device *);
+};
+
+enum fimc_is_sensor_state {
+ FIMC_IS_SENSOR_OPEN,
+ FIMC_IS_SENSOR_MCLK_ON,
+ FIMC_IS_SENSOR_ICLK_ON,
+ FIMC_IS_SENSOR_GPIO_ON,
+ FIMC_IS_SENSOR_DRIVING,
+ FIMC_IS_SENSOR_FRONT_START,
+ FIMC_IS_SENSOR_FRONT_DTP_STOP,
+ FIMC_IS_SENSOR_BACK_START,
+ FIMC_IS_SENSOR_BACK_NOWAIT_STOP
+};
+
+struct fimc_is_device_sensor {
+ struct v4l2_device v4l2_dev;
+ struct platform_device *pdev;
+ struct fimc_is_mem mem;
+
+ u32 instance;
+ struct fimc_is_image image;
+
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_video video;
+
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_resourcemgr *resourcemgr;
+ struct fimc_is_module_enum module_enum[SENSOR_MAX_ENUM];
+
+ /* current control value */
+ struct camera2_sensor_ctl sensor_ctl;
+ struct camera2_lens_ctl lens_ctl;
+ struct camera2_flash_ctl flash_ctl;
+ struct work_struct control_work;
+ struct fimc_is_frame *control_frame;
+
+ u32 fcount;
+ u32 instant_cnt;
+ int instant_ret;
+ wait_queue_head_t instant_wait;
+ struct work_struct instant_work;
+ unsigned long state;
+ spinlock_t slock_state;
+
+ /* hardware configuration */
+ struct v4l2_subdev *subdev_module;
+ struct v4l2_subdev *subdev_csi;
+ struct v4l2_subdev *subdev_flite;
+
+ int mode;
+ /* gain boost */
+ int min_target_fps;
+ int max_target_fps;
+ int scene_mode;
+
+ /* for vision control */
+ int exposure_time;
+ u64 frame_duration;
+
+ /* ENABLE_DTP */
+ bool dtp_check;
+ struct timer_list dtp_timer;
+ unsigned long force_stop;
+
+ struct exynos_platform_fimc_is_sensor *pdata;
+ void *private_data;
+
+ /* DVFS state */
+ bool request_cam_qos;
+ bool request_int_qos;
+ bool request_mif_qos;
+};
+
+int fimc_is_sensor_open(struct fimc_is_device_sensor *device,
+ struct fimc_is_video_ctx *vctx);
+int fimc_is_sensor_close(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_s_input(struct fimc_is_device_sensor *device,
+ u32 input,
+ u32 scenario);
+int fimc_is_sensor_s_format(struct fimc_is_device_sensor *device,
+ struct fimc_is_fmt *format,
+ u32 width,
+ u32 height);
+int fimc_is_sensor_s_ctrl(struct fimc_is_device_sensor *device,
+ struct v4l2_control *ctrl);
+int fimc_is_sensor_buffer_queue(struct fimc_is_device_sensor *device,
+ u32 index);
+int fimc_is_sensor_buffer_finish(struct fimc_is_device_sensor *device,
+ u32 index);
+
+int fimc_is_sensor_front_start(struct fimc_is_device_sensor *device,
+ u32 instant_cnt,
+ u32 nonblock);
+int fimc_is_sensor_front_stop(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_back_start(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_back_stop(struct fimc_is_device_sensor *device);
+
+int fimc_is_sensor_s_framerate(struct fimc_is_device_sensor *device,
+ struct v4l2_streamparm *param);
+int fimc_is_sensor_s_bns(struct fimc_is_device_sensor *device,
+ u32 reatio);
+
+int fimc_is_sensor_s_frame_duration(struct fimc_is_device_sensor *device,
+ u32 frame_duration);
+int fimc_is_sensor_s_exposure_time(struct fimc_is_device_sensor *device,
+ u32 exposure_time);
+
+int fimc_is_sensor_g_ctrl(struct fimc_is_device_sensor *device,
+ struct v4l2_control *ctrl);
+int fimc_is_sensor_g_instance(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_framerate(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_fcount(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_width(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_height(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_bns_width(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_bns_height(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_bns_ratio(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_bratio(struct fimc_is_device_sensor *device);
+int fimc_is_sensor_g_module(struct fimc_is_device_sensor *device,
+ struct fimc_is_module_enum **module);
+int fimc_is_sensor_gpio_off_softlanding(struct fimc_is_device_sensor *device);
+
+/* sensor driver */
+int fimc_is_sensor_read8(struct i2c_client *client,
+ u16 addr, u8 *val);
+int fimc_is_sensor_read16(struct i2c_client *client,
+ u16 addr, u16 *val);
+int fimc_is_sensor_write(struct i2c_client *client,
+ u8 *buf, u32 size);
+int fimc_is_sensor_write8(struct i2c_client *client,
+ u16 addr, u8 val);
+int fimc_is_sensor_write16(struct i2c_client *client,
+ u16 addr, u16 val);
+
+#define CALL_MOPS(s, op, args...) (((s)->ops->op) ? ((s)->ops->op(args)) : 0)
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/sched.h>
+#include <mach/exynos-fimc-is-sensor.h>
+#include <mach/exynos-fimc-is.h>
+#include <media/exynos_mc.h>
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#endif
+
+#include "fimc-is-core.h"
+#include "fimc-is-dt.h"
+
+#ifdef CONFIG_OF
+int get_pin_lookup_state(struct device *dev,
+ struct exynos_platform_fimc_is_sensor *pdata)
+{
+ int ret = 0;
+ u32 i, j, k;
+ char ch_name[30];
+ struct exynos_sensor_pin (*pin_ctrls)[2][GPIO_CTRL_MAX];
+ struct pinctrl_state *s;
+
+ pin_ctrls = pdata->pin_ctrls;
+
+ for (i = 0; i < SENSOR_SCENARIO_MAX; ++i) {
+ for (j = 0; j < GPIO_SCENARIO_MAX; ++j) {
+ for (k = 0; k < GPIO_CTRL_MAX; ++k) {
+ if (pin_ctrls[i][j][k].act == PIN_FUNCTION) {
+ snprintf(ch_name, sizeof(ch_name), "%s%d",
+ pin_ctrls[i][j][k].name,
+ pdata->csi_ch);
+ s = pinctrl_lookup_state(pdata->pinctrl, ch_name);
+ if (IS_ERR(s)) {
+ err("cam %s, ch %d pinctrl_lookup_state is failed", ch_name, pdata->csi_ch);
+ ret = -EINVAL;
+ goto p_err;
+ } else {
+ pin_ctrls[i][j][k].pin = (unsigned long)s;
+ pr_info("[%d][%d][%d][%s] gpio function cfg is seted", i, j, k, ch_name);
+ }
+ }
+ }
+ }
+ }
+
+p_err:
+ return ret;
+}
+
+static int parse_gate_info(struct exynos_platform_fimc_is *pdata, struct device_node *np)
+{
+ int ret = 0;
+ struct device_node *group_np = NULL;
+ struct device_node *gate_info_np;
+ struct property *prop;
+ struct property *prop2;
+ const __be32 *p;
+ const char *s;
+ u32 i = 0, u = 0;
+ struct exynos_fimc_is_clk_gate_info *gate_info;
+
+ /* get subip of fimc-is info */
+ gate_info = kzalloc(sizeof(struct exynos_fimc_is_clk_gate_info), GFP_KERNEL);
+ if (!gate_info) {
+ printk(KERN_ERR "%s: no memory for fimc_is gate_info\n", __func__);
+ return -EINVAL;
+ }
+
+ s = NULL;
+ /* get gate register info */
+ prop2 = of_find_property(np, "clk_gate_strs", NULL);
+ of_property_for_each_u32(np, "clk_gate_enums", prop, p, u) {
+ printk(KERN_INFO "int value: %d\n", u);
+ s = of_prop_next_string(prop2, s);
+ if (s != NULL) {
+ printk(KERN_INFO "String value: %d-%s\n", u, s);
+ gate_info->gate_str[u] = s;
+ }
+ }
+
+ /* gate info */
+ gate_info_np = of_find_node_by_name(np, "clk_gate_ctrl");
+ if (!gate_info_np) {
+ printk(KERN_ERR "%s: can't find fimc_is clk_gate_ctrl node\n", __func__);
+ ret = -ENOENT;
+ goto p_err;
+ }
+ i = 0;
+ while ((group_np = of_get_next_child(gate_info_np, group_np))) {
+ struct exynos_fimc_is_clk_gate_group *group =
+ &gate_info->groups[i];
+ of_property_for_each_u32(group_np, "mask_clk_on_org", prop, p, u) {
+ printk(KERN_INFO "(%d) int1 value: %d\n", i, u);
+ group->mask_clk_on_org |= (1 << u);
+ }
+ of_property_for_each_u32(group_np, "mask_clk_off_self_org", prop, p, u) {
+ printk(KERN_INFO "(%d) int2 value: %d\n", i, u);
+ group->mask_clk_off_self_org |= (1 << u);
+ }
+ of_property_for_each_u32(group_np, "mask_clk_off_depend", prop, p, u) {
+ printk(KERN_INFO "(%d) int3 value: %d\n", i, u);
+ group->mask_clk_off_depend |= (1 << u);
+ }
+ of_property_for_each_u32(group_np, "mask_cond_for_depend", prop, p, u) {
+ printk(KERN_INFO "(%d) int4 value: %d\n", i, u);
+ group->mask_cond_for_depend |= (1 << u);
+ }
+ i++;
+ printk(KERN_INFO "(%d) [0x%x , 0x%x, 0x%x, 0x%x\n", i,
+ group->mask_clk_on_org,
+ group->mask_clk_off_self_org,
+ group->mask_clk_off_depend,
+ group->mask_cond_for_depend
+ );
+ }
+
+ pdata->gate_info = gate_info;
+ pdata->gate_info->user_clk_gate = exynos_fimc_is_set_user_clk_gate;
+ pdata->gate_info->clk_on_off = exynos_fimc_is_clk_gate;
+
+ return 0;
+p_err:
+ kfree(gate_info);
+ return ret;
+}
+
+static int parse_dvfs_data(struct exynos_platform_fimc_is *pdata, struct device_node *np)
+{
+ u32 temp;
+ char *pprop;
+
+ memset(pdata->dvfs_data, 0, sizeof(pdata->dvfs_data));
+ DT_READ_U32(np, "default_int", pdata->dvfs_data[FIMC_IS_SN_DEFAULT][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "default_cam", pdata->dvfs_data[FIMC_IS_SN_DEFAULT][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "default_mif", pdata->dvfs_data[FIMC_IS_SN_DEFAULT][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "default_i2c", pdata->dvfs_data[FIMC_IS_SN_DEFAULT][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "front_preview_int", pdata->dvfs_data[FIMC_IS_SN_FRONT_PREVIEW][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "front_preview_cam", pdata->dvfs_data[FIMC_IS_SN_FRONT_PREVIEW][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "front_preview_mif", pdata->dvfs_data[FIMC_IS_SN_FRONT_PREVIEW][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "front_preview_i2c", pdata->dvfs_data[FIMC_IS_SN_FRONT_PREVIEW][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "front_capture_int", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAPTURE][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "front_capture_cam", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAPTURE][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "front_capture_mif", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAPTURE][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "front_capture_i2c", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAPTURE][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "front_camcording_int", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAMCORDING][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "front_camcording_cam", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAMCORDING][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "front_camcording_mif", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAMCORDING][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "front_camcording_i2c", pdata->dvfs_data[FIMC_IS_SN_FRONT_CAMCORDING][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "front_vt1_int", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT1][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "front_vt1_cam", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT1][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "front_vt1_mif", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT1][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "front_vt1_i2c", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT1][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "front_vt2_int", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT2][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "front_vt2_cam", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT2][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "front_vt2_mif", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT2][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "front_vt2_i2c", pdata->dvfs_data[FIMC_IS_SN_FRONT_VT2][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "rear_preview_fhd_bns_off_int", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_preview_fhd_bns_off_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_preview_fhd_bns_off_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_preview_fhd_bns_off_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "rear_preview_fhd_int", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_preview_fhd_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_preview_fhd_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_preview_fhd_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_I2C]);
+ /* if there's no FHD preview(with BNS off) dvfa data, set value of FHD recording data */
+ if (!(pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_MIF])) {
+ pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_INT] = pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_INT];
+ pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_CAM] = pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_CAM];
+ pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_MIF] = pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_MIF];
+ pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF][FIMC_IS_DVFS_I2C] = pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_FHD][FIMC_IS_DVFS_I2C];
+ }
+ DT_READ_U32(np, "rear_preview_whd_int", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_WHD][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_preview_whd_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_WHD][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_preview_whd_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_WHD][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_preview_whd_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_WHD][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "rear_preview_uhd_int", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_UHD][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_preview_uhd_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_UHD][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_preview_uhd_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_UHD][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_preview_uhd_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_PREVIEW_UHD][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "rear_capture_int", pdata->dvfs_data[FIMC_IS_SN_REAR_CAPTURE][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_capture_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_CAPTURE][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_capture_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_CAPTURE][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_capture_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_CAPTURE][FIMC_IS_DVFS_I2C]);
+
+ DT_READ_U32(np, "rear_camcording_fhd_bns_off_int", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_camcording_fhd_bns_off_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_camcording_fhd_bns_off_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_camcording_fhd_bns_off_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "rear_camcording_fhd_int", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_camcording_fhd_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_camcording_fhd_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_camcording_fhd_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "rear_camcording_whd_int", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_WHD][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_camcording_whd_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_WHD][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_camcording_whd_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_WHD][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_camcording_whd_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_WHD][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "rear_camcording_uhd_int", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_UHD][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "rear_camcording_uhd_cam", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_UHD][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "rear_camcording_uhd_mif", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_UHD][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "rear_camcording_uhd_i2c", pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_UHD][FIMC_IS_DVFS_I2C]);
+ /* if there's no FHD recording(with BNS off) dvfa data, set value of FHD recording data */
+ if (!(pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_MIF])) {
+ pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_INT] = pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_INT];
+ pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_CAM] = pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_CAM];
+ pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_MIF] = pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_MIF];
+ pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF][FIMC_IS_DVFS_I2C] = pdata->dvfs_data[FIMC_IS_SN_REAR_CAMCORDING_FHD][FIMC_IS_DVFS_I2C];
+ }
+ DT_READ_U32(np, "dual_preview_int", pdata->dvfs_data[FIMC_IS_SN_DUAL_PREVIEW][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "dual_preview_cam", pdata->dvfs_data[FIMC_IS_SN_DUAL_PREVIEW][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "dual_preview_mif", pdata->dvfs_data[FIMC_IS_SN_DUAL_PREVIEW][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "dual_preview_i2c", pdata->dvfs_data[FIMC_IS_SN_DUAL_PREVIEW][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "dual_capture_int", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAPTURE][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "dual_capture_cam", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAPTURE][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "dual_capture_mif", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAPTURE][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "dual_capture_i2c", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAPTURE][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "dual_camcording_int", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAMCORDING][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "dual_camcording_cam", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAMCORDING][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "dual_camcording_mif", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAMCORDING][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "dual_camcording_i2c", pdata->dvfs_data[FIMC_IS_SN_DUAL_CAMCORDING][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "high_speed_fps_int", pdata->dvfs_data[FIMC_IS_SN_HIGH_SPEED_FPS][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "high_speed_fps_cam", pdata->dvfs_data[FIMC_IS_SN_HIGH_SPEED_FPS][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "high_speed_fps_mif", pdata->dvfs_data[FIMC_IS_SN_HIGH_SPEED_FPS][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "high_speed_fps_i2c", pdata->dvfs_data[FIMC_IS_SN_HIGH_SPEED_FPS][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "dis_enable_int", pdata->dvfs_data[FIMC_IS_SN_DIS_ENABLE][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "dis_enable_cam", pdata->dvfs_data[FIMC_IS_SN_DIS_ENABLE][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "dis_enable_mif", pdata->dvfs_data[FIMC_IS_SN_DIS_ENABLE][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "dis_enable_i2c", pdata->dvfs_data[FIMC_IS_SN_DIS_ENABLE][FIMC_IS_DVFS_I2C]);
+ DT_READ_U32(np, "max_int", pdata->dvfs_data[FIMC_IS_SN_MAX][FIMC_IS_DVFS_INT]);
+ DT_READ_U32(np, "max_cam", pdata->dvfs_data[FIMC_IS_SN_MAX][FIMC_IS_DVFS_CAM]);
+ DT_READ_U32(np, "max_mif", pdata->dvfs_data[FIMC_IS_SN_MAX][FIMC_IS_DVFS_MIF]);
+ DT_READ_U32(np, "max_i2c", pdata->dvfs_data[FIMC_IS_SN_MAX][FIMC_IS_DVFS_I2C]);
+
+ return 0;
+}
+
+static int parse_subip_info(struct exynos_platform_fimc_is *pdata, struct device_node *np)
+{
+ u32 temp;
+ char *pprop;
+ struct exynos_fimc_is_subip_info *subip_info;
+
+ /* get subip of fimc-is info */
+ subip_info = kzalloc(sizeof(struct exynos_fimc_is_subip_info), GFP_KERNEL);
+ if (!subip_info) {
+ printk(KERN_ERR "%s: no memory for fimc_is subip_info\n", __func__);
+ return -EINVAL;
+ }
+
+ DT_READ_U32(np, "num_of_mcuctl", subip_info->_mcuctl.valid);
+ DT_READ_U32(np, "num_of_3a0", subip_info->_3a0.valid);
+ DT_READ_U32(np, "num_of_3a1", subip_info->_3a1.valid);
+ DT_READ_U32(np, "num_of_isp", subip_info->_isp.valid);
+ DT_READ_U32(np, "num_of_drc", subip_info->_drc.valid);
+ DT_READ_U32(np, "num_of_scc", subip_info->_scc.valid);
+ DT_READ_U32(np, "num_of_odc", subip_info->_odc.valid);
+ DT_READ_U32(np, "num_of_dis", subip_info->_dis.valid);
+ DT_READ_U32(np, "num_of_dnr", subip_info->_dnr.valid);
+ DT_READ_U32(np, "num_of_scp", subip_info->_scp.valid);
+ DT_READ_U32(np, "num_of_fd", subip_info->_fd.valid);
+
+ DT_READ_U32(np, "full_bypass_mcuctl", subip_info->_mcuctl.full_bypass);
+ DT_READ_U32(np, "full_bypass_3a0", subip_info->_3a0.full_bypass);
+ DT_READ_U32(np, "full_bypass_3a1", subip_info->_3a1.full_bypass);
+ DT_READ_U32(np, "full_bypass_isp", subip_info->_isp.full_bypass);
+ DT_READ_U32(np, "full_bypass_drc", subip_info->_drc.full_bypass);
+ DT_READ_U32(np, "full_bypass_scc", subip_info->_scc.full_bypass);
+ DT_READ_U32(np, "full_bypass_odc", subip_info->_odc.full_bypass);
+ DT_READ_U32(np, "full_bypass_dis", subip_info->_dis.full_bypass);
+ DT_READ_U32(np, "full_bypass_dnr", subip_info->_dnr.full_bypass);
+ DT_READ_U32(np, "full_bypass_scp", subip_info->_scp.full_bypass);
+ DT_READ_U32(np, "full_bypass_fd", subip_info->_fd.full_bypass);
+
+ DT_READ_U32(np, "version_mcuctl", subip_info->_mcuctl.version);
+ DT_READ_U32(np, "version_3a0", subip_info->_3a0.version);
+ DT_READ_U32(np, "version_3a1", subip_info->_3a1.version);
+ DT_READ_U32(np, "version_isp", subip_info->_isp.version);
+ DT_READ_U32(np, "version_drc", subip_info->_drc.version);
+ DT_READ_U32(np, "version_scc", subip_info->_scc.version);
+ DT_READ_U32(np, "version_odc", subip_info->_odc.version);
+ DT_READ_U32(np, "version_dis", subip_info->_dis.version);
+ DT_READ_U32(np, "version_dnr", subip_info->_dnr.version);
+ DT_READ_U32(np, "version_scp", subip_info->_scp.version);
+ DT_READ_U32(np, "version_fd", subip_info->_fd.version);
+
+ pdata->subip_info = subip_info;
+
+ return 0;
+}
+
+int fimc_is_power_initpin(struct device *dev)
+{
+ struct exynos_platform_fimc_is_sensor *pdata;
+ int gpio_none = 0;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ pdata = dev->platform_data;
+
+ if (!pdata->sensor_id || (pdata->sensor_id >= SENSOR_NAME_END)) {
+ err("check the sensor id. sensor_id %d", pdata->sensor_id);
+ return -ENODEV;
+ }
+
+ /* POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+
+int fimc_is_power_setpin(struct device *dev, int position, int sensor_id)
+{
+ struct fimc_is_core *core;
+ struct fimc_is_device_sensor *sensor;
+ int ret = 0;
+ int i, pos, found;
+
+ if (!fimc_is_dev) {
+ err("fimc_is_dev is not yet probed");
+ return -ENODEV;
+ }
+
+ if (!sensor_id || (sensor_id >= SENSOR_NAME_END)) {
+ err("check the sensor id. sensor_id %d", sensor_id);
+ return -ENODEV;
+ }
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core is NULL");
+ return -EINVAL;
+ }
+
+ if (!atomic_read(&core->resourcemgr.rsccount_module))
+ err("sensor driver not probed");
+
+ sensor = &core->sensor[position];
+
+ /* Call power_setpin and return */
+ for (i = 0; i < atomic_read(&core->resourcemgr.rsccount_module); i++) {
+ if (sensor_id == sensor->module_enum[i].id) {
+ info("%s: sensor found(id %d). %s\n", __func__, sensor_id,
+ (position == sensor->module_enum[i].position) ? "" : "position not matched");
+
+ if (sensor->module_enum[i].power_setpin)
+ ret = sensor->module_enum[i].power_setpin(dev);
+
+ return ret;
+ }
+ }
+
+ /* Enumerate probed sensor lists if not found */
+ for (pos = 0, found = 0; pos < FIMC_IS_MAX_NODES; pos++, found = 0) {
+ sensor = &core->sensor[pos];
+ for (i = 0; i < atomic_read(&core->resourcemgr.rsccount_module); i++) {
+ if (sensor->module_enum[i].id) {
+ info("Camera sensor %d: id %3d. %s\n", pos, sensor->module_enum[i].id,
+ sensor->module_enum[i].setfile_name ?
+ sensor->module_enum[i].setfile_name : "");
+ found++;
+ }
+ }
+
+ if (!found)
+ info("Camera sensor %d: none\n", pos);
+ }
+
+ err("sensor not found (pos %d, id %d)", position, sensor_id);
+
+ return 0;
+}
+
+struct exynos_platform_fimc_is *fimc_is_parse_dt(struct device *dev)
+{
+ void *ret = NULL;
+ struct exynos_platform_fimc_is *pdata;
+ struct device_node *subip_info_np;
+ struct device_node *dvfs_np;
+ struct device_node *np = dev->of_node;
+#if defined CONFIG_COMPANION_USE || defined CONFIG_USE_VENDER_FEATURE
+ int retVal = 0;
+#endif
+
+ if (!np)
+ return ERR_PTR(-ENOENT);
+
+ pdata = kzalloc(sizeof(struct exynos_platform_fimc_is), GFP_KERNEL);
+ if (!pdata) {
+ printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pdata->clk_cfg = exynos_fimc_is_cfg_clk;
+ pdata->clk_on = exynos_fimc_is_clk_on;
+ pdata->clk_off = exynos_fimc_is_clk_off;
+ pdata->print_clk = exynos_fimc_is_print_clk;
+ pdata->print_cfg = exynos_fimc_is_print_cfg;
+ pdata->print_pwr = exynos_fimc_is_print_pwr;
+
+ dev->platform_data = pdata;
+
+#ifdef CONFIG_COMPANION_USE
+ retVal = of_property_read_u32(np, "companion_spi_channel", &pdata->companion_spi_channel);
+ if (retVal) {
+ err("spi_channel read is fail(%d)", retVal);
+ }
+
+ pdata->use_two_spi_line = of_property_read_bool(np, "use_two_spi_line");
+#endif
+#ifdef CONFIG_USE_VENDER_FEATURE
+ retVal = of_property_read_u32(np, "use_sensor_dynamic_voltage_mode", &pdata->use_sensor_dynamic_voltage_mode);
+ if (retVal) {
+ err("use_sensor_dynamic_voltage_mode read is fail(%d)", retVal);
+ pdata->use_sensor_dynamic_voltage_mode = 0;
+ }
+#ifdef CONFIG_OIS_USE
+ pdata->use_ois = of_property_read_bool(np, "use_ois");
+ if (!pdata->use_ois) {
+ err("use_ois not use(%d)", pdata->use_ois);
+ }
+#endif /* CONFIG_OIS_USE */
+ pdata->use_ois_hsi2c = of_property_read_bool(np, "use_ois_hsi2c");
+ if (!pdata->use_ois_hsi2c) {
+ err("use_ois_hsi2c not use(%d)", pdata->use_ois_hsi2c);
+ }
+
+ pdata->use_module_check = of_property_read_bool(np, "use_module_check");
+ if (!pdata->use_module_check) {
+ err("use_module_check not use(%d)", pdata->use_module_check);
+ }
+#endif
+ subip_info_np = of_find_node_by_name(np, "subip_info");
+ if (!subip_info_np) {
+ printk(KERN_ERR "%s: can't find fimc_is subip_info node\n", __func__);
+ ret = ERR_PTR(-ENOENT);
+ goto p_err;
+ }
+ parse_subip_info(pdata, subip_info_np);
+
+ if (parse_gate_info(pdata, np) < 0)
+ printk(KERN_ERR "%s: can't parse clock gate info node\n", __func__);
+
+ dvfs_np = of_find_node_by_name(np, "fimc_is_dvfs");
+ if (!dvfs_np) {
+ printk(KERN_ERR "%s: can't find fimc_is_dvfs node\n", __func__);
+ ret = ERR_PTR(-ENOENT);
+ goto p_err;
+ }
+ parse_dvfs_data(pdata, dvfs_np);
+
+ return pdata;
+p_err:
+ kfree(pdata);
+ return ret;
+}
+
+int fimc_is_sensor_parse_dt(struct platform_device *pdev)
+{
+ int ret = 0;
+ u32 temp;
+ char *pprop;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ struct device *dev;
+ const char *name;
+ u32 id;
+
+ BUG_ON(!pdev);
+ BUG_ON(!pdev->dev.of_node);
+
+ dev = &pdev->dev;
+ dnode = dev->of_node;
+
+ pdata = kzalloc(sizeof(struct exynos_platform_fimc_is_sensor), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("%s: no memory for platform data\n", __func__);
+ return -ENOMEM;
+ }
+
+ pdata->gpio_cfg = exynos_fimc_is_sensor_pins_cfg;
+ pdata->iclk_cfg = exynos_fimc_is_sensor_iclk_cfg;
+ pdata->iclk_on = exynos_fimc_is_sensor_iclk_on;
+ pdata->iclk_off = exynos_fimc_is_sensor_iclk_off;
+ pdata->mclk_on = exynos_fimc_is_sensor_mclk_on;
+ pdata->mclk_off = exynos_fimc_is_sensor_mclk_off;
+
+ ret = of_property_read_u32(dnode, "scenario", &pdata->scenario);
+ if (ret) {
+ err("scenario read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "mclk_ch", &pdata->mclk_ch);
+ if (ret) {
+ err("mclk_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "csi_ch", &pdata->csi_ch);
+ if (ret) {
+ err("csi_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "flite_ch", &pdata->flite_ch);
+ if (ret) {
+ err("flite_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "i2c_ch", &pdata->i2c_ch);
+ if (ret) {
+ err("i2c_ch read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "i2c_addr", &pdata->i2c_addr);
+ if (ret) {
+ err("i2c_addr read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "is_bns", &pdata->is_bns);
+ if (ret) {
+ err("is_bns read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = of_property_read_u32(dnode, "id", &id);
+ if (ret) {
+ err("id read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ DT_READ_U32(dnode, "flash_first_gpio", pdata->flash_first_gpio);
+ DT_READ_U32(dnode, "flash_second_gpio", pdata->flash_second_gpio);
+
+ ret = of_property_read_string(dnode, "sensor_name", &name);
+ if (ret) {
+ err("sensor_name read is fail(%d)", ret);
+ goto p_err;
+ }
+ strcpy(pdata->sensor_name, name);
+
+ ret = of_property_read_u32(dnode, "sensor_id", &pdata->sensor_id);
+ if (ret) {
+ err("sensor_id read is fail(%d)", ret);
+ goto p_err;
+ }
+
+ dev->platform_data = pdata;
+
+ ret = fimc_is_power_setpin(dev, id, pdata->sensor_id);
+ if (ret)
+ err("power_setpin failed(%d). id %d", ret, id);
+
+ pdev->id = id;
+
+ pdata->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pdata->pinctrl)) {
+ err("devm_pinctrl_get is fail");
+ goto p_err;
+ } else {
+ ret = get_pin_lookup_state(dev, pdata);
+ if (ret < 0) {
+ err("fimc_is_get_pin_lookup_state is fail");
+ goto p_err;
+ }
+ }
+
+ return ret;
+
+p_err:
+ kfree(pdata);
+ return ret;
+}
+#else
+struct exynos_platform_fimc_is *fimc_is_parse_dt(struct device *dev)
+{
+ return ERR_PTR(-EINVAL);
+}
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 <mach/exynos-fimc-is-sensor.h>
+
+#ifndef FIMC_IS_DT_H
+#define FIMC_IS_DT_H
+
+#define DT_READ_U32(node, key, value) do {\
+ pprop = key; \
+ temp = 0; \
+ if (of_property_read_u32((node), key, &temp)) \
+ pr_warn("%s: no property in the node.\n", pprop);\
+ (value) = temp; \
+ } while (0)
+
+#define DT_READ_STR(node, key, value) do {\
+ pprop = key; \
+ if (of_property_read_string((node), key, &name)) \
+ pr_warn("%s: no property in the node.\n", pprop);\
+ (value) = name; \
+ } while (0)
+
+int get_pin_lookup_state(struct device *dev, struct exynos_platform_fimc_is_sensor *pdata);
+int fimc_is_power_initpin(struct device *dev);
+int fimc_is_power_setpin(struct device *dev, int position, int sensor_id);
+struct exynos_platform_fimc_is *fimc_is_parse_dt(struct device *dev);
+int fimc_is_sensor_parse_dt(struct platform_device *pdev);
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/slab.h>
+#include "fimc-is-core.h"
+#include "fimc-is-dvfs.h"
+
+extern struct pm_qos_request exynos_isp_qos_cpu_min;
+extern struct pm_qos_request exynos_isp_qos_cpu_max;
+extern struct pm_qos_request exynos_isp_qos_int;
+extern struct pm_qos_request exynos_isp_qos_mem;
+extern struct pm_qos_request exynos_isp_qos_cam;
+extern struct pm_qos_request exynos_isp_qos_disp;
+
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_CAPTURE);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_CAMCORDING);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_PREVIEW);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_HIGH_SPEED_FPS);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_FHD);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_WHD);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_UHD);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_FHD);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_WHD);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_UHD);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_VT1);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_VT2);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_PREVIEW);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAPTURE);
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DIS_ENABLE);
+
+#if defined(ENABLE_DVFS)
+/*
+ * Static Scenario Set
+ * You should describe static scenario by priorities of scenario.
+ * And you should name array 'static_scenarios'
+ */
+static struct fimc_is_dvfs_scenario static_scenarios[] = {
+ {
+ .scenario_id = FIMC_IS_SN_DUAL_CAMCORDING,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_DUAL_CAMCORDING),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_CAMCORDING),
+ }, {
+ .scenario_id = FIMC_IS_SN_DUAL_PREVIEW,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_DUAL_PREVIEW),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_PREVIEW),
+ }, {
+ .scenario_id = FIMC_IS_SN_HIGH_SPEED_FPS,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_HIGH_SPEED_FPS),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_HIGH_SPEED_FPS),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_CAMCORDING_FHD,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_CAMCORDING_FHD),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_FHD),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_CAMCORDING_WHD,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_CAMCORDING_WHD),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_WHD),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_CAMCORDING_UHD,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_CAMCORDING_UHD),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_UHD),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_PREVIEW_FHD,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_PREVIEW_FHD),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_FHD),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_PREVIEW_WHD,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_PREVIEW_WHD),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_WHD),
+ }, {
+ .scenario_id = FIMC_IS_SN_REAR_PREVIEW_UHD,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_PREVIEW_UHD),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_UHD),
+ }, {
+ .scenario_id = FIMC_IS_SN_FRONT_VT1,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_FRONT_VT1),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_VT1),
+ }, {
+ .scenario_id = FIMC_IS_SN_FRONT_VT2,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_FRONT_VT2),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_VT2),
+ }, {
+ .scenario_id = FIMC_IS_SN_FRONT_PREVIEW,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_FRONT_PREVIEW),
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_PREVIEW),
+ },
+};
+
+/*
+ * Dynamic Scenario Set
+ * You should describe static scenario by priorities of scenario.
+ * And you should name array 'dynamic_scenarios'
+ */
+static struct fimc_is_dvfs_scenario dynamic_scenarios[] = {
+ {
+ .scenario_id = FIMC_IS_SN_DUAL_CAPTURE,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_DUAL_CAPTURE),
+ .keep_frame_tick = KEEP_FRAME_TICK_DEFAULT,
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_CAPTURE),
+ },
+ {
+ .scenario_id = FIMC_IS_SN_REAR_CAPTURE,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_REAR_CAPTURE),
+ .keep_frame_tick = KEEP_FRAME_TICK_DEFAULT,
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAPTURE),
+ },
+ {
+ .scenario_id = FIMC_IS_SN_DIS_ENABLE,
+ .scenario_nm = DVFS_SN_STR(FIMC_IS_SN_DIS_ENABLE),
+ .keep_frame_tick = KEEP_FRAME_TICK_DEFAULT,
+ .check_func = GET_DVFS_CHK_FUNC(FIMC_IS_SN_DIS_ENABLE),
+ },
+};
+#else
+/*
+ * Default Scenario can not be seleted, this declaration is for static variable.
+ */
+static struct fimc_is_dvfs_scenario static_scenarios[] = {
+ {
+ .scenario_id = FIMC_IS_SN_DEFAULT,
+ .scenario_nm = NULL,
+ .keep_frame_tick = 0,
+ .check_func = NULL,
+ },
+};
+static struct fimc_is_dvfs_scenario dynamic_scenarios[] = {
+ {
+ .scenario_id = FIMC_IS_SN_DEFAULT,
+ .scenario_nm = NULL,
+ .keep_frame_tick = 0,
+ .check_func = NULL,
+ },
+};
+#endif
+
+static inline int fimc_is_get_open_sensor_cnt(struct fimc_is_core *core)
+{
+ int i, sensor_cnt = 0;
+
+ for (i = 0; i < FIMC_IS_MAX_NODES; i++)
+ if (test_bit(FIMC_IS_SENSOR_OPEN, &(core->sensor[i].state)))
+ sensor_cnt++;
+
+ return sensor_cnt;
+}
+
+static inline u32 fimc_is_chk_req(struct fimc_is_frame *frame, enum fimc_is_video_dev_num vid)
+{
+ int i;
+ struct camera2_node *node;
+ u32 ret = 0;
+
+ if (frame == NULL)
+ return ret;
+
+ for (i = 0; i < CAPTURE_NODE_MAX; i++) {
+ node = &frame->shot_ext->node_group.capture[i];
+ if (node->vid == vid) {
+ ret = node->request;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* dual capture */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_CAPTURE)
+{
+ struct fimc_is_core *core;
+ int sensor_cnt = 0;
+ core = (struct fimc_is_core *)device->interface->core;
+ sensor_cnt = fimc_is_get_open_sensor_cnt(core);
+
+ if ((sensor_cnt >= 2) &&
+ (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)))
+ return 1;
+ else
+ return 0;
+}
+
+/* dual camcording */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_CAMCORDING)
+{
+ struct fimc_is_core *core;
+ int sensor_cnt = 0;
+ core = (struct fimc_is_core *)device->interface->core;
+ sensor_cnt = fimc_is_get_open_sensor_cnt(core);
+
+ if ((sensor_cnt >= 2) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ == ISS_SUB_SCENARIO_DUAL_VIDEO))
+ return 1;
+ else
+ return 0;
+}
+
+/* dual preview */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DUAL_PREVIEW)
+{
+ struct fimc_is_core *core;
+ int sensor_cnt = 0;
+ core = (struct fimc_is_core *)device->interface->core;
+ sensor_cnt = fimc_is_get_open_sensor_cnt(core);
+
+ if ((sensor_cnt >= 2) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ != ISS_SUB_SCENARIO_DUAL_VIDEO))
+ return 1;
+ else
+ return 0;
+}
+
+/* high speed fps */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_HIGH_SPEED_FPS)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) > 30))
+ return 1;
+ else
+ return 0;
+}
+
+/* rear camcording FHD with BNS off */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_FHD_BNS_OFF)
+{
+ u32 mask = (device->setfile & FIMC_IS_SETFILE_MASK);
+ bool setfile_flag = (mask == ISS_SUB_SCENARIO_VIDEO) ||
+ (mask == ISS_SUB_SCENARIO_VIDEO_WDR);
+
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height <= SIZE_FHD) &&
+ (fimc_is_sensor_g_bns_ratio(device->sensor) <= 1000) &&
+ setfile_flag)
+ return 1;
+ else
+ return 0;
+}
+
+/* rear camcording FHD*/
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_FHD)
+{
+ u32 mask = (device->setfile & FIMC_IS_SETFILE_MASK);
+ bool setfile_flag = (mask == ISS_SUB_SCENARIO_VIDEO) ||
+ (mask == ISS_SUB_SCENARIO_VIDEO_WDR);
+
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height <= SIZE_FHD) &&
+ (fimc_is_sensor_g_bns_ratio(device->sensor) > 1000) &&
+ setfile_flag)
+ return 1;
+ else
+ return 0;
+}
+
+/* rear camcording WHD*/
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_WHD)
+{
+ u32 mask = (device->setfile & FIMC_IS_SETFILE_MASK);
+ bool setfile_flag = (mask == ISS_SUB_SCENARIO_VIDEO) ||
+ (mask == ISS_SUB_SCENARIO_VIDEO_WDR);
+
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height > SIZE_FHD) &&
+ (device->chain3_width * device->chain3_height <= SIZE_WHD) &&
+ setfile_flag)
+ return 1;
+ else
+ return 0;
+}
+
+/* rear camcording UHD*/
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAMCORDING_UHD)
+{
+ u32 mask = (device->setfile & FIMC_IS_SETFILE_MASK);
+ bool setfile_flag = (mask == ISS_SUB_SCENARIO_UHD_30FPS) ||
+ (mask == ISS_SUB_SCENARIO_UHD_30FPS_WDR);
+
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height > SIZE_WHD) &&
+ (device->chain3_width * device->chain3_height <= SIZE_UHD) &&
+ setfile_flag)
+ return 1;
+ else
+ return 0;
+}
+
+/* rear preview FHD with BNS off */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_FHD_BNS_OFF)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height <= SIZE_FHD) &&
+ (fimc_is_sensor_g_bns_ratio(device->sensor) <= 1000) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ != ISS_SUB_SCENARIO_VIDEO))
+
+ return 1;
+ else
+ return 0;
+}
+
+/* rear preview FHD */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_FHD)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height <= SIZE_FHD) &&
+ (fimc_is_sensor_g_bns_ratio(device->sensor) > 1000) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ != ISS_SUB_SCENARIO_VIDEO))
+
+ return 1;
+ else
+ return 0;
+}
+
+/* rear preview WHD */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_WHD)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height > SIZE_FHD) &&
+ (device->chain3_width * device->chain3_height <= SIZE_WHD) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ != ISS_SUB_SCENARIO_VIDEO))
+ return 1;
+ else
+ return 0;
+}
+
+/* rear preview UHD */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_PREVIEW_UHD)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ (fimc_is_sensor_g_framerate(device->sensor) <= 30) &&
+ (device->chain3_width * device->chain3_height > SIZE_WHD) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ != ISS_SUB_SCENARIO_VIDEO))
+ return 1;
+ else
+ return 0;
+}
+
+/* front vt1 */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_VT1)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_FRONT) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ == ISS_SUB_SCENARIO_FRONT_VT1))
+ return 1;
+ else
+ return 0;
+}
+
+/* front vt2 */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_VT2)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_FRONT) &&
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ == ISS_SUB_SCENARIO_FRONT_VT2))
+ return 1;
+ else
+ return 0;
+}
+
+/* front preview */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_FRONT_PREVIEW)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_FRONT) &&
+ !(((device->setfile & FIMC_IS_SETFILE_MASK) \
+ == ISS_SUB_SCENARIO_FRONT_VT1) ||
+ ((device->setfile & FIMC_IS_SETFILE_MASK) \
+ == ISS_SUB_SCENARIO_FRONT_VT2)))
+ return 1;
+ else
+ return 0;
+}
+
+/* rear capture */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_REAR_CAPTURE)
+{
+ if ((device->sensor->pdev->id == SENSOR_POSITION_REAR) &&
+ ((test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) ||
+ fimc_is_chk_req(frame, FIMC_IS_VIDEO_SCC_NUM)))
+ return 1;
+ else
+ return 0;
+}
+
+/* dis */
+DECLARE_DVFS_CHK_FUNC(FIMC_IS_SN_DIS_ENABLE)
+{
+ if (test_bit(FIMC_IS_SUBDEV_START, &device->dis.state))
+ return 1;
+ else
+ return 0;
+}
+
+static int fimc_is_set_pwm(struct fimc_is_device_ischain *device, u32 pwm_qos)
+{
+ int ret = 0;
+ u32 base_addr;
+ void __iomem *addr;
+
+ base_addr = GET_FIMC_IS_ADDR_OF_SUBIP2(device, pwm);
+
+ if (base_addr) {
+ addr = ioremap(base_addr + FIMC_IS_PWM_TCNTB0, SZ_4);
+ writel(pwm_qos, addr);
+ dbg("PWM SFR Read(%08X), pwm_qos(%08X)\n", readl(addr), pwm_qos);
+ iounmap(addr);
+ }
+
+ return ret;
+}
+
+int fimc_is_dvfs_init(struct fimc_is_resourcemgr *resourcemgr)
+{
+ int i;
+ pr_info("%s\n", __func__);
+
+ BUG_ON(!resourcemgr);
+
+ resourcemgr->dvfs_ctrl.cur_cpu_min_qos = 0;
+ resourcemgr->dvfs_ctrl.cur_cpu_max_qos = 0;
+ resourcemgr->dvfs_ctrl.cur_int_qos = 0;
+ resourcemgr->dvfs_ctrl.cur_mif_qos = 0;
+ resourcemgr->dvfs_ctrl.cur_cam_qos = 0;
+ resourcemgr->dvfs_ctrl.cur_i2c_qos = 0;
+ resourcemgr->dvfs_ctrl.cur_disp_qos = 0;
+
+ /* init spin_lock for clock gating */
+ mutex_init(&resourcemgr->dvfs_ctrl.lock);
+
+ if (!(resourcemgr->dvfs_ctrl.static_ctrl))
+ resourcemgr->dvfs_ctrl.static_ctrl =
+ kzalloc(sizeof(struct fimc_is_dvfs_scenario_ctrl), GFP_KERNEL);
+ if (!(resourcemgr->dvfs_ctrl.dynamic_ctrl))
+ resourcemgr->dvfs_ctrl.dynamic_ctrl =
+ kzalloc(sizeof(struct fimc_is_dvfs_scenario_ctrl), GFP_KERNEL);
+
+ if (!resourcemgr->dvfs_ctrl.static_ctrl || !resourcemgr->dvfs_ctrl.dynamic_ctrl) {
+ err("dvfs_ctrl alloc is failed!!\n");
+ return -ENOMEM;
+ }
+
+ /* set priority by order */
+ for (i = 0; i < ARRAY_SIZE(static_scenarios); i++)
+ static_scenarios[i].priority = i;
+ for (i = 0; i < ARRAY_SIZE(dynamic_scenarios); i++)
+ dynamic_scenarios[i].priority = i;
+
+ resourcemgr->dvfs_ctrl.static_ctrl->cur_scenario_id = -1;
+ resourcemgr->dvfs_ctrl.static_ctrl->cur_scenario_idx = -1;
+ resourcemgr->dvfs_ctrl.static_ctrl->scenarios = static_scenarios;
+ if (static_scenarios[0].scenario_id == FIMC_IS_SN_DEFAULT)
+ resourcemgr->dvfs_ctrl.static_ctrl->scenario_cnt = 0;
+ else
+ resourcemgr->dvfs_ctrl.static_ctrl->scenario_cnt = ARRAY_SIZE(static_scenarios);
+
+ resourcemgr->dvfs_ctrl.dynamic_ctrl->cur_scenario_id = -1;
+ resourcemgr->dvfs_ctrl.dynamic_ctrl->cur_scenario_idx = -1;
+ resourcemgr->dvfs_ctrl.dynamic_ctrl->cur_frame_tick = -1;
+ resourcemgr->dvfs_ctrl.dynamic_ctrl->scenarios = dynamic_scenarios;
+ if (static_scenarios[0].scenario_id == FIMC_IS_SN_DEFAULT)
+ resourcemgr->dvfs_ctrl.dynamic_ctrl->scenario_cnt = 0;
+ else
+ resourcemgr->dvfs_ctrl.dynamic_ctrl->scenario_cnt = ARRAY_SIZE(dynamic_scenarios);
+
+ return 0;
+}
+
+int fimc_is_dvfs_sel_scenario(u32 type, struct fimc_is_device_ischain *device, struct fimc_is_frame *frame)
+{
+ struct fimc_is_dvfs_ctrl *dvfs_ctrl;
+ struct fimc_is_dvfs_scenario_ctrl *static_ctrl, *dynamic_ctrl;
+ struct fimc_is_dvfs_scenario *scenarios;
+ struct fimc_is_dvfs_scenario *cur_scenario;
+ struct fimc_is_resourcemgr *resourcemgr;
+ int i, scenario_id, scenario_cnt;
+
+ if (device == NULL) {
+ err("device is NULL\n");
+ return -EINVAL;
+ }
+
+ resourcemgr = device->resourcemgr;
+ dvfs_ctrl = &(resourcemgr->dvfs_ctrl);
+ static_ctrl = dvfs_ctrl->static_ctrl;
+ dynamic_ctrl = dvfs_ctrl->dynamic_ctrl;
+
+ if (type == FIMC_IS_DYNAMIC_SN) {
+ /* dynamic scenario */
+ if (!dynamic_ctrl) {
+ err("dynamic_dvfs_ctrl is NULL\n");
+ return -EINVAL;
+ }
+
+ if (dynamic_ctrl->scenario_cnt == 0) {
+ pr_debug("dynamic_scenario's count is jero\n");
+ return -EINVAL;
+ }
+
+ scenarios = dynamic_ctrl->scenarios;
+ scenario_cnt = dynamic_ctrl->scenario_cnt;
+
+ if (dynamic_ctrl->cur_frame_tick >= 0) {
+ (dynamic_ctrl->cur_frame_tick)--;
+ /*
+ * when cur_frame_tick is lower than 0, clear current scenario.
+ * This means that current frame tick to keep dynamic scenario
+ * was expired.
+ */
+ if (dynamic_ctrl->cur_frame_tick < 0) {
+ dynamic_ctrl->cur_scenario_id = -1;
+ dynamic_ctrl->cur_scenario_idx = -1;
+ }
+ }
+ } else {
+ /* static scenario */
+ if (!static_ctrl) {
+ err("static_dvfs_ctrl is NULL\n");
+ return -EINVAL;
+ }
+
+ if (static_ctrl->scenario_cnt == 0) {
+ pr_debug("static_scenario's count is jero\n");
+ return -EINVAL;
+ }
+
+ scenarios = static_ctrl->scenarios;
+ scenario_cnt = static_ctrl->scenario_cnt;
+ }
+
+ for (i = 0; i < scenario_cnt; i++) {
+ if (!scenarios[i].check_func) {
+ warn("check_func[%d] is NULL\n", i);
+ continue;
+ }
+
+ if ((scenarios[i].check_func(device, frame)) > 0) {
+ scenario_id = scenarios[i].scenario_id;
+
+ if (type == FIMC_IS_DYNAMIC_SN) {
+ cur_scenario = &scenarios[dynamic_ctrl->cur_scenario_idx];
+
+ /*
+ * if condition 1 or 2 is true
+ * condition 1 : There's no dynamic scenario applied.
+ * condition 2 : Finded scenario's prority was higher than current
+ */
+ if ((dynamic_ctrl->cur_scenario_id <= 0) ||
+ (scenarios[i].priority < (cur_scenario->priority))) {
+ dynamic_ctrl->cur_scenario_id = scenarios[i].scenario_id;
+ dynamic_ctrl->cur_scenario_idx = i;
+ dynamic_ctrl->cur_frame_tick = scenarios[i].keep_frame_tick;
+ } else {
+ /* if finded scenario is same */
+ if (scenarios[i].priority == (cur_scenario->priority))
+ dynamic_ctrl->cur_frame_tick = scenarios[i].keep_frame_tick;
+ return -EAGAIN;
+ }
+ } else {
+ static_ctrl->cur_scenario_id = scenario_id;
+ static_ctrl->cur_scenario_idx = i;
+ static_ctrl->cur_frame_tick = scenarios[i].keep_frame_tick;
+ }
+
+ return scenario_id;
+ }
+ }
+
+ if (type == FIMC_IS_DYNAMIC_SN)
+ return -EAGAIN;
+
+ {
+ struct fimc_is_core *core;
+ int sensor_cnt = 0;
+ core = (struct fimc_is_core *)device->interface->core;
+ sensor_cnt = fimc_is_get_open_sensor_cnt(core);
+
+ warn("couldn't find static dvfs scenario [sensor:(%d/%d)/fps:%d/setfile:%d/scp size:(%d/%d)]\n",
+ sensor_cnt,
+ device->sensor->pdev->id,
+ fimc_is_sensor_g_framerate(device->sensor),
+ (device->setfile & FIMC_IS_SETFILE_MASK),
+ device->chain3_width,
+ device->chain3_height);
+ }
+
+ static_ctrl->cur_scenario_id = FIMC_IS_SN_DEFAULT;
+ static_ctrl->cur_scenario_idx = -1;
+ static_ctrl->cur_frame_tick = -1;
+
+ return FIMC_IS_SN_DEFAULT;
+}
+
+int fimc_is_get_qos(struct fimc_is_core *core, u32 type, u32 scenario_id)
+{
+ struct exynos_platform_fimc_is *pdata = NULL;
+ int qos = 0;
+
+ pdata = core->pdata;
+ if (pdata == NULL) {
+ err("pdata is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->get_int_qos || !pdata->get_mif_qos)
+ goto struct_qos;
+
+ switch (type) {
+ case FIMC_IS_DVFS_INT:
+ qos = pdata->get_int_qos(scenario_id);
+ break;
+ case FIMC_IS_DVFS_MIF:
+ qos = pdata->get_mif_qos(scenario_id);
+ break;
+ case FIMC_IS_DVFS_I2C:
+ if (pdata->get_i2c_qos)
+ qos = pdata->get_i2c_qos(scenario_id);
+ break;
+ }
+ goto exit;
+
+struct_qos:
+ if (max(0, (int)type) >= FIMC_IS_DVFS_END) {
+ err("Cannot find DVFS value");
+ return -EINVAL;
+ }
+
+ qos = pdata->dvfs_data[scenario_id][type];
+
+exit:
+ return qos;
+}
+
+int fimc_is_set_dvfs(struct fimc_is_device_ischain *device, u32 scenario_id)
+{
+ int ret = 0;
+ int cpu_min_qos, cpu_max_qos, int_qos, mif_qos, i2c_qos, cam_qos, disp_qos, pwm_qos = 0;
+ int refcount;
+ struct fimc_is_core *core;
+ struct fimc_is_resourcemgr *resourcemgr;
+ struct fimc_is_dvfs_ctrl *dvfs_ctrl;
+
+ if (device == NULL) {
+ err("device is NULL\n");
+ return -EINVAL;
+ }
+
+ core = (struct fimc_is_core *)device->interface->core;
+ resourcemgr = device->resourcemgr;
+ dvfs_ctrl = &(resourcemgr->dvfs_ctrl);
+
+ refcount = atomic_read(&core->video_isp.refcount);
+ if (refcount < 0) {
+ err("invalid ischain refcount");
+ goto exit;
+ }
+
+ cpu_min_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CPU_MIN, scenario_id);
+ cpu_max_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CPU_MAX, scenario_id);
+ int_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_INT, scenario_id);
+ mif_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_MIF, scenario_id);
+ i2c_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_I2C, scenario_id);
+ cam_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CAM, scenario_id);
+ disp_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_DISP, scenario_id);
+ pwm_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_PWM, scenario_id);
+
+ if ((int_qos < 0) || (mif_qos < 0) || (i2c_qos < 0)
+ || (cam_qos < 0) || (disp_qos < 0) || (pwm_qos < 0)) {
+ err("getting qos value is failed!!\n");
+ return -EINVAL;
+ }
+
+ if (dvfs_ctrl->cur_cpu_min_qos != cpu_min_qos) {
+ pm_qos_update_request(&exynos_isp_qos_cpu_min, cpu_min_qos);
+ dvfs_ctrl->cur_cpu_min_qos = cpu_min_qos;
+ }
+
+ if (dvfs_ctrl->cur_cpu_max_qos != cpu_max_qos) {
+ pm_qos_update_request(&exynos_isp_qos_cpu_max, cpu_max_qos);
+ dvfs_ctrl->cur_cpu_max_qos = cpu_max_qos;
+ }
+
+ /* check current qos */
+ if (int_qos && dvfs_ctrl->cur_int_qos != int_qos) {
+ if (i2c_qos) {
+ ret = fimc_is_itf_i2c_lock(device, i2c_qos, true);
+ if (ret) {
+ err("fimc_is_itf_i2_clock fail\n");
+ goto exit;
+ }
+ }
+
+ if (pwm_qos) {
+ fimc_is_set_pwm(device, pwm_qos);
+ if (ret) {
+ err("fimc_is_set_pwm fail\n");
+ goto exit;
+ }
+ }
+
+ pm_qos_update_request(&exynos_isp_qos_int, int_qos);
+ dvfs_ctrl->cur_int_qos = int_qos;
+
+ if (i2c_qos) {
+ /* i2c unlock */
+ ret = fimc_is_itf_i2c_lock(device, i2c_qos, false);
+ if (ret) {
+ err("fimc_is_itf_i2c_unlock fail\n");
+ goto exit;
+ }
+ }
+ }
+
+ if (mif_qos && dvfs_ctrl->cur_mif_qos != mif_qos) {
+ pm_qos_update_request(&exynos_isp_qos_mem, mif_qos);
+ dvfs_ctrl->cur_mif_qos = mif_qos;
+ }
+
+ if (cam_qos && dvfs_ctrl->cur_cam_qos != cam_qos) {
+ pm_qos_update_request(&exynos_isp_qos_cam, cam_qos);
+ dvfs_ctrl->cur_cam_qos = cam_qos;
+ }
+
+ if (disp_qos && dvfs_ctrl->cur_disp_qos != disp_qos) {
+ pm_qos_update_request(&exynos_isp_qos_disp, disp_qos);
+ dvfs_ctrl->cur_disp_qos = disp_qos;
+ }
+
+ dbg("[RSC:%d]: New QoS [INT(%d), MIF(%d), CAM(%d), DISP(%d), I2C(%d), PWM(%d) CPU(%d/%d)]\n",
+ device->instance, int_qos, mif_qos,
+ cam_qos, disp_qos, i2c_qos, pwm_qos, cpu_min_qos, cpu_max_qos);
+exit:
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DVFS_H
+#define FIMC_IS_DVFS_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-groupmgr.h"
+#include "fimc-is-device-ischain.h"
+
+#define KEEP_FRAME_TICK_DEFAULT (5)
+#define DVFS_SN_STR(__SCENARIO) #__SCENARIO
+#define GET_DVFS_CHK_FUNC(__SCENARIO) check_ ## __SCENARIO
+#define DECLARE_DVFS_CHK_FUNC(__SCENARIO) \
+ int check_ ## __SCENARIO \
+ (struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, ...)
+
+#define SIZE_FHD (1920 * 1080)
+#define SIZE_WHD (2560 * 1440)
+#define SIZE_UHD (3840 * 2160)
+
+enum FIMC_IS_DVFS_SCENARIO_TYPE {
+ FIMC_IS_STATIC_SN,
+ FIMC_IS_DYNAMIC_SN,
+};
+
+struct fimc_is_dvfs_scenario {
+ u32 scenario_id; /* scenario_id */
+ char *scenario_nm; /* string of scenario_id */
+ int priority; /* priority for dynamic scenario */
+ int keep_frame_tick; /* keep qos lock during specific frames when dynamic scenario */
+
+ /* function pointer to check a scenario */
+ int (*check_func)(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame, ...);
+};
+
+struct fimc_is_dvfs_scenario_ctrl {
+ int cur_scenario_id; /* selected scenario idx */
+ int cur_frame_tick; /* remained frame tick to keep qos lock in dynamic scenario */
+ int scenario_cnt; /* total scenario count */
+ int cur_scenario_idx; /* selected scenario idx for scenarios */
+ struct fimc_is_dvfs_scenario *scenarios;
+};
+
+int fimc_is_dvfs_init(struct fimc_is_resourcemgr *resourcemgr);
+int fimc_is_dvfs_sel_scenario(u32 type, struct fimc_is_device_ischain *device, struct fimc_is_frame *frame);
+int fimc_is_get_qos(struct fimc_is_core *core, u32 type, u32 scenario_id);
+int fimc_is_set_dvfs(struct fimc_is_device_ischain *device, u32 scenario_id);
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_ERR_H
+#define FIMC_IS_ERR_H
+
+#define IS_ERROR_VER 014 /* IS ERROR VERSION 0.14 */
+
+#define IS_ERROR_SUCCESS 0
+/* General 1 ~ 100 */
+#define IS_ERROR_INVALID_COMMAND (IS_ERROR_SUCCESS+1)
+#define IS_ERROR_REQUEST_FAIL (IS_ERROR_INVALID_COMMAND+1)
+#define IS_ERROR_INVALID_SCENARIO (IS_ERROR_REQUEST_FAIL+1)
+#define IS_ERROR_INVALID_SENSORID (IS_ERROR_INVALID_SCENARIO+1)
+#define IS_ERROR_INVALID_MODE_CHANGE (IS_ERROR_INVALID_SENSORID+1)
+#define IS_ERROR_INVALID_MAGIC_NUMBER (IS_ERROR_INVALID_MODE_CHANGE+1)
+#define IS_ERROR_INVALID_SETFILE_HDR (IS_ERROR_INVALID_MAGIC_NUMBER+1)
+#define IS_ERROR_ISP_SETFILE_VERSION_MISMATCH (IS_ERROR_INVALID_SETFILE_HDR+1)
+#define IS_ERROR_ISP_SETFILE_REVISION_MISMATCH\
+ (IS_ERROR_ISP_SETFILE_VERSION_MISMATCH+1)
+#define IS_ERROR_BUSY (IS_ERROR_ISP_SETFILE_REVISION_MISMATCH+1)
+#define IS_ERROR_SET_PARAMETER (IS_ERROR_BUSY+1)
+#define IS_ERROR_INVALID_PATH (IS_ERROR_SET_PARAMETER+1)
+#define IS_ERROR_OPEN_SENSOR_FAIL (IS_ERROR_INVALID_PATH+1)
+#define IS_ERROR_ENTRY_MSG_THREAD_DOWN (IS_ERROR_OPEN_SENSOR_FAIL+1)
+#define IS_ERROR_ISP_FRAME_END_NOT_DONE (IS_ERROR_ENTRY_MSG_THREAD_DOWN+1)
+#define IS_ERROR_DRC_FRAME_END_NOT_DONE (IS_ERROR_ISP_FRAME_END_NOT_DONE+1)
+#define IS_ERROR_SCALERC_FRAME_END_NOT_DONE (IS_ERROR_DRC_FRAME_END_NOT_DONE+1)
+#define IS_ERROR_DIS_FRAME_END_NOT_DONE (IS_ERROR_SCALERC_FRAME_END_NOT_DONE+1)
+#define IS_ERROR_TDNR_FRAME_END_NOT_DONE (IS_ERROR_DIS_FRAME_END_NOT_DONE+1)
+#define IS_ERROR_SCALERP_FRAME_END_NOT_DONE (IS_ERROR_TDNR_FRAME_END_NOT_DONE+1)
+#define IS_ERROR_WAIT_STREAM_OFF_NOT_DONE\
+ (IS_ERROR_SCALERP_FRAME_END_NOT_DONE+1)
+#define IS_ERROR_NO_MSG_IS_RECEIVED (IS_ERROR_WAIT_STREAM_OFF_NOT_DONE+1)
+#define IS_ERROR_SENSOR_MSG_FAIL (IS_ERROR_NO_MSG_IS_RECEIVED+1)
+#define IS_ERROR_ISP_MSG_FAIL (IS_ERROR_SENSOR_MSG_FAIL+1)
+#define IS_ERROR_DRC_MSG_FAIL (IS_ERROR_ISP_MSG_FAIL+1)
+#define IS_ERROR_SCALERC_MSG_FAIL (IS_ERROR_DRC_MSG_FAIL+1)
+#define IS_ERROR_DIS_MSG_FAIL (IS_ERROR_ODC_MSG_FAIL+1)
+#define IS_ERROR_TDNR_MSG_FAIL (IS_ERROR_DIS_MSG_FAIL+1)
+#define IS_ERROR_SCALERP_MSG_FAIL (IS_ERROR_TDNR_MSG_FAIL+1)
+#define IS_ERROR_LHFD_MSG_FAIL (IS_ERROR_SCALERP_MSG_FAIL+1)
+#define IS_ERROR_INTERNAL_STOP (IS_ERROR_LHFD_MSG_FAIL+1)
+#define IS_ERROR_UNKNOWN 1000
+#define IS_ERROR_TIME_OUT_FLAG 0x80000000
+
+/* Sensor 100 ~ 200 */
+#define IS_ERROR_SENSOR_PWRDN_FAIL 100
+#define IS_ERROR_SENSOR_STREAM_ON_FAIL (IS_ERROR_SENSOR_PWRDN_FAIL+1)
+#define IS_ERROR_SENSOR_STREAM_OFF_FAIL (IS_ERROR_SENSOR_STREAM_ON_FAIL+1)
+
+/* ISP 200 ~ 300 */
+#define IS_ERROR_ISP_PWRDN_FAIL 200
+#define IS_ERROR_ISP_MULTIPLE_INPUT (IS_ERROR_ISP_PWRDN_FAIL+1)
+#define IS_ERROR_ISP_ABSENT_INPUT (IS_ERROR_ISP_MULTIPLE_INPUT+1)
+#define IS_ERROR_ISP_ABSENT_OUTPUT (IS_ERROR_ISP_ABSENT_INPUT+1)
+#define IS_ERROR_ISP_NONADJACENT_OUTPUT (IS_ERROR_ISP_ABSENT_OUTPUT+1)
+#define IS_ERROR_ISP_FORMAT_MISMATCH (IS_ERROR_ISP_NONADJACENT_OUTPUT+1)
+#define IS_ERROR_ISP_WIDTH_MISMATCH (IS_ERROR_ISP_FORMAT_MISMATCH+1)
+#define IS_ERROR_ISP_HEIGHT_MISMATCH (IS_ERROR_ISP_WIDTH_MISMATCH+1)
+#define IS_ERROR_ISP_BITWIDTH_MISMATCH (IS_ERROR_ISP_HEIGHT_MISMATCH+1)
+#define IS_ERROR_ISP_FRAME_END_TIME_OUT (IS_ERROR_ISP_BITWIDTH_MISMATCH+1)
+
+/* DRC 300 ~ 400 */
+#define IS_ERROR_DRC_PWRDN_FAIL 300
+#define IS_ERROR_DRC_MULTIPLE_INPUT (IS_ERROR_DRC_PWRDN_FAIL+1)
+#define IS_ERROR_DRC_ABSENT_INPUT (IS_ERROR_DRC_MULTIPLE_INPUT+1)
+#define IS_ERROR_DRC_NONADJACENT_INTPUT (IS_ERROR_DRC_ABSENT_INPUT+1)
+#define IS_ERROR_DRC_ABSENT_OUTPUT (IS_ERROR_DRC_NONADJACENT_INTPUT+1)
+#define IS_ERROR_DRC_NONADJACENT_OUTPUT (IS_ERROR_DRC_ABSENT_OUTPUT+1)
+#define IS_ERROR_DRC_FORMAT_MISMATCH (IS_ERROR_DRC_NONADJACENT_OUTPUT+1)
+#define IS_ERROR_DRC_WIDTH_MISMATCH (IS_ERROR_DRC_FORMAT_MISMATCH+1)
+#define IS_ERROR_DRC_HEIGHT_MISMATCH (IS_ERROR_DRC_WIDTH_MISMATCH+1)
+#define IS_ERROR_DRC_BITWIDTH_MISMATCH (IS_ERROR_DRC_HEIGHT_MISMATCH+1)
+#define IS_ERROR_DRC_FRAME_END_TIME_OUT (IS_ERROR_DRC_BITWIDTH_MISMATCH+1)
+
+/*SCALERC(400~500)*/
+#define IS_ERROR_SCALERC_PWRDN_FAIL 400
+
+/*DIS(600~700)*/
+#define IS_ERROR_DIS_PWRDN_FAIL 600
+
+/*TDNR(700~800)\r*/
+#define IS_ERROR_TDNR_PWRDN_FAIL 700
+
+/*SCALERP(800~900)*/
+#define IS_ERROR_SCALERP_PWRDN_FAIL 800
+
+/*FD(900~1000)*/
+#define IS_ERROR_FD_PWRDN_FAIL 900
+#define IS_ERROR_FD_MULTIPLE_INPUT (IS_ERROR_FD_PWRDN_FAIL+1)
+#define IS_ERROR_FD_ABSENT_INPUT (IS_ERROR_FD_MULTIPLE_INPUT+1)
+#define IS_ERROR_FD_NONADJACENT_INPUT (IS_ERROR_FD_ABSENT_INPUT+1)
+#define IS_ERROR_LHFD_FRAME_END_TIME_OUT \
+ (IS_ERROR_FD_NONADJACENT_INPUT+1)
+
+/* Set parameter error enum */
+enum error {
+ /* Common error (0~99) */
+ ERROR_COMMON_NO = 0,
+ ERROR_COMMON_CMD = 1, /* Invalid command*/
+ ERROR_COMMON_PARAMETER = 2, /* Invalid parameter*/
+ /* setfile is not loaded before adjusting */
+ ERROR_COMMON_SETFILE_LOAD = 3,
+ /* setfile is not Adjusted before runnng. */
+ ERROR_COMMON_SETFILE_ADJUST = 4,
+ /* index of setfile is not valid. */
+ ERROR_COMMON_SETFILE_INDEX = 5,
+ /* Input path can be changed in ready state(stop) */
+ ERROR_COMMON_INPUT_PATH = 6,
+ /* IP can not start if input path is not set */
+ ERROR_COMMON_INPUT_INIT = 7,
+ /* Output path can be changed in ready state(stop) */
+ ERROR_COMMON_OUTPUT_PATH = 8,
+ /* IP can not start if output path is not set */
+ ERROR_COMMON_OUTPUT_INIT = 9,
+
+ ERROR_CONTROL_NO = ERROR_COMMON_NO,
+ ERROR_CONTROL_BYPASS = 11, /* Enable or Disable */
+ ERROR_CONTROL_BUF = 12, /* invalid buffer info */
+
+ ERROR_OTF_INPUT_NO = ERROR_COMMON_NO,
+ /* invalid command */
+ ERROR_OTF_INPUT_CMD = 21,
+ /* invalid format (DRC: YUV444, FD: YUV444, 422, 420) */
+ ERROR_OTF_INPUT_FORMAT = 22,
+ /* invalid width (DRC: 128~8192, FD: 32~8190) */
+ ERROR_OTF_INPUT_WIDTH = 23,
+ /* invalid height (DRC: 64~8192, FD: 16~8190) */
+ ERROR_OTF_INPUT_HEIGHT = 24,
+ /* invalid bit-width (DRC: 8~12bits, FD: 8bit) */
+ ERROR_OTF_INPUT_BIT_WIDTH = 25,
+ /* invalid frame time for ISP */
+ ERROR_OTF_INPUT_USER_FRAMETILE = 26,
+
+ ERROR_DMA_INPUT_NO = ERROR_COMMON_NO,
+ /* invalid width (DRC: 128~8192, FD: 32~8190) */
+ ERROR_DMA_INPUT_WIDTH = 31,
+ /* invalid height (DRC: 64~8192, FD: 16~8190) */
+ ERROR_DMA_INPUT_HEIGHT = 32,
+ /* invalid format (DRC: YUV444 or YUV422, FD: YUV444, 422, 420) */
+ ERROR_DMA_INPUT_FORMAT = 33,
+ /* invalid bit-width (DRC: 8~12bit, FD: 8bit) */
+ ERROR_DMA_INPUT_BIT_WIDTH = 34,
+ /* invalid order(DRC: YYCbCrorYCbYCr, FD:NO,YYCbCr,YCbYCr,CbCr,CrCb) */
+ ERROR_DMA_INPUT_ORDER = 35,
+ /* invalid palne (DRC: 3, FD: 1, 2, 3) */
+ ERROR_DMA_INPUT_PLANE = 36,
+
+ ERROR_OTF_OUTPUT_NO = ERROR_COMMON_NO,
+ /* invalid width (DRC: 128~8192) */
+ ERROR_OTF_OUTPUT_WIDTH = 41,
+ /* invalid height (DRC: 64~8192) */
+ ERROR_OTF_OUTPUT_HEIGHT = 42,
+ /* invalid format (DRC: YUV444) */
+ ERROR_OTF_OUTPUT_FORMAT = 43,
+ /* invalid bit-width (DRC: 8~12bits) */
+ ERROR_OTF_OUTPUT_BIT_WIDTH = 44,
+ /* invalid crop size (ODC: left>2, right>10) */
+ ERROR_OTF_OUTPUT_CROP = 45,
+
+ ERROR_DMA_OUTPUT_NO = ERROR_COMMON_NO,
+ ERROR_DMA_OUTPUT_WIDTH = 51, /* invalid width */
+ ERROR_DMA_OUTPUT_HEIGHT = 52, /* invalid height */
+ ERROR_DMA_OUTPUT_FORMAT = 53, /* invalid format */
+ ERROR_DMA_OUTPUT_BIT_WIDTH = 54, /* invalid bit-width */
+ ERROR_DMA_OUTPUT_PLANE = 55, /* invalid plane */
+ ERROR_DMA_OUTPUT_ORDER = 56, /* invalid order */
+ ERROR_DMA_OUTPUT_BUF = 57, /* invalid buffer info */
+
+ ERROR_GLOBAL_SHOTMODE_NO = ERROR_COMMON_NO,
+
+ /* SENSOR Error(100~199) */
+ ERROR_SENSOR_NO = ERROR_COMMON_NO,
+ ERROR_SENSOR_I2C_FAIL = 101,
+ ERROR_SENSOR_INVALID_FRAMERATE,
+ ERROR_SENSOR_INVALID_EXPOSURETIME,
+ ERROR_SENSOR_INVALID_SIZE,
+ ERROR_SENSOR_ACTURATOR_INIT_FAIL,
+ ERROR_SENSOR_INVALID_AF_POS,
+ ERROR_SENSOR_UNSUPPORT_FUNC,
+ ERROR_SENSOR_UNSUPPORT_PERI,
+ ERROR_SENSOR_UNSUPPORT_AF,
+ ERROR_SENSOR_FLASH_FAIL,
+ ERROR_SENSOR_START_FAIL,
+ ERROR_SENSOR_STOP_FAIL,
+
+ /* ISP Error (200~299) */
+ ERROR_ISP_AF_NO = ERROR_COMMON_NO,
+ ERROR_ISP_AF_BUSY = 201,
+ ERROR_ISP_AF_INVALID_COMMAND = 202,
+ ERROR_ISP_AF_INVALID_MODE = 203,
+ ERROR_ISP_FLASH_NO = ERROR_COMMON_NO,
+ ERROR_ISP_AWB_NO = ERROR_COMMON_NO,
+ ERROR_ISP_IMAGE_EFFECT_NO = ERROR_COMMON_NO,
+ ERROR_ISP_IMAGE_EFFECT_INVALID = 231,
+ ERROR_ISP_ISO_NO = ERROR_COMMON_NO,
+ ERROR_ISP_ADJUST_NO = ERROR_COMMON_NO,
+ ERROR_ISP_METERING_NO = ERROR_COMMON_NO,
+ ERROR_ISP_AFC_NO = ERROR_COMMON_NO,
+
+ /* DRC Error (300~399) */
+
+ /* FD Error (400~499) */
+ ERROR_FD_NO = ERROR_COMMON_NO,
+ /* Invalid max number (1~16) */
+ ERROR_FD_CONFIG_MAX_NUMBER_STATE = 401,
+ ERROR_FD_CONFIG_MAX_NUMBER_INVALID = 402,
+ ERROR_FD_CONFIG_YAW_ANGLE_STATE = 403,
+ ERROR_FD_CONFIG_YAW_ANGLE_INVALID = 404,
+ ERROR_FD_CONFIG_ROLL_ANGLE_STATE = 405,
+ ERROR_FD_CONFIG_ROLL_ANGLE_INVALID = 406,
+ ERROR_FD_CONFIG_SMILE_MODE_INVALID = 407,
+ ERROR_FD_CONFIG_BLINK_MODE_INVALID = 408,
+ ERROR_FD_CONFIG_EYES_DETECT_INVALID = 409,
+ ERROR_FD_CONFIG_MOUTH_DETECT_INVALID = 410,
+ ERROR_FD_CONFIG_ORIENTATION_STATE = 411,
+ ERROR_FD_CONFIG_ORIENTATION_INVALID = 412,
+ ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID = 413,
+ /* PARAM_FdResultStr can be only applied
+ * in ready-state or stream off */
+ ERROR_FD_RESULT = 414,
+ /* PARAM_FdModeStr can be only applied
+ * in ready-state or stream off */
+ ERROR_FD_MODE = 415,
+
+ /*SCALER ERR(500~599)*/
+ ERROR_SCALER_NO = ERROR_COMMON_NO,
+ ERROR_SCALER_DMA_OUTSEL = 501,
+ ERROR_SCALER_H_RATIO = 502,
+ ERROR_SCALER_V_RATIO = 503,
+ ERROR_SCALER_FRAME_BUFFER_SEQ = 504,
+
+ ERROR_SCALER_IMAGE_EFFECT = 510,
+
+ ERROR_SCALER_ROTATE = 520,
+ ERROR_SCALER_FLIP = 521,
+
+};
+
+enum ShotErrorType {
+ IS_SHOT_SUCCESS = 0,
+ /* Un-known state.(Normally under processing.) */
+ IS_SHOT_UNKNOWN,
+ /* Bad frame. Ndone is occured at provious group. */
+ IS_SHOT_BAD_FRAME,
+ /* Metadata is not valid. For example, sirc sdk's fd is not valid. */
+ IS_SHOT_CORRUPTED_FRAME,
+ /* Processing of previous group is not complete. */
+ IS_SHOT_EARLY_FRAME,
+ /* Shot is too late at OTF mode. */
+ IS_SHOT_LATE_FRAME,
+ /* Shot is coming when group is process-stop. */
+ IS_SHOT_GROUP_PROCESSSTOP,
+ /* Frame number is not allocated. */
+ IS_SHOT_INVALID_FRAMENUMBER,
+ /* Overflow is occred during processing. */
+ IS_SHOT_OVERFLOW,
+ /* Shot is time-out during processing.(Unknown reason.) */
+ IS_SHOT_SAME_FRAME_COUNT,
+ /* Shot is time-out during processing.(Unknown reason.) */
+ IS_SHOT_TIMEOUT,
+ /* Shot is droped at BufferEntry. */
+ IS_SHOT_DROP,
+ IS_SHOT_3AA_FRAME_END,
+ IS_SHOT_IP_CLOCK_OFF,
+ IS_SHOT_ENDPROC_DELAY
+};
+
+enum REPORT_ERR_TYPE {
+ REPORT_ERR_CIS_ID = 0,
+ REPORT_ERR_CIS_CRC = 1,
+ REPORT_ERR_CIS_ECC = 2,
+ REPORT_ERR_CIS_OVERFLOW_VC0 = 3,
+ REPORT_ERR_CIS_LOST_FE_VC0 = 4,
+ REPORT_ERR_CIS_LOST_FS_VC0 = 5,
+ REPORT_ERR_CIS_SOT_VC0 = 6,
+ REPORT_ERR_CIS_SOT_VC1 = 7,
+ REPORT_ERR_CIS_SOT_VC2 = 8,
+ REPORT_ERR_CIS_SOT_VC3 = 9,
+ REPORT_ERR_3AA_OVERFLOW = 10,
+ REPORT_ERR_FLITE_D_OVERFLOW = 11,
+ REPORT_ERR_COMPANION_LOST_FRAME = 12,
+ REPORT_ERR_3A_ALGORITHM_DELAYED = 13,
+ REPORT_ERR_END
+};
+
+#define ENOBASE_IS 0x10000
+#define ENOSHOT (ENOBASE_IS + 1) /* shot error */
+#define ENOMDONE (ENOBASE_IS + 2) /* meta done error */
+
+#endif
--- /dev/null
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include "fimc-is-fan53555.h"
+
+/**
+ * FAN53555 Vout Tables
+ */
+static const struct fan53555_vout vout_tables[] = {
+ {0, FAN53555_VOUT_1P00, "1.00"}, /* defualt voltage */
+ {1, FAN53555_VOUT_0P88, "0.88"},
+ {2, FAN53555_VOUT_0P90, "0.90"},
+ {3, FAN53555_VOUT_0P93, "0.93"},
+ {4, FAN53555_VOUT_0P95, "0.95"},
+ {5, FAN53555_VOUT_0P98, "0.98"},
+ {6, FAN53555_VOUT_1P00, "1.00"},
+};
+
+/**
+ * fan53555_get_vout_val: get i2c register value to set vout of dcdc regulator.
+ */
+int fan53555_get_vout_val(int sel)
+{
+ int i, vout = vout_tables[0].val;
+
+ if (sel < 0)
+ pr_err("%s: error, invalid sel %d\n", __func__, sel);
+
+ for (i = 0; ARRAY_SIZE(vout_tables); i++) {
+ if (vout_tables[i].sel == sel) {
+ return vout_tables[i].val;
+ }
+ }
+
+ pr_err("%s: warning, default voltage selected. sel %d\n", __func__, sel);
+
+ return vout;
+}
+
+/**
+ * fan53555_get_vout_name: get voltage name of vout as string.
+ */
+ const char *fan53555_get_vout_str(int sel)
+{
+ const char *vout = vout_tables[0].vout;
+ int i;
+
+ if (sel < 0)
+ pr_err("%s: error, invalid sel %d\n", __func__, sel);
+
+ for (i = 0; ARRAY_SIZE(vout_tables); i++) {
+ if (vout_tables[i].sel == sel) {
+ return vout_tables[i].vout;
+ }
+ }
+
+ pr_err("%s: warning, default voltage selected. sel %d\n", __func__, sel);
+
+ return vout;
+}
+
+int fan53555_enable_vsel0(struct i2c_client *client, int on_off)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, REG_VSEL0);
+ if(ret < 0){
+ pr_err("%s: read error = %d , try again", __func__, ret);
+ ret = i2c_smbus_read_byte_data(client, REG_VSEL0);
+ if (ret < 0)
+ pr_err("%s: read 2nd error = %d", __func__, ret);
+ }
+
+ ret &= (~VSEL0_BUCK_EN0);
+ ret |= (on_off << VSEL0_BUCK_EN0_SHIFT);
+
+ ret = i2c_smbus_write_byte_data(client, REG_VSEL0, (BYTE)ret);
+ if (ret < 0){
+ pr_err("%s: write error = %d , try again", __func__, ret);
+ ret = i2c_smbus_write_byte_data(client, REG_VSEL0, (BYTE)ret);
+ if (ret < 0)
+ pr_err("%s: write 2nd error = %d", __func__, ret);
+ }
+ return ret;
+}
+
+/**
+ * fan53555_set_vsel0_vout: set dcdc vout with i2c register value.
+ */
+int fan53555_set_vsel0_vout(struct i2c_client *client, int vout)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, REG_VSEL0);
+ if(ret < 0){
+ pr_err("%s: read error = %d , try again", __func__, ret);
+ ret = i2c_smbus_read_byte_data(client, REG_VSEL0);
+ if (ret < 0)
+ pr_err("%s: read 2nd error = %d", __func__, ret);
+ }
+
+ ret &= (~VSEL0_NSEL0);
+ ret |= vout;
+
+ ret = i2c_smbus_write_byte_data(client, REG_VSEL0, (BYTE)ret);
+ if (ret < 0){
+ pr_err("%s: write error = %d , try again", __func__, ret);
+ ret = i2c_smbus_write_byte_data(client, REG_VSEL0, (BYTE)ret);
+ if (ret < 0)
+ pr_err("%s: write 2nd error = %d", __func__, ret);
+ }
+ return ret;
+}
+
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include "fimc-is-core.h"
+
+typedef unsigned char BYTE;
+
+#define REG_VSEL0 0x00
+#define VSEL0_NSEL0 0x3f
+#define VSEL0_BUCK_EN0_SHIFT 7
+#define VSEL0_BUCK_EN0 (0x01 << VSEL0_BUCK_EN0_SHIFT)
+#define VSEL0_INIT_VAL VSEL0_BUCK_EN0 | FAN53555_VOUT_1P00
+
+// FAN53555UC08X : Vout = 0.60V + NSELx * 10mV
+enum{
+ FAN53555_VOUT_0P60 = 0,
+ FAN53555_VOUT_0P61,
+ FAN53555_VOUT_0P62,
+ FAN53555_VOUT_0P63,
+ FAN53555_VOUT_0P64,
+ FAN53555_VOUT_0P65,
+ FAN53555_VOUT_0P66,
+ FAN53555_VOUT_0P67,
+ FAN53555_VOUT_0P68,
+ FAN53555_VOUT_0P69,
+
+ FAN53555_VOUT_0P70 = 10,
+ FAN53555_VOUT_0P71,
+ FAN53555_VOUT_0P72,
+ FAN53555_VOUT_0P73,
+ FAN53555_VOUT_0P74,
+ FAN53555_VOUT_0P75,
+ FAN53555_VOUT_0P76,
+ FAN53555_VOUT_0P77,
+ FAN53555_VOUT_0P78,
+ FAN53555_VOUT_0P79,
+
+ FAN53555_VOUT_0P80 = 20,
+ FAN53555_VOUT_0P81,
+ FAN53555_VOUT_0P82,
+ FAN53555_VOUT_0P83,
+ FAN53555_VOUT_0P84,
+ FAN53555_VOUT_0P85,
+ FAN53555_VOUT_0P86,
+ FAN53555_VOUT_0P87,
+ FAN53555_VOUT_0P88,
+ FAN53555_VOUT_0P89,
+
+ FAN53555_VOUT_0P90 = 30,
+ FAN53555_VOUT_0P91,
+ FAN53555_VOUT_0P92,
+ FAN53555_VOUT_0P93,
+ FAN53555_VOUT_0P94,
+ FAN53555_VOUT_0P95,
+ FAN53555_VOUT_0P96,
+ FAN53555_VOUT_0P97,
+ FAN53555_VOUT_0P98,
+ FAN53555_VOUT_0P99,
+
+ FAN53555_VOUT_1P00 = 40,
+ FAN53555_VOUT_1P01,
+ FAN53555_VOUT_1P02, // VSEL0 default, 08X
+ FAN53555_VOUT_1P03,
+ FAN53555_VOUT_1P04,
+ FAN53555_VOUT_1P05,
+ FAN53555_VOUT_1P06,
+ FAN53555_VOUT_1P07,
+ FAN53555_VOUT_1P08,
+ FAN53555_VOUT_1P09,
+
+ FAN53555_VOUT_1P10 = 50,
+ FAN53555_VOUT_1P11,
+ FAN53555_VOUT_1P12,
+ FAN53555_VOUT_1P13,
+ FAN53555_VOUT_1P14,
+ FAN53555_VOUT_1P15, // VSEL1 default, 08X
+ FAN53555_VOUT_1P16,
+ FAN53555_VOUT_1P17,
+ FAN53555_VOUT_1P18,
+ FAN53555_VOUT_1P19,
+
+ FAN53555_VOUT_1P20 = 60,
+ FAN53555_VOUT_1P21,
+ FAN53555_VOUT_1P22,
+ FAN53555_VOUT_1P23,
+};
+
+struct fan53555_vout {
+ int sel; /* selector, unique value for vout entry and indepedant to dcdc vendor */
+ int val; /* dcdc-specific value for vout register */
+ char vout[7]; /* voltage level string */
+};
+
+int fan53555_get_vout_val(int sel);
+const char *fan53555_get_vout_str(int sel);
+int fan53555_enable_vsel0(struct i2c_client *client, int on_off);
+int fan53555_set_vsel0_vout(struct i2c_client *client, int vout);
+
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+#include "fimc-is-device-sensor.h"
+
+int fimc_is_frame_s_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (item) {
+ item->state = FIMC_IS_FRAME_STATE_FREE;
+
+ list_add_tail(&item->list, &this->frame_free_head);
+ this->frame_fre_cnt++;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_free_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+
+int fimc_is_frame_g_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_fre_cnt) {
+ *item = container_of(this->frame_free_head.next,
+ struct fimc_is_frame, list);
+ list_del(&(*item)->list);
+ this->frame_fre_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_free_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ if (this->frame_fre_cnt)
+ *item = container_of(this->frame_free_head.next,
+ struct fimc_is_frame, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_free_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_ERR "[FRM] fre(%d, %d) :", this->id, this->frame_fre_cnt);
+
+ list_for_each(temp, &this->frame_free_head) {
+ shot = list_entry(temp, struct fimc_is_frame, list);
+ printk(KERN_CONT "%d->", shot->index);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_s_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (item) {
+ list_add_tail(&item->list, &this->frame_request_head);
+ this->frame_req_cnt++;
+
+ item->state = FIMC_IS_FRAME_STATE_REQUEST;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_request_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+int fimc_is_frame_g_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_req_cnt) {
+ *item = container_of(this->frame_request_head.next,
+ struct fimc_is_frame, list);
+ list_del(&(*item)->list);
+ this->frame_req_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_request_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ if (this->frame_req_cnt)
+ *item = container_of(this->frame_request_head.next,
+ struct fimc_is_frame, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_request_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_ERR "[FRM] req(%d, %d) :",
+ this->id, this->frame_req_cnt);
+
+ list_for_each(temp, &this->frame_request_head) {
+ shot = list_entry(temp, struct fimc_is_frame, list);
+ printk(KERN_CONT "%d->", shot->index);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_s_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (item) {
+ list_add_tail(&item->list, &this->frame_process_head);
+ this->frame_pro_cnt++;
+
+ item->state = FIMC_IS_FRAME_STATE_PROCESS;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_process_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+int fimc_is_frame_g_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_pro_cnt) {
+ *item = container_of(this->frame_process_head.next,
+ struct fimc_is_frame, list);
+ list_del(&(*item)->list);
+ this->frame_pro_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_process_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ if (this->frame_pro_cnt)
+ *item = container_of(this->frame_process_head.next,
+ struct fimc_is_frame, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_process_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_ERR "[FRM] pro(%d, %d) :",
+ this->id, this->frame_pro_cnt);
+
+ list_for_each(temp, &this->frame_process_head) {
+ shot = list_entry(temp, struct fimc_is_frame, list);
+ printk(KERN_CONT "%d(%d)->", shot->index, shot->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_s_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (item) {
+ list_add_tail(&item->list, &this->frame_complete_head);
+ this->frame_com_cnt++;
+
+ item->state = FIMC_IS_FRAME_STATE_COMPLETE;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_complete_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+
+int fimc_is_frame_g_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_com_cnt) {
+ *item = container_of(this->frame_complete_head.next,
+ struct fimc_is_frame, list);
+ list_del(&(*item)->list);
+ this->frame_com_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_complete_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **item)
+{
+ if (this->frame_com_cnt)
+ *item = container_of(this->frame_complete_head.next,
+ struct fimc_is_frame, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_complete_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_ERR "[FRM] com(%d, %d) :",
+ this->id, this->frame_com_cnt);
+
+ list_for_each(temp, &this->frame_complete_head) {
+ shot = list_entry(temp, struct fimc_is_frame, list);
+ printk(KERN_CONT "%d->", shot->index);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_trans_fre_to_req(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_fre_cnt) {
+ err("shot free count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_fre_cnt--;
+
+ fimc_is_frame_s_request_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_req_to_pro(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_req_cnt) {
+ err("shot request count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_req_cnt--;
+
+ fimc_is_frame_s_process_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_req_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_req_cnt) {
+ err("shot request count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_req_cnt--;
+
+ fimc_is_frame_s_complete_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_req_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_req_cnt) {
+ err("shot request count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_req_cnt--;
+
+ fimc_is_frame_s_free_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_pro_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_pro_cnt) {
+ err("shot process count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_pro_cnt--;
+
+ fimc_is_frame_s_complete_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_pro_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_pro_cnt) {
+ err("shot process count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_pro_cnt--;
+
+ fimc_is_frame_s_free_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_fre_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_fre_cnt) {
+ err("shot free count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_fre_cnt--;
+
+ fimc_is_frame_s_complete_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_com_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item)
+{
+ int ret = 0;
+
+ if (!this->frame_com_cnt) {
+ err("shot complete count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_com_cnt--;
+
+ fimc_is_frame_s_free_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_swap_process_head(struct fimc_is_framemgr *this)
+{
+ int ret = 0;
+ struct fimc_is_frame *head;
+ struct fimc_is_frame *next;
+
+ if (!this->frame_pro_cnt) {
+ err("shot process count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ fimc_is_frame_process_head(this, &head);
+
+ list_del(&head->list);
+ this->frame_pro_cnt--;
+
+ /* list swap operation */
+ fimc_is_frame_process_head(this, &next);
+ if (next) {
+ list_del(&next->list);
+ this->frame_pro_cnt--;
+ fimc_is_frame_s_process_shot(this, next);
+ head->has_fcount = false;
+ }
+
+ fimc_is_frame_s_process_shot(this, head);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_probe(struct fimc_is_framemgr *this, u32 id)
+{
+ int ret = 0;
+
+ this->id = id;
+ spin_lock_init(&this->slock);
+
+ return ret;
+}
+
+int fimc_is_frame_open(struct fimc_is_framemgr *this, u32 buffers)
+{
+ int ret = 0;
+ u32 i, j;
+
+ INIT_LIST_HEAD(&this->frame_free_head);
+ INIT_LIST_HEAD(&this->frame_request_head);
+ INIT_LIST_HEAD(&this->frame_process_head);
+ INIT_LIST_HEAD(&this->frame_complete_head);
+
+ this->frame_cnt = buffers;
+ this->frame_fre_cnt = 0;
+ this->frame_req_cnt = 0;
+ this->frame_pro_cnt = 0;
+ this->frame_com_cnt = 0;
+
+ for (i = 0; i < buffers; ++i) {
+ clear_bit(FRAME_INI_MEM, &this->frame[i].memory);
+ clear_bit(FRAME_MAP_MEM, &this->frame[i].memory);
+ this->frame[i].work_data1 = NULL;
+ this->frame[i].work_data2 = NULL;
+ this->frame[i].index = i;
+ this->frame[i].fcount = 0;
+ this->frame[i].rcount = 0;
+ this->frame[i].req_flag = 0;
+ this->frame[i].out_flag = 0;
+
+ this->frame[i].vb = NULL;
+ this->frame[i].shot = NULL;
+ this->frame[i].shot_ext = NULL;
+ this->frame[i].shot_size = 0;
+
+ this->frame[i].stream = NULL;
+ this->frame[i].stream_size = 0;
+
+ this->frame[i].planes = 0;
+ for (j = 0; j < FIMC_IS_MAX_PLANES; ++j) {
+ this->frame[i].kvaddr_buffer[j] = 0;
+ this->frame[i].dvaddr_buffer[j] = 0;
+ }
+
+ this->frame[i].kvaddr_shot = 0;
+ this->frame[i].dvaddr_shot = 0;
+ this->frame[i].has_fcount = false;
+ fimc_is_frame_s_free_shot(this, &this->frame[i]);
+ }
+
+ return ret;
+}
+
+int fimc_is_frame_close(struct fimc_is_framemgr *this)
+{
+ int ret = 0;
+ u32 buffers;
+ u32 i, j;
+
+ buffers = this->frame_cnt;
+
+ for (i = 0; i < buffers; ++i) {
+ clear_bit(FRAME_INI_MEM, &this->frame[i].memory);
+ clear_bit(FRAME_MAP_MEM, &this->frame[i].memory);
+ this->frame[i].index = i;
+ this->frame[i].fcount = 0;
+ this->frame[i].rcount = 0;
+ this->frame[i].req_flag = 0;
+
+ this->frame[i].vb = NULL;
+ this->frame[i].shot = NULL;
+ this->frame[i].shot_ext = NULL;
+ this->frame[i].shot_size = 0;
+
+ this->frame[i].stream = NULL;
+ this->frame[i].stream_size = 0;
+
+ this->frame[i].planes = 0;
+ for (j = 0; j < FIMC_IS_MAX_PLANES; ++j) {
+ this->frame[i].kvaddr_buffer[j] = 0;
+ this->frame[i].dvaddr_buffer[j] = 0;
+ }
+
+ this->frame[i].kvaddr_shot = 0;
+ this->frame[i].dvaddr_shot = 0;
+ this->frame[i].has_fcount = false;
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_print_all(struct fimc_is_framemgr *this)
+{
+ fimc_is_frame_print_free_list(this);
+ fimc_is_frame_print_request_list(this);
+ fimc_is_frame_print_process_list(this);
+ fimc_is_frame_print_complete_list(this);
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/kthread.h>
+
+#ifndef FIMC_IS_FRAME_MGR_H
+#define FIMC_IS_FRAME_MGR_H
+
+#define FIMC_IS_MAX_BUFS VIDEO_MAX_FRAME
+#define FIMC_IS_MAX_PLANES VIDEO_MAX_PLANES
+
+#define FRAMEMGR_ID_INVALID 0x000000
+#define FRAMEMGR_ID_SENSOR 0x000100
+#define FRAMEMGR_ID_3AA_GRP 0x000200
+#define FRAMEMGR_ID_3AAC 0x000400
+#define FRAMEMGR_ID_3AAP 0x000800
+#define FRAMEMGR_ID_ISP_GRP 0x001000
+#define FRAMEMGR_ID_SCC 0x002000
+#define FRAMEMGR_ID_DIS 0x004000
+#define FRAMEMGR_ID_DIS_GRP 0x008000
+#define FRAMEMGR_ID_SCP 0x010000
+#define FRAMEMGR_ID_SHOT (FRAMEMGR_ID_SENSOR | FRAMEMGR_ID_3AA_GRP | \
+ FRAMEMGR_ID_ISP_GRP | FRAMEMGR_ID_DIS_GRP)
+#define FRAMEMGR_ID_STREAM (FRAMEMGR_ID_3AAC | FRAMEMGR_ID_3AAP | \
+ FRAMEMGR_ID_SCC | FRAMEMGR_ID_DIS | \
+ FRAMEMGR_ID_SCP)
+/* #define TRACE_FRAME */
+#define TRACE_ID (FRAMEMGR_ID_SHOT | FRAMEMGR_ID_STREAM)
+
+#define FRAMEMGR_MAX_REQUEST VIDEO_MAX_FRAME
+
+/*flite frame start tasklet*/
+#define FMGR_IDX_0 (0x10)
+/*flite frame end tasklet*/
+#define FMGR_IDX_1 (0x20)
+/*sensor queue*/
+#define FMGR_IDX_2 (0x30)
+/*sensor dequeue*/
+#define FMGR_IDX_3 (0x40)
+/*dev framedone*/
+#define FMGR_IDX_4 (0x50)
+/*scc framedone*/
+#define FMGR_IDX_5 (0x60)
+/*scp framedone*/
+#define FMGR_IDX_6 (0x70)
+/*isp framedone*/
+#define FMGR_IDX_7 (0x80)
+/*scc callback*/
+#define FMGR_IDX_8 (0x90)
+/*scp callback*/
+#define FMGR_IDX_9 (0xA0)
+/*3a0c callback*/
+#define FMGR_IDX_10 (0xB0)
+/*3a1c callback*/
+#define FMGR_IDX_11 (0xC0)
+
+#define framemgr_e_barrier_irqs(this, index, flag) \
+ spin_lock_irqsave(&this->slock, flag)
+#define framemgr_x_barrier_irqr(this, index, flag) \
+ spin_unlock_irqrestore(&this->slock, flag)
+#define framemgr_e_barrier_irq(this, index) \
+ spin_lock_irq(&this->slock)
+#define framemgr_x_barrier_irq(this, index) \
+ spin_unlock_irq(&this->slock)
+#define framemgr_e_barrier(this, index) \
+ spin_lock(&this->slock)
+#define framemgr_x_barrier(this, index) \
+ spin_unlock(&this->slock)
+
+enum fimc_is_frame_shot_state {
+ FIMC_IS_FRAME_STATE_FREE,
+ FIMC_IS_FRAME_STATE_REQUEST,
+ FIMC_IS_FRAME_STATE_PROCESS,
+ FIMC_IS_FRAME_STATE_COMPLETE,
+ FIMC_IS_FRAME_STATE_INVALID
+};
+
+enum fimc_is_frame_reqeust {
+ /* SCC, SCP frame done,
+ ISP meta done */
+ REQ_FRAME,
+ /* 3AA shot done */
+ REQ_3AA_SHOT,
+ /* ISP shot done */
+ REQ_ISP_SHOT,
+ /* DIS shot done */
+ REQ_DIS_SHOT
+};
+
+enum fimc_is_frame_output {
+ /* 3AAC frame done */
+ OUT_3AAC_FRAME,
+ /* 3AAP frame done */
+ OUT_3AAP_FRAME,
+ /* SCC frame done */
+ OUT_SCC_FRAME,
+ /* DIS frame done */
+ OUT_DIS_FRAME,
+ /* SCP frame done */
+ OUT_SCP_FRAME
+};
+
+enum fimc_is_frame_mem {
+ /* initialized memory */
+ FRAME_INI_MEM,
+ /* mapped memory */
+ FRAME_MAP_MEM
+};
+
+struct fimc_is_frame {
+ struct list_head list;
+ struct kthread_work work;
+ void *work_data1;
+ void *work_data2;
+
+ /* group leader use */
+ struct camera2_shot *shot;
+ struct camera2_shot_ext *shot_ext;
+ u32 kvaddr_shot;
+ u32 dvaddr_shot;
+ u32 cookie_shot;
+ u32 shot_size;
+
+ /* stream use */
+ struct camera2_stream *stream;
+ u32 stream_size;
+
+ /* common use */
+ u32 planes;
+ u32 kvaddr_buffer[FIMC_IS_MAX_PLANES];
+ u32 dvaddr_buffer[FIMC_IS_MAX_PLANES];
+
+ /* internal use */
+ unsigned long memory;
+ u32 state;
+ u32 fcount;
+ u32 rcount;
+ u32 index;
+ unsigned long req_flag;
+ unsigned long out_flag;
+ struct vb2_buffer *vb;
+
+ /* for overwriting framecount check */
+ bool has_fcount;
+
+ /* time measure externally */
+ struct timeval *tzone;
+ /* time measure internally */
+ struct timeval time_queued;
+ struct timeval time_shot;
+ struct timeval time_shotdone;
+ struct timeval time_dequeued;
+};
+
+struct fimc_is_framemgr {
+ struct fimc_is_frame frame[FRAMEMGR_MAX_REQUEST];
+
+ struct list_head frame_free_head;
+ struct list_head frame_request_head;
+ struct list_head frame_process_head;
+ struct list_head frame_complete_head;
+
+ spinlock_t slock;
+
+ u32 frame_cnt;
+ u32 frame_fre_cnt;
+ u32 frame_req_cnt;
+ u32 frame_pro_cnt;
+ u32 frame_com_cnt;
+
+ u32 id;
+};
+
+int fimc_is_frame_probe(struct fimc_is_framemgr *this, u32 id);
+int fimc_is_frame_open(struct fimc_is_framemgr *this, u32 buffers);
+int fimc_is_frame_close(struct fimc_is_framemgr *this);
+void fimc_is_frame_print_all(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_g_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_free_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_print_free_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_g_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_request_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_print_request_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_g_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_process_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_print_process_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_g_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_complete_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame **frame);
+void fimc_is_frame_print_complete_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_trans_fre_to_req(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_trans_fre_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_trans_req_to_pro(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_trans_req_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_trans_req_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *item);
+int fimc_is_frame_trans_pro_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_trans_pro_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+int fimc_is_frame_trans_com_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame *frame);
+
+int fimc_is_frame_swap_process_head(struct fimc_is_framemgr *this);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-framemgr.h"
+#include "fimc-is-groupmgr.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-dvfs.h"
+
+/* sysfs variable for debug */
+extern struct fimc_is_sysfs_debug sysfs_debug;
+
+static void fimc_is_gframe_s_info(struct fimc_is_group_frame *item,
+ u32 group_id, struct fimc_is_frame *frame)
+{
+ BUG_ON(!item);
+ BUG_ON(!frame);
+ BUG_ON(!frame->shot_ext);
+
+ memcpy(&item->group_cfg[group_id], &frame->shot_ext->node_group,
+ sizeof(struct camera2_node_group));
+}
+
+static void fimc_is_gframe_free_head(struct fimc_is_group_framemgr *framemgr,
+ struct fimc_is_group_frame **item)
+{
+ if (framemgr->frame_free_cnt)
+ *item = container_of(framemgr->frame_free_head.next,
+ struct fimc_is_group_frame, list);
+ else
+ *item = NULL;
+}
+
+static void fimc_is_gframe_s_free(struct fimc_is_group_framemgr *framemgr,
+ struct fimc_is_group_frame *item)
+{
+ BUG_ON(!framemgr);
+ BUG_ON(!item);
+
+ list_add_tail(&item->list, &framemgr->frame_free_head);
+ framemgr->frame_free_cnt++;
+}
+
+static void fimc_is_gframe_print_free(struct fimc_is_group_framemgr *framemgr)
+{
+ struct list_head *temp;
+ struct fimc_is_group_frame *gframe;
+
+ BUG_ON(!framemgr);
+
+ printk(KERN_ERR "[GFRM] fre(%d) :", framemgr->frame_free_cnt);
+
+ list_for_each(temp, &framemgr->frame_free_head) {
+ gframe = list_entry(temp, struct fimc_is_group_frame, list);
+ printk(KERN_CONT "%d->", gframe->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+static void fimc_is_gframe_group_head(struct fimc_is_group *group,
+ struct fimc_is_group_frame **item)
+{
+ if (group->frame_group_cnt)
+ *item = container_of(group->frame_group_head.next,
+ struct fimc_is_group_frame, list);
+ else
+ *item = NULL;
+}
+
+static void fimc_is_gframe_s_group(struct fimc_is_group *group,
+ struct fimc_is_group_frame *item)
+{
+ BUG_ON(!group);
+ BUG_ON(!item);
+
+ list_add_tail(&item->list, &group->frame_group_head);
+ group->frame_group_cnt++;
+}
+
+static void fimc_is_gframe_print_group(struct fimc_is_group *group)
+{
+ struct list_head *temp;
+ struct fimc_is_group_frame *gframe;
+
+ BUG_ON(!group);
+
+ printk(KERN_ERR "[GFRM] req(%d, %d) :", group->id, group->frame_group_cnt);
+
+ list_for_each(temp, &group->frame_group_head) {
+ gframe = list_entry(temp, struct fimc_is_group_frame, list);
+ printk(KERN_CONT "%d->", gframe->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+static int fimc_is_gframe_trans_fre_to_grp(struct fimc_is_group_framemgr *prev,
+ struct fimc_is_group *next,
+ struct fimc_is_group_frame *item)
+{
+ int ret = 0;
+
+ BUG_ON(!prev);
+ BUG_ON(!next);
+ BUG_ON(!item);
+
+ if (!prev->frame_free_cnt) {
+ err("frame_free_cnt is zero");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ prev->frame_free_cnt--;
+
+ fimc_is_gframe_s_group(next, item);
+
+exit:
+ return ret;
+}
+
+static int fimc_is_gframe_trans_grp_to_grp(struct fimc_is_group *prev,
+ struct fimc_is_group *next,
+ struct fimc_is_group_frame *item)
+{
+ int ret = 0;
+ u32 *input_crop, *output_crop;
+
+ BUG_ON(!prev);
+ BUG_ON(!next);
+ BUG_ON(!item);
+
+ if (!prev->frame_group_cnt) {
+ err("frame_group_cnt is zero");
+ ret = -EFAULT;
+ goto p_err;
+ }
+
+ list_del(&item->list);
+ prev->frame_group_cnt--;
+
+ fimc_is_gframe_s_group(next, item);
+
+ if (item->group_cfg[prev->id].capture[0].vid == next->source_vid) {
+ output_crop = item->group_cfg[prev->id].capture[0].output.cropRegion;
+ input_crop = item->group_cfg[next->id].leader.input.cropRegion;
+ } else if (item->group_cfg[prev->id].capture[1].vid == next->source_vid) {
+ output_crop = item->group_cfg[prev->id].capture[1].output.cropRegion;
+ input_crop = item->group_cfg[next->id].leader.input.cropRegion;
+ } else {
+ merr("vid(%d) is invalid", prev, next->source_vid);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if ((output_crop[0] != input_crop[0]) || (output_crop[1] != input_crop[1]) ||
+ (output_crop[2] != input_crop[2]) || (output_crop[3] != input_crop[3])) {
+ mwarn("GRP%d & GRP%d is incoincidence((%d,%d,%d,%d) != (%d,%d,%d,%d))",
+ prev, prev->id, next->id,
+ output_crop[0], output_crop[1], output_crop[2], output_crop[3],
+ input_crop[0], input_crop[1], input_crop[2], input_crop[3]);
+ input_crop[0] = output_crop[0];
+ input_crop[1] = output_crop[1];
+ input_crop[2] = output_crop[2];
+ input_crop[3] = output_crop[3];
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_gframe_trans_grp_to_fre(struct fimc_is_group *prev,
+ struct fimc_is_group_framemgr *next,
+ struct fimc_is_group_frame *item)
+{
+ int ret = 0;
+
+ BUG_ON(!prev);
+ BUG_ON(!next);
+ BUG_ON(!item);
+
+ if (!prev->frame_group_cnt) {
+ err("frame_group_cnt is zero");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ prev->frame_group_cnt--;
+
+ fimc_is_gframe_s_free(next, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_gframe_cancel(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group, u32 target_fcount)
+{
+ int ret = -EINVAL;
+ struct fimc_is_group_framemgr *gframemgr;
+ struct fimc_is_group_frame *gframe, *temp;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+
+ gframemgr = &groupmgr->framemgr[group->instance];
+
+ spin_lock_irq(&gframemgr->frame_slock);
+
+ list_for_each_entry_safe(gframe, temp, &group->frame_group_head, list) {
+ if (gframe->fcount == target_fcount) {
+ list_del(&gframe->list);
+ group->frame_group_cnt--;
+ mwarn("gframe%d is cancelled", group, target_fcount);
+ fimc_is_gframe_s_free(gframemgr, gframe);
+ ret = 0;
+ break;
+ }
+ }
+
+ spin_unlock_irq(&gframemgr->frame_slock);
+
+ return ret;
+}
+
+void * fimc_is_gframe_rewind(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group, u32 target_fcount)
+{
+ struct fimc_is_group_framemgr *gframemgr;
+ struct fimc_is_group_frame *gframe, *temp;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+
+ gframemgr = &groupmgr->framemgr[group->instance];
+
+ list_for_each_entry_safe(gframe, temp, &group->frame_group_head, list) {
+ if (gframe->fcount == target_fcount)
+ break;
+
+ if (gframe->fcount > target_fcount) {
+ mwarn("target fcount is invalid(%d > %d)", group,
+ gframe->fcount, target_fcount);
+ gframe = NULL;
+ break;
+ }
+
+ list_del(&gframe->list);
+ group->frame_group_cnt--;
+ mwarn("gframe%d is cancelled(count : %d)", group,
+ gframe->fcount, group->frame_group_cnt);
+ fimc_is_gframe_s_free(gframemgr, gframe);
+ }
+
+ if (!group->frame_group_cnt) {
+ merr("gframe%d can't be found", group, target_fcount);
+ gframe = NULL;
+ }
+
+ return gframe;
+}
+
+int fimc_is_gframe_flush(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group)
+{
+ int ret = 0;
+ struct fimc_is_group_framemgr *gframemgr;
+ struct fimc_is_group_frame *gframe, *temp;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+
+ gframemgr = &groupmgr->framemgr[group->instance];
+
+ spin_lock_irq(&gframemgr->frame_slock);
+
+ list_for_each_entry_safe(gframe, temp, &group->frame_group_head, list) {
+ list_del(&gframe->list);
+ group->frame_group_cnt--;
+ mwarn("gframe%d is flushed(count : %d)", group,
+ gframe->fcount, group->frame_group_cnt);
+ fimc_is_gframe_s_free(gframemgr, gframe);
+ }
+
+ spin_unlock_irq(&gframemgr->frame_slock);
+
+ return ret;
+}
+
+static void fimc_is_group_3a0_cancel(struct fimc_is_framemgr *framemgr,
+ struct fimc_is_frame *frame,
+ struct fimc_is_queue *queue,
+ struct fimc_is_video_ctx *vctx,
+ u32 instance)
+{
+ BUG_ON(!vctx);
+ BUG_ON(!framemgr);
+ BUG_ON(!frame);
+ BUG_ON(!queue);
+
+ pr_err("[3A0:D:%d:%d] GRP0 CANCEL(%d, %d)\n", instance,
+ V4L2_TYPE_IS_OUTPUT(queue->vbq->type),
+ frame->fcount, frame->index);
+
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ queue_done(vctx, queue, frame->index, VB2_BUF_STATE_ERROR);
+}
+
+static void fimc_is_group_3a1_cancel(struct fimc_is_framemgr *framemgr,
+ struct fimc_is_frame *frame,
+ struct fimc_is_queue *queue,
+ struct fimc_is_video_ctx *vctx,
+ u32 instance)
+{
+ BUG_ON(!vctx);
+ BUG_ON(!framemgr);
+ BUG_ON(!frame);
+ BUG_ON(!queue);
+
+ pr_err("[3A1:D:%d:%d] GRP1 CANCEL(%d, %d)\n", instance,
+ V4L2_TYPE_IS_OUTPUT(queue->vbq->type),
+ frame->fcount, frame->index);
+
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ queue_done(vctx, queue, frame->index, VB2_BUF_STATE_ERROR);
+}
+
+static void fimc_is_group_isp_cancel(struct fimc_is_framemgr *framemgr,
+ struct fimc_is_frame *frame,
+ struct fimc_is_video_ctx *vctx,
+ u32 instance)
+{
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!framemgr);
+ BUG_ON(!frame);
+
+ pr_err("[ISP:D:%d] GRP2 CANCEL(%d, %d)\n", instance,
+ frame->fcount, frame->index);
+
+ queue = GET_SRC_QUEUE(vctx);
+
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ queue_done(vctx, queue, frame->index, VB2_BUF_STATE_ERROR);
+}
+
+static void fimc_is_group_dis_cancel(struct fimc_is_framemgr *framemgr,
+ struct fimc_is_frame *frame,
+ struct fimc_is_video_ctx *vctx,
+ u32 instance)
+{
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!framemgr);
+ BUG_ON(!frame);
+
+ pr_err("[DIS:D:%d] GRP3 CANCEL(%d, %d)\n", instance,
+ frame->fcount, frame->index);
+
+ queue = GET_SRC_QUEUE(vctx);
+
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ queue_done(vctx, queue, frame->index, VB2_BUF_STATE_ERROR);
+}
+
+static void fimc_is_group_cancel(struct fimc_is_group *group,
+ struct fimc_is_frame *ldr_frame)
+{
+ unsigned long flags;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_framemgr *ldr_framemgr;
+ /* for M2M device */
+ struct fimc_is_framemgr *sub_framemgr = NULL;
+ struct fimc_is_queue *ldr_queue, *sub_queue;
+ struct fimc_is_frame *sub_frame;
+
+ BUG_ON(!group);
+ BUG_ON(!ldr_frame);
+
+ vctx = group->leader.vctx;
+ if (!vctx) {
+ merr("vctx is NULL, critical error", group);
+ return;
+ }
+
+ ldr_framemgr = GET_SRC_FRAMEMGR(vctx);
+ if (!ldr_framemgr) {
+ merr("ldr_framemgr is NULL, critical error", group);
+ return;
+ }
+
+ framemgr_e_barrier_irqs(ldr_framemgr, 0, flags);
+
+ switch (group->id) {
+ case GROUP_ID_3A0:
+ ldr_queue = GET_SRC_QUEUE(vctx);
+ fimc_is_group_3a0_cancel(ldr_framemgr, ldr_frame,
+ ldr_queue, vctx, group->instance);
+ /* for M2M device */
+ sub_framemgr = GET_DST_FRAMEMGR(vctx);
+ break;
+ case GROUP_ID_3A1:
+ ldr_queue = GET_SRC_QUEUE(vctx);
+ fimc_is_group_3a1_cancel(ldr_framemgr, ldr_frame,
+ ldr_queue, vctx, group->instance);
+ /* for M2M device */
+ sub_framemgr = GET_DST_FRAMEMGR(vctx);
+ break;
+ case GROUP_ID_ISP:
+ fimc_is_group_isp_cancel(ldr_framemgr, ldr_frame,
+ vctx, group->instance);
+ break;
+ case GROUP_ID_DIS:
+ fimc_is_group_dis_cancel(ldr_framemgr, ldr_frame,
+ vctx, group->instance);
+ break;
+ default:
+ err("unresolved group id %d", group->id);
+ break;
+ }
+
+ framemgr_x_barrier_irqr(ldr_framemgr, 0, flags);
+
+ if (sub_framemgr) {
+ framemgr_e_barrier_irqs(sub_framemgr, 0, flags);
+
+ switch (group->id) {
+ case GROUP_ID_3A0:
+ sub_queue = GET_DST_QUEUE(vctx);
+ fimc_is_frame_request_head(sub_framemgr, &sub_frame);
+ if (sub_frame)
+ fimc_is_group_3a0_cancel(sub_framemgr, sub_frame,
+ sub_queue, vctx, group->instance);
+ break;
+ case GROUP_ID_3A1:
+ sub_queue = GET_DST_QUEUE(vctx);
+ fimc_is_frame_request_head(sub_framemgr, &sub_frame);
+ if (sub_frame)
+ fimc_is_group_3a1_cancel(sub_framemgr, sub_frame,
+ sub_queue, vctx, group->instance);
+ break;
+ default:
+ err("unresolved group id %d", group->id);
+ break;
+ }
+
+ framemgr_x_barrier_irqr(sub_framemgr, 0, flags);
+ }
+}
+#ifdef CONFIG_USE_VENDER_FEATURE
+/* Flash Mode Control */
+#ifdef CONFIG_LEDS_LM3560
+extern int lm3560_reg_update_export(u8 reg, u8 mask, u8 data);
+#endif
+#ifdef CONFIG_LEDS_SKY81296
+extern int sky81296_torch_ctrl(int state);
+#endif
+
+static void fimc_is_group_set_torch(struct fimc_is_group *group,
+ struct fimc_is_frame *ldr_frame)
+{
+ if (group->prev)
+ return;
+
+ if (group->aeflashMode != ldr_frame->shot->ctl.aa.aeflashMode) {
+ group->aeflashMode = ldr_frame->shot->ctl.aa.aeflashMode;
+ switch (group->aeflashMode) {
+ case AA_FLASHMODE_ON_ALWAYS: /*TORCH mode*/
+#ifdef CONFIG_LEDS_LM3560
+ lm3560_reg_update_export(0xE0, 0xFF, 0xEF);
+#elif defined(CONFIG_LEDS_SKY81296)
+ sky81296_torch_ctrl(1);
+#endif
+ break;
+ case AA_FLASHMODE_START: /*Pre flash mode*/
+#ifdef CONFIG_LEDS_LM3560
+ lm3560_reg_update_export(0xE0, 0xFF, 0xEF);
+#elif defined(CONFIG_LEDS_SKY81296)
+ sky81296_torch_ctrl(1);
+#endif
+ break;
+ case AA_FLASHMODE_CAPTURE: /*Main flash mode*/
+ break;
+ case AA_FLASHMODE_OFF: /*OFF mode*/
+#ifdef CONFIG_LEDS_SKY81296
+ sky81296_torch_ctrl(0);
+#endif
+ break;
+ default:
+ break;
+ }
+ }
+ return;
+}
+#endif
+
+#ifdef DEBUG_AA
+static void fimc_is_group_debug_aa_shot(struct fimc_is_group *group,
+ struct fimc_is_frame *ldr_frame)
+{
+ if (group->prev)
+ return;
+
+#ifdef DEBUG_FLASH
+ if (ldr_frame->shot->ctl.aa.aeflashMode != group->flashmode) {
+ group->flashmode = ldr_frame->shot->ctl.aa.aeflashMode;
+ pr_info("flash ctl : %d(%d)\n", group->flashmode, ldr_frame->fcount);
+ }
+#endif
+}
+
+static void fimc_is_group_debug_aa_done(struct fimc_is_group *group,
+ struct fimc_is_frame *ldr_frame)
+{
+ if (group->prev)
+ return;
+
+#ifdef DEBUG_FLASH
+ if (ldr_frame->shot->dm.flash.firingStable != group->flash.firingStable) {
+ group->flash.firingStable = ldr_frame->shot->dm.flash.firingStable;
+ pr_info("flash stable : %d(%d)\n", group->flash.firingStable, ldr_frame->fcount);
+ }
+
+ if (ldr_frame->shot->dm.flash.flashReady!= group->flash.flashReady) {
+ group->flash.flashReady = ldr_frame->shot->dm.flash.flashReady;
+ pr_info("flash ready : %d(%d)\n", group->flash.flashReady, ldr_frame->fcount);
+ }
+
+ if (ldr_frame->shot->dm.flash.flashOffReady!= group->flash.flashOffReady) {
+ group->flash.flashOffReady = ldr_frame->shot->dm.flash.flashOffReady;
+ pr_info("flash off : %d(%d)\n", group->flash.flashOffReady, ldr_frame->fcount);
+ }
+#endif
+}
+#endif
+
+static void fimc_is_group_start_trigger(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_frame *frame)
+{
+ BUG_ON(!group);
+ BUG_ON(!frame);
+
+ atomic_inc(&group->rcount);
+ queue_kthread_work(group->worker, &frame->work);
+}
+
+static void fimc_is_group_pump(struct kthread_work *work)
+{
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+ struct fimc_is_frame *frame;
+
+ frame = container_of(work, struct fimc_is_frame, work);
+ groupmgr = frame->work_data1;
+ group = frame->work_data2;
+
+ fimc_is_group_start(groupmgr, group, frame);
+}
+
+int fimc_is_groupmgr_probe(struct fimc_is_groupmgr *groupmgr)
+{
+ int ret = 0;
+ u32 i, j;
+
+ for (i = 0; i < FIMC_IS_MAX_NODES; ++i) {
+ spin_lock_init(&groupmgr->framemgr[i].frame_slock);
+ INIT_LIST_HEAD(&groupmgr->framemgr[i].frame_free_head);
+ groupmgr->framemgr[i].frame_free_cnt = 0;
+
+ for (j = 0; j < FIMC_IS_MAX_GFRAME; ++j) {
+ groupmgr->framemgr[i].frame[j].fcount = 0;
+ fimc_is_gframe_s_free(&groupmgr->framemgr[i],
+ &groupmgr->framemgr[i].frame[j]);
+ }
+
+ for (j = 0; j < GROUP_ID_MAX; ++j)
+ groupmgr->group[i][j] = NULL;
+ }
+
+ for (i = 0; i < GROUP_ID_MAX; ++i) {
+ atomic_set(&groupmgr->group_refcount[i], 0);
+ clear_bit(FIMC_IS_GGROUP_START, &groupmgr->group_state[i]);
+ clear_bit(FIMC_IS_GGROUP_INIT, &groupmgr->group_state[i]);
+ clear_bit(FIMC_IS_GGROUP_REQUEST_STOP, &groupmgr->group_state[i]);
+ }
+
+ return ret;
+}
+
+int fimc_is_group_probe(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ u32 entry)
+{
+ int ret = 0;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+
+ group->id = GROUP_ID_INVALID;
+ group->leader.entry = entry;
+
+ clear_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &group->state);
+ clear_bit(FIMC_IS_GROUP_FORCE_STOP, &group->state);
+ clear_bit(FIMC_IS_GROUP_SHOT, &group->state);
+ clear_bit(FIMC_IS_GROUP_READY, &group->state);
+ clear_bit(FIMC_IS_GROUP_RUN, &group->state);
+ clear_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state);
+ clear_bit(FIMC_IS_GROUP_INIT, &group->state);
+
+ return ret;
+}
+
+int fimc_is_group_open(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group, u32 id, u32 instance,
+ struct fimc_is_video_ctx *vctx,
+ struct fimc_is_device_ischain *device,
+ fimc_is_start_callback start_callback)
+{
+ int ret = 0, i;
+ char name[30];
+ struct fimc_is_core *core;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_framemgr *framemgr;
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(!device);
+ BUG_ON(!vctx);
+ BUG_ON(instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(id >= GROUP_ID_MAX);
+
+ leader = &group->leader;
+ framemgr = GET_SRC_FRAMEMGR(vctx);
+ core = (struct fimc_is_core *)device->interface->core;
+
+ mdbgd_ischain("%s(id %d)\n", device, __func__, id);
+
+ if (test_bit(FIMC_IS_GROUP_OPEN, &group->state)) {
+ merr("group%d already open", device, id);
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+ /* 1. start kthread */
+ if (!test_bit(FIMC_IS_GGROUP_START, &groupmgr->group_state[id])) {
+ init_kthread_worker(&groupmgr->group_worker[id]);
+ snprintf(name, sizeof(name), "fimc_is_gworker%d", id);
+ groupmgr->group_task[id] = kthread_run(kthread_worker_fn,
+ &groupmgr->group_worker[id], name);
+ if (IS_ERR(groupmgr->group_task[id])) {
+ err("failed to create group_task%d\n", id);
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ ret = sched_setscheduler_nocheck(groupmgr->group_task[id], SCHED_FIFO, ¶m);
+ if (ret) {
+ merr("sched_setscheduler_nocheck is fail(%d)", group, ret);
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_GGROUP_START, &groupmgr->group_state[id]);
+ }
+
+ group->worker = &groupmgr->group_worker[id];
+ for (i = 0; i < FRAMEMGR_MAX_REQUEST; ++i)
+ init_kthread_work(&framemgr->frame[i].work, fimc_is_group_pump);
+
+ /* 2. Init Group */
+ clear_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &group->state);
+ clear_bit(FIMC_IS_GROUP_FORCE_STOP, &group->state);
+ clear_bit(FIMC_IS_GROUP_SHOT, &group->state);
+ clear_bit(FIMC_IS_GROUP_READY, &group->state);
+ clear_bit(FIMC_IS_GROUP_RUN, &group->state);
+ clear_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state);
+ clear_bit(FIMC_IS_GROUP_INIT, &group->state);
+
+ group->start_callback = start_callback;
+ group->device = device;
+ group->id = id;
+ group->instance = instance;
+ group->source_vid = 0;
+ group->fcount = 0;
+ group->pcount = 0;
+ group->aeflashMode = 0; /* Flash Mode Control */
+ atomic_set(&group->scount, 0);
+ atomic_set(&group->rcount, 0);
+ atomic_set(&group->backup_fcount, 0);
+ atomic_set(&group->sensor_fcount, 1);
+ sema_init(&group->smp_trigger, 0);
+
+ INIT_LIST_HEAD(&group->frame_group_head);
+ group->frame_group_cnt = 0;
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ measure_init(&group->time, group->instance, group->id, 66);
+#endif
+#endif
+
+ /* 3. Subdev Init */
+ mutex_init(&leader->mutex_state);
+ leader->vctx = vctx;
+ leader->group = group;
+ leader->leader = NULL;
+ leader->input.width = 0;
+ leader->input.height = 0;
+ leader->output.width = 0;
+ leader->output.height = 0;
+ clear_bit(FIMC_IS_SUBDEV_START, &leader->state);
+ set_bit(FIMC_IS_SUBDEV_OPEN, &leader->state);
+
+ /* 4. Configure Group & Subdev List */
+ switch (id) {
+ case GROUP_ID_3A0:
+ case GROUP_ID_3A1:
+ /* path configuration */
+ group->prev = NULL;
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, isp)) {
+ group->next = &device->group_isp;
+ /* HACK */
+ group->next->prev = group;
+ } else {
+ group->next = NULL;
+ }
+ group->subdev[ENTRY_SCALERC] = NULL;
+ group->subdev[ENTRY_DIS] = NULL;
+ group->subdev[ENTRY_TDNR] = NULL;
+ group->subdev[ENTRY_SCALERP] = NULL;
+ group->subdev[ENTRY_LHFD] = NULL;
+ group->subdev[ENTRY_3AAC] = &device->taac;
+ group->subdev[ENTRY_3AAP] = &device->taap;
+
+ device->taac.leader = leader;
+ device->taap.leader = leader;
+
+ device->taac.group = group;
+ device->taap.group = group;
+
+ set_bit(FIMC_IS_GROUP_ACTIVE, &group->state);
+ break;
+ case GROUP_ID_ISP:
+ /* path configuration */
+ group->prev = NULL;
+ group->next = NULL;
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, scc))
+ group->subdev[ENTRY_SCALERC] = &device->scc;
+ else
+ group->subdev[ENTRY_SCALERC] = NULL;
+ /* dis is not included to any group initially */
+ group->subdev[ENTRY_DIS] = NULL;
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, dnr))
+ group->subdev[ENTRY_TDNR] = &device->dnr;
+ else
+ group->subdev[ENTRY_TDNR] = NULL;
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, scp))
+ group->subdev[ENTRY_SCALERP] = &device->scp;
+ else
+ group->subdev[ENTRY_SCALERP] = NULL;
+
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, fd))
+ group->subdev[ENTRY_LHFD] = &device->fd;
+ else
+ group->subdev[ENTRY_LHFD] = NULL;
+ group->subdev[ENTRY_3AAC] = NULL;
+ group->subdev[ENTRY_3AAP] = NULL;
+
+ device->scc.leader = leader;
+ device->dis.leader = leader;
+ device->dnr.leader = leader;
+ device->scp.leader = leader;
+ device->fd.leader = leader;
+
+ device->scc.group = group;
+ device->dis.group = group;
+ device->dnr.group = group;
+ device->scp.group = group;
+ device->fd.group = group;
+
+ set_bit(FIMC_IS_GROUP_ACTIVE, &group->state);
+ break;
+ case GROUP_ID_DIS:
+ /* path configuration */
+ group->prev = NULL;
+ group->next = NULL;
+ group->subdev[ENTRY_SCALERC] = NULL;
+ group->subdev[ENTRY_DIS] = NULL;
+ group->subdev[ENTRY_TDNR] = NULL;
+ group->subdev[ENTRY_SCALERP] = NULL;
+ group->subdev[ENTRY_LHFD] = NULL;
+ group->subdev[ENTRY_3AAC] = NULL;
+ group->subdev[ENTRY_3AAP] = NULL;
+
+ clear_bit(FIMC_IS_GROUP_ACTIVE, &group->state);
+ break;
+ default:
+ merr("group id(%d) is invalid", vctx, id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* 5. Update Group Manager */
+ groupmgr->group[instance][id] = group;
+ atomic_inc(&groupmgr->group_refcount[id]);
+ set_bit(FIMC_IS_GROUP_OPEN, &group->state);
+
+p_err:
+ mdbgd_group("%s(%d)\n", group, __func__, ret);
+ return ret;
+}
+
+int fimc_is_group_close(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group)
+{
+ int ret = 0;
+ u32 refcount, i;
+ struct fimc_is_group_framemgr *gframemgr;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+
+ refcount = atomic_read(&groupmgr->group_refcount[group->id]);
+
+ if (!test_bit(FIMC_IS_GROUP_OPEN, &group->state)) {
+ merr("group%d already close", group, group->id);
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+ /*
+ * Maybe there are some waiting smp_shot semaphores when finishing kthread
+ * in group close. This situation caused waiting kthread_stop to finish it
+ * We should check if there are smp_shot in waiting list.
+ */
+ if (test_bit(FIMC_IS_GROUP_INIT, &group->state)) {
+ while (!list_empty(&group->smp_shot.wait_list)) {
+ warn("group%d frame reqs are waiting in semaphore[%d] when closing",
+ group->id, group->smp_shot.count);
+ up(&group->smp_shot);
+ }
+ }
+
+ if ((refcount == 1) &&
+ test_bit(FIMC_IS_GGROUP_INIT, &groupmgr->group_state[group->id]) &&
+ groupmgr->group_task[group->id]) {
+
+ set_bit(FIMC_IS_GGROUP_REQUEST_STOP, &groupmgr->group_state[group->id]);
+
+ /* flush semaphore shot */
+ atomic_inc(&group->smp_shot_count);
+
+ /* flush semaphore trigger */
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state))
+ up(&group->smp_trigger);
+
+ /*
+ * flush kthread wait until all work is complete
+ * it's dangerous if all is not finished
+ * so it's commented currently
+ * flush_kthread_worker(&groupmgr->group_worker[group->id]);
+ */
+ kthread_stop(groupmgr->group_task[group->id]);
+
+ clear_bit(FIMC_IS_GGROUP_REQUEST_STOP, &groupmgr->group_state[group->id]);
+ clear_bit(FIMC_IS_GGROUP_START, &groupmgr->group_state[group->id]);
+ clear_bit(FIMC_IS_GGROUP_INIT, &groupmgr->group_state[group->id]);
+ }
+
+ groupmgr->group[group->instance][group->id] = NULL;
+ atomic_dec(&groupmgr->group_refcount[group->id]);
+
+ /* all group is closed */
+ if (!groupmgr->group[group->instance][GROUP_ID_3A0] &&
+ !groupmgr->group[group->instance][GROUP_ID_3A1] &&
+ !groupmgr->group[group->instance][GROUP_ID_ISP] &&
+ !groupmgr->group[group->instance][GROUP_ID_DIS]) {
+ gframemgr = &groupmgr->framemgr[group->instance];
+ if (gframemgr->frame_free_cnt != FIMC_IS_MAX_GFRAME) {
+ mwarn("gframemgr free count is invalid(%d)", group,
+ gframemgr->frame_free_cnt);
+ INIT_LIST_HEAD(&gframemgr->frame_free_head);
+ gframemgr->frame_free_cnt = 0;
+ for (i = 0; i < FIMC_IS_MAX_GFRAME; ++i) {
+ gframemgr->frame[i].fcount = 0;
+ fimc_is_gframe_s_free(gframemgr,
+ &gframemgr->frame[i]);
+ }
+ }
+ }
+
+ group->id = GROUP_ID_INVALID;
+ clear_bit(FIMC_IS_GROUP_INIT, &group->state);
+ clear_bit(FIMC_IS_GROUP_OPEN, &group->state);
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &group->leader.state);
+
+p_err:
+ mdbgd_group("%s(ref %d, %d)", group, __func__, (refcount - 1), ret);
+ return ret;
+}
+
+int fimc_is_group_init(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ bool otf_input,
+ u32 video_id)
+{
+ int ret = 0;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+
+ if (test_bit(FIMC_IS_GROUP_INIT, &group->state)) {
+ merr("already initialized", group);
+ /* HACK */
+ /* ret = -EINVAL; */
+ goto p_err;
+ }
+
+ group->source_vid = video_id;
+
+ if (!test_bit(FIMC_IS_GGROUP_INIT, &groupmgr->group_state[group->id])) {
+ if (otf_input)
+ sema_init(&groupmgr->group_smp_res[group->id], MIN_OF_SHOT_RSC);
+ else
+ sema_init(&groupmgr->group_smp_res[group->id], 1);
+
+ set_bit(FIMC_IS_GGROUP_INIT, &groupmgr->group_state[group->id]);
+ }
+
+ if (otf_input) {
+ sema_init(&group->smp_shot, MIN_OF_SHOT_RSC);
+ atomic_set(&group->smp_shot_count, MIN_OF_SHOT_RSC);
+ set_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state);
+ group->async_shots = MIN_OF_ASYNC_SHOTS;
+ group->sync_shots = MIN_OF_SYNC_SHOTS;
+ } else {
+ sema_init(&group->smp_shot, 1);
+ atomic_set(&group->smp_shot_count, 1);
+ clear_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state);
+ group->async_shots = 0;
+ group->sync_shots = 1;
+ }
+
+ set_bit(FIMC_IS_GROUP_INIT, &group->state);
+
+p_err:
+ mdbgd_group("%s(otf : %d, %d)\n", group, __func__, otf_input, ret);
+ return ret;
+}
+
+int fimc_is_group_change(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group_isp,
+ struct fimc_is_frame *frame)
+{
+ int ret = 0;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader_isp, *leader_dis;
+ struct fimc_is_group *group_dis;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group_isp);
+ BUG_ON(!group_isp->device);
+ BUG_ON(!frame);
+
+ device = group_isp->device;
+ group_dis = &device->group_dis;
+ leader_dis = &group_dis->leader;
+ leader_isp = &group_isp->leader;
+
+ if (frame->shot->ctl.aa.videoStabilizationMode) {
+ if (!test_bit(FIMC_IS_GROUP_READY, &group_dis->state)) {
+ merr("DIS group is not ready", group_dis);
+ frame->shot->dm.aa.videoStabilizationMode = 0;
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_GROUP_ACTIVE, &group_dis->state)) {
+ pr_info("[GRP%d] Change On\n", group_isp->id);
+
+ /* HACK */
+ sema_init(&group_dis->smp_trigger, 0);
+
+ group_isp->prev = &device->group_3aa;
+ group_isp->next = group_dis;
+ group_isp->subdev[ENTRY_SCALERC] = &device->scc;
+ group_isp->subdev[ENTRY_DIS] = &device->dis;
+ group_isp->subdev[ENTRY_TDNR] = NULL;
+ group_isp->subdev[ENTRY_SCALERP] = NULL;
+ group_isp->subdev[ENTRY_LHFD] = NULL;
+
+ group_dis->next = NULL;
+ group_dis->prev = group_isp;
+ group_dis->subdev[ENTRY_SCALERC] = NULL;
+ group_dis->subdev[ENTRY_DIS] = NULL;
+ group_dis->subdev[ENTRY_TDNR] = &device->dnr;
+ group_dis->subdev[ENTRY_SCALERP] = &device->scp;
+ group_dis->subdev[ENTRY_LHFD] = &device->fd;
+
+ device->scc.leader = leader_isp;
+ device->dis.leader = leader_isp;
+ device->dnr.leader = leader_dis;
+ device->scp.leader = leader_dis;
+ device->fd.leader = leader_dis;
+
+ device->scc.group = group_isp;
+ device->dis.group = group_isp;
+ device->dnr.group = group_dis;
+ device->scp.group = group_dis;
+ device->fd.group = group_dis;
+
+ set_bit(FIMC_IS_GROUP_ACTIVE, &group_dis->state);
+ }
+
+ frame->shot->dm.aa.videoStabilizationMode = 1;
+ } else {
+ if (test_bit(FIMC_IS_GROUP_ACTIVE, &group_dis->state)) {
+ pr_info("[GRP%d] Change Off\n", group_isp->id);
+ group_isp->prev = &device->group_3aa;
+ group_isp->next = NULL;
+ group_isp->subdev[ENTRY_SCALERC] = &device->scc;
+ group_isp->subdev[ENTRY_DIS] = &device->dis;
+ group_isp->subdev[ENTRY_TDNR] = &device->dnr;
+ group_isp->subdev[ENTRY_SCALERP] = &device->scp;
+ group_isp->subdev[ENTRY_LHFD] = &device->fd;
+
+ group_dis->next = NULL;
+ group_dis->prev = NULL;
+ group_dis->subdev[ENTRY_SCALERC] = NULL;
+ group_dis->subdev[ENTRY_DIS] = NULL;
+ group_dis->subdev[ENTRY_TDNR] = NULL;
+ group_dis->subdev[ENTRY_SCALERP] = NULL;
+ group_dis->subdev[ENTRY_LHFD] = NULL;
+
+ device->scc.leader = leader_isp;
+ device->dis.leader = leader_isp;
+ device->dnr.leader = leader_isp;
+ device->scp.leader = leader_isp;
+ device->fd.leader = leader_isp;
+
+ device->scc.group = group_isp;
+ device->dis.group = group_isp;
+ device->dnr.group = group_isp;
+ device->scp.group = group_isp;
+ device->fd.group = group_isp;
+
+ clear_bit(FIMC_IS_GROUP_ACTIVE, &group_dis->state);
+ }
+
+ frame->shot->dm.aa.videoStabilizationMode = 0;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_group_process_start(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ struct fimc_is_device_sensor *sensor = NULL;
+ struct fimc_is_framemgr *framemgr = NULL;
+ u32 shot_resource = 1;
+ u32 sensor_fcount;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(!group->device);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+ BUG_ON(!queue);
+ BUG_ON(!test_bit(FIMC_IS_GGROUP_INIT, &groupmgr->group_state[group->id]));
+ BUG_ON(!test_bit(FIMC_IS_GROUP_INIT, &group->state));
+
+ if (test_bit(FIMC_IS_GROUP_READY, &group->state)) {
+ warn("already group start");
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ framemgr = &queue->framemgr;
+ if (!framemgr) {
+ err("framemgr is null\n");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ sensor = group->device->sensor;
+ if (!sensor) {
+ err("sensor is null\n");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* async & sync shots */
+ if (fimc_is_sensor_g_framerate(sensor) > 30)
+ group->async_shots = max_t(int, MIN_OF_ASYNC_SHOTS,
+ DIV_ROUND_UP(framemgr->frame_cnt, 3));
+ else
+ group->async_shots = MIN_OF_ASYNC_SHOTS;
+ group->sync_shots = max_t(int, MIN_OF_SYNC_SHOTS,
+ framemgr->frame_cnt - group->async_shots);
+
+ /* shot resource */
+ shot_resource = group->async_shots + MIN_OF_SYNC_SHOTS;
+ sema_init(&groupmgr->group_smp_res[group->id], shot_resource);
+
+ /* frame count */
+ sensor_fcount = fimc_is_sensor_g_fcount(sensor) + 1;
+ atomic_set(&group->sensor_fcount, sensor_fcount);
+ atomic_set(&group->backup_fcount, sensor_fcount - 1);
+ group->fcount = sensor_fcount - 1;
+
+ info("[OTF] framerate: %d, async shots: %d, shot resource: %d\n",
+ fimc_is_sensor_g_framerate(sensor),
+ group->async_shots,
+ shot_resource);
+
+ memset(&group->intent_ctl, 0, sizeof(struct camera2_ctl));
+ }
+
+ sema_init(&group->smp_shot, shot_resource);
+ atomic_set(&group->smp_shot_count, shot_resource);
+
+ atomic_set(&group->scount, 0);
+ atomic_set(&group->rcount, 0);
+ sema_init(&group->smp_trigger, 0);
+
+ set_bit(FIMC_IS_GROUP_READY, &group->state);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_group_process_stop(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ int retry;
+ u32 rcount;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_device_sensor *sensor;
+ u32 group_id;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+ BUG_ON(!queue);
+
+ if (!test_bit(FIMC_IS_GROUP_READY, &group->state)) {
+ warn("already group stop");
+ goto p_err;
+ }
+
+ device = group->device;
+ if (!device) {
+ merr("device is NULL", group);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state)) {
+ warn("alredy close sensor was called");
+ goto p_err;
+ }
+
+ sensor = device->sensor;
+ framemgr = &queue->framemgr;
+
+ if (test_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &group->state)) {
+ set_bit(FIMC_IS_GROUP_FORCE_STOP, &group->state);
+ clear_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &group->state);
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state) &&
+ !list_empty(&group->smp_trigger.wait_list)) {
+ if (!sensor) {
+ warn("sensor is NULL, forcely trigger");
+ up(&group->smp_trigger);
+ goto check_completion;
+ }
+
+ if (!test_bit(FIMC_IS_SENSOR_OPEN, &sensor->state)) {
+ warn("sensor is closed, forcely trigger");
+ up(&group->smp_trigger);
+ goto check_completion;
+ }
+
+ if (!test_bit(FIMC_IS_SENSOR_FRONT_START, &sensor->state)) {
+ warn("front sensor is stopped, forcely trigger");
+ up(&group->smp_trigger);
+ goto check_completion;
+ }
+
+ if (!test_bit(FIMC_IS_SENSOR_BACK_START, &sensor->state)) {
+ warn("back sensor is stopped, forcely trigger");
+ up(&group->smp_trigger);
+ goto check_completion;
+ }
+ }
+ }
+
+check_completion:
+ retry = 150;
+ while (--retry && framemgr->frame_req_cnt) {
+ warn("%d frame reqs waiting...\n", framemgr->frame_req_cnt);
+ msleep(20);
+ }
+
+ if (!retry) {
+ merr("waiting(until request empty) is fail", group);
+ ret = -EINVAL;
+ }
+
+ if (!test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ retry = 10;
+ while (--retry && framemgr->frame_pro_cnt) {
+ warn("%d frame pros waiting...\n", framemgr->frame_pro_cnt);
+ msleep(20);
+ }
+
+ if (!retry) {
+ merr("waiting(until process empty) is fail", group);
+ ret = -EINVAL;
+ }
+ }
+
+ if (test_bit(FIMC_IS_GROUP_FORCE_STOP, &group->state)) {
+ ret = fimc_is_itf_force_stop(device, GROUP_ID(group->id));
+ if (ret) {
+ merr("fimc_is_itf_force_stop is fail", group);
+ ret = -EINVAL;
+ }
+ } else {
+ /* if there's only one group of isp, send group id by 3a0 */
+ if ((group->id == GROUP_ID_ISP) &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0) == 0 &&
+ GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1) == 0)
+ group_id = GROUP_ID(GROUP_ID_3A0);
+ else
+ group_id = GROUP_ID(group->id);
+
+ ret = fimc_is_itf_process_stop(device, group_id);
+ if (ret) {
+ merr("fimc_is_itf_process_stop is fail", group);
+ ret = -EINVAL;
+ }
+ }
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ retry = 10;
+ while (--retry && framemgr->frame_pro_cnt) {
+ warn("%d frame pros waiting...\n", framemgr->frame_pro_cnt);
+ msleep(20);
+ }
+
+ if (!retry) {
+ merr("waiting(until process empty) is fail", group);
+ ret = -EINVAL;
+ }
+ }
+
+ rcount = atomic_read(&group->rcount);
+ if (rcount) {
+ merr("rcount is not empty(%d)", group, rcount);
+ ret = -EINVAL;
+ }
+
+ retry = 100;
+ while (--retry && test_bit(FIMC_IS_GROUP_SHOT, &group->state)) {
+ mgwarn(" thread stop waiting...", device, group);
+ msleep(10);
+ }
+
+ if (!retry) {
+ mgerr(" waiting(until thread stop) is fail", device, group);
+ ret = -EINVAL;
+ }
+
+ fimc_is_gframe_flush(groupmgr, group);
+
+ clear_bit(FIMC_IS_GROUP_FORCE_STOP, &group->state);
+ clear_bit(FIMC_IS_GROUP_READY, &group->state);
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state))
+ pr_info("[OTF] sensor fcount: %d, fcount: %d\n",
+ atomic_read(&group->sensor_fcount), group->fcount);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_group_buffer_queue(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_queue *queue,
+ u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_device_sensor *sensor;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(!group->device);
+ BUG_ON(!group->device->sensor);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+ BUG_ON(!queue);
+ BUG_ON(index >= FRAMEMGR_MAX_REQUEST);
+
+ device = group->device;
+ sensor = device->sensor;
+ framemgr = &queue->framemgr;
+
+ /* 1. check frame validation */
+ frame = &framemgr->frame[index];
+ if (!frame) {
+ err("frame is null\n");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (unlikely(!test_bit(FRAME_INI_MEM, &frame->memory))) {
+ err("frame %d is NOT init", index);
+ ret = EINVAL;
+ goto p_err;
+ }
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_queued);
+#endif
+#endif
+
+ /* 2. update frame manager */
+ framemgr_e_barrier_irqs(framemgr, index, flags);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_FREE) {
+ if (frame->req_flag) {
+ merr("req_flag of buffer%d is not clear(%08X)",
+ group, frame->index, (u32)frame->req_flag);
+ frame->req_flag = 0;
+ }
+
+ if (test_bit(OUT_SCC_FRAME, &frame->out_flag)) {
+ merr("scc output is not generated", group);
+ clear_bit(OUT_SCC_FRAME, &frame->out_flag);
+ }
+
+ if (test_bit(OUT_DIS_FRAME, &frame->out_flag)) {
+ merr("dis output is not generated", group);
+ clear_bit(OUT_DIS_FRAME, &frame->out_flag);
+ }
+
+ if (test_bit(OUT_SCP_FRAME, &frame->out_flag)) {
+ merr("scp output is not generated", group);
+ clear_bit(OUT_SCP_FRAME, &frame->out_flag);
+ }
+
+ if (test_bit(OUT_3AAC_FRAME, &frame->out_flag)) {
+ merr("3aac output is not generated", group);
+ clear_bit(OUT_3AAC_FRAME, &frame->out_flag);
+ }
+
+ if (!test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state) &&
+ (framemgr->frame_req_cnt >= 3))
+ mwarn("GROUP%d is working lately(%d)",
+ group, group->id, framemgr->frame_req_cnt);
+
+ frame->fcount = frame->shot->dm.request.frameCount;
+ frame->rcount = frame->shot->ctl.request.frameCount;
+ frame->work_data1 = groupmgr;
+ frame->work_data2 = group;
+
+#ifdef FIXED_FPS_DEBUG
+ frame->shot_ext->shot.ctl.aa.aeTargetFpsRange[0] = FIXED_FPS_VALUE;
+ frame->shot_ext->shot.ctl.aa.aeTargetFpsRange[1] = FIXED_FPS_VALUE;
+ frame->shot_ext->shot.ctl.sensor.frameDuration = 1000000000/FIXED_FPS_VALUE;
+#endif
+
+#ifdef ENABLE_FAST_SHOT
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ memcpy(&group->fast_ctl.aa, &frame->shot->ctl.aa,
+ sizeof(struct camera2_aa_ctl));
+ memcpy(&group->fast_ctl.scaler, &frame->shot->ctl.scaler,
+ sizeof(struct camera2_scaler_ctl));
+ }
+#endif
+
+ fimc_is_frame_trans_fre_to_req(framemgr, frame);
+ } else {
+ err("frame(%d) is invalid state(%d)\n", index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, index, flags);
+
+ if (unlikely(!test_bit(FRAME_MAP_MEM, &frame->memory) &&
+ !test_bit(FIMC_IS_SENSOR_FRONT_START, &sensor->state))) {
+ fimc_is_itf_map(device, GROUP_ID(group->id), frame->dvaddr_shot, frame->shot_size);
+ set_bit(FRAME_MAP_MEM, &frame->memory);
+ }
+
+ fimc_is_group_start_trigger(groupmgr, group, frame);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_group_buffer_finish(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group, u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(!group->leader.vctx);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+ BUG_ON(index >= FRAMEMGR_MAX_REQUEST);
+
+ framemgr = GET_GROUP_FRAMEMGR(group);
+
+ /* 2. update frame manager */
+ framemgr_e_barrier_irqs(framemgr, index, flags);
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ if (frame) {
+ if (frame->index == index) {
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+
+ frame->shot_ext->free_cnt = framemgr->frame_fre_cnt;
+ frame->shot_ext->request_cnt = framemgr->frame_req_cnt;
+ frame->shot_ext->process_cnt = framemgr->frame_pro_cnt;
+ frame->shot_ext->complete_cnt = framemgr->frame_com_cnt;
+ } else {
+ merr("buffer index is NOT matched(G%d, %d != %d)",
+ group, group->id, index, frame->index);
+ fimc_is_frame_print_all(framemgr);
+ ret = -EINVAL;
+ }
+ } else {
+ merr("frame is empty from complete", group);
+ fimc_is_frame_print_all(framemgr);
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, index, flags);
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_dequeued);
+ measure_time(&group->time,
+ &frame->time_queued, &frame->time_shot,
+ &frame->time_shotdone, &frame->time_dequeued);
+#endif
+#endif
+
+ return ret;
+}
+
+int fimc_is_group_start(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_frame *ldr_frame)
+{
+ int ret = 0;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_resourcemgr *resourcemgr;
+ struct fimc_is_group *group_next, *group_prev;
+ struct fimc_is_group_framemgr *gframemgr;
+ struct fimc_is_group_frame *gframe;
+ int async_step = 0;
+ bool try_sdown = false;
+ bool try_rdown = false;
+#ifdef ENABLE_DVFS
+ int scenario_id;
+#endif
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(!group->leader.vctx);
+ BUG_ON(!group->start_callback);
+ BUG_ON(!group->device);
+ BUG_ON(!ldr_frame);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+
+ set_bit(FIMC_IS_GROUP_SHOT, &group->state);
+ atomic_dec(&group->rcount);
+
+ if (test_bit(FIMC_IS_GROUP_FORCE_STOP, &group->state)) {
+ mwarn("g%dframe is cancelled(force stop)", group, group->id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_GGROUP_REQUEST_STOP, &groupmgr->group_state[group->id])) {
+ merr("cancel by group stop #1", group);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ PROGRAM_COUNT(1);
+ ret = down_interruptible(&group->smp_shot);
+ if (ret) {
+ err("down is fail1(%d)", ret);
+ goto p_err;
+ }
+ atomic_dec(&group->smp_shot_count);
+ try_sdown = true;
+
+ /* skip left operation, if group is closing */
+ if (!test_bit(FIMC_IS_GROUP_READY, &group->state)) {
+ mwarn("this group%d was already process stoped", group, group->id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ PROGRAM_COUNT(2);
+ ret = down_interruptible(&groupmgr->group_smp_res[group->id]);
+ if (ret) {
+ err("down is fail2(%d)", ret);
+ goto p_err;
+ }
+ try_rdown = true;
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ if (atomic_read(&group->smp_shot_count) < MIN_OF_SYNC_SHOTS) {
+ PROGRAM_COUNT(3);
+ ret = down_interruptible(&group->smp_trigger);
+ if (ret) {
+ err("down is fail3(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ /*
+ * backup fcount can not be bigger than sensor fcount
+ * otherwise, duplicated shot can be generated.
+ * this is problem can be caused by hal qbuf timing
+ */
+ if (atomic_read(&group->backup_fcount) >=
+ atomic_read(&group->sensor_fcount)) {
+ PROGRAM_COUNT(4);
+ ret = down_interruptible(&group->smp_trigger);
+ if (ret) {
+ err("down is fail4(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ /*
+ * this statement is execued only at initial.
+ * automatic increase the frame count of sensor
+ * for next shot without real frame start
+ */
+
+ /* it's a async shot time */
+ async_step = 1;
+ }
+ }
+
+ if (test_bit(FIMC_IS_GGROUP_REQUEST_STOP, &groupmgr->group_state[group->id])) {
+ err("cancel by group stop #2");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ldr_frame->fcount = atomic_read(&group->sensor_fcount);
+ atomic_set(&group->backup_fcount, ldr_frame->fcount);
+ ldr_frame->shot->dm.request.frameCount = ldr_frame->fcount;
+ ldr_frame->shot->dm.sensor.timeStamp = fimc_is_get_timestamp();
+
+ /* real automatic increase */
+ if (async_step && (atomic_read(&group->smp_shot_count) > MIN_OF_SYNC_SHOTS))
+ atomic_inc(&group->sensor_fcount);
+ }
+
+ if (test_bit(FIMC_IS_GGROUP_REQUEST_STOP, &groupmgr->group_state[group->id])) {
+ err("cancel by group stop #3");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+#ifdef ENABLE_VDIS
+ if (group->id == GROUP_ID_ISP)
+ fimc_is_group_change(groupmgr, group, ldr_frame);
+
+ /* HACK */
+ if ((group->id == GROUP_ID_DIS) &&
+ test_bit(FIMC_IS_GROUP_ACTIVE, &group->state))
+ down(&group->smp_trigger);
+#endif
+
+ PROGRAM_COUNT(5);
+ device = group->device;
+ resourcemgr = device->resourcemgr;
+ group_next = group->next;
+ group_prev = group->prev;
+ gframemgr = &groupmgr->framemgr[group->instance];
+ if (!gframemgr) {
+ err("gframemgr is NULL(instance %d)", group->instance);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (group_prev && !group_next) {
+ /* tailer */
+ spin_lock_irq(&gframemgr->frame_slock);
+ fimc_is_gframe_group_head(group, &gframe);
+ if (!gframe) {
+ merr("g%dframe is NULL1", group, group->id);
+ warn("GRP%d(res %d, rcnt %d), GRP2(res %d, rcnt %d)",
+ device->group_3aa.id,
+ groupmgr->group_smp_res[device->group_3aa.id].count,
+ atomic_read(&device->group_3aa.rcount),
+ groupmgr->group_smp_res[device->group_isp.id].count,
+ atomic_read(&device->group_isp.rcount));
+ fimc_is_gframe_print_group(group_prev);
+ fimc_is_gframe_print_free(gframemgr);
+ spin_unlock_irq(&gframemgr->frame_slock);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (ldr_frame->fcount != gframe->fcount) {
+ mwarn("grp%d shot mismatch(%d != %d)", group, group->id,
+ ldr_frame->fcount, gframe->fcount);
+ gframe = fimc_is_gframe_rewind(groupmgr, group,
+ ldr_frame->fcount);
+ if (!gframe) {
+ spin_unlock_irq(&gframemgr->frame_slock);
+ merr("rewinding is fail,can't recovery", group);
+ goto p_err;
+ }
+ }
+
+ fimc_is_gframe_s_info(gframe, group->id, ldr_frame);
+ fimc_is_gframe_trans_grp_to_fre(group, gframemgr, gframe);
+ spin_unlock_irq(&gframemgr->frame_slock);
+ } else if (!group_prev && group_next) {
+ /* leader */
+ group->fcount++;
+ spin_lock_irq(&gframemgr->frame_slock);
+ fimc_is_gframe_free_head(gframemgr, &gframe);
+ if (!gframe) {
+ merr("g%dframe is NULL2", group, group->id);
+ warn("GRP%d(res %d, rcnt %d), GRP2(res %d, rcnt %d)",
+ device->group_3aa.id,
+ groupmgr->group_smp_res[device->group_3aa.id].count,
+ atomic_read(&device->group_3aa.rcount),
+ groupmgr->group_smp_res[device->group_isp.id].count,
+ atomic_read(&device->group_isp.rcount));
+ fimc_is_gframe_print_free(gframemgr);
+ fimc_is_gframe_print_group(group_next);
+ spin_unlock_irq(&gframemgr->frame_slock);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state) &&
+ (ldr_frame->fcount != group->fcount)) {
+ if (ldr_frame->fcount > group->fcount) {
+ warn("grp%d shot mismatch(%d != %d)", group->id,
+ ldr_frame->fcount, group->fcount);
+ group->fcount = ldr_frame->fcount;
+ } else {
+ spin_unlock_irq(&gframemgr->frame_slock);
+ err("grp%d shot mismatch(%d, %d)", group->id,
+ ldr_frame->fcount, group->fcount);
+ group->fcount--;
+ ret = -EINVAL;
+ goto p_err;
+ }
+ }
+
+ gframe->fcount = ldr_frame->fcount;
+ fimc_is_gframe_s_info(gframe, group->id, ldr_frame);
+ fimc_is_gframe_trans_fre_to_grp(gframemgr, group_next, gframe);
+ spin_unlock_irq(&gframemgr->frame_slock);
+ } else if (group_prev && group_next) {
+ spin_lock_irq(&gframemgr->frame_slock);
+ fimc_is_gframe_group_head(group, &gframe);
+ if (!gframe) {
+ merr("g%dframe is NULL3", group, group->id);
+ warn("GRP%d(res %d, rcnt %d), GRP2(res %d, rcnt %d)",
+ device->group_3aa.id,
+ groupmgr->group_smp_res[device->group_3aa.id].count,
+ atomic_read(&device->group_3aa.rcount),
+ groupmgr->group_smp_res[device->group_isp.id].count,
+ atomic_read(&device->group_isp.rcount));
+ fimc_is_gframe_print_group(group_prev);
+ fimc_is_gframe_print_group(group_next);
+ spin_unlock_irq(&gframemgr->frame_slock);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (ldr_frame->fcount != gframe->fcount) {
+ mwarn("grp%d shot mismatch(%d != %d)", group, group->id,
+ ldr_frame->fcount, gframe->fcount);
+ gframe = fimc_is_gframe_rewind(groupmgr, group,
+ ldr_frame->fcount);
+ if (!gframe) {
+ spin_unlock_irq(&gframemgr->frame_slock);
+ merr("rewinding is fail,can't recovery", group);
+ goto p_err;
+ }
+ }
+
+ fimc_is_gframe_s_info(gframe, group->id, ldr_frame);
+ fimc_is_gframe_trans_grp_to_grp(group, group_next, gframe);
+ spin_unlock_irq(&gframemgr->frame_slock);
+ } else {
+ /* single */
+ group->fcount++;
+ spin_lock_irq(&gframemgr->frame_slock);
+ fimc_is_gframe_free_head(gframemgr, &gframe);
+ if (!gframe) {
+ merr("g%dframe is NULL4", group, group->id);
+ warn("GRP%d(res %d, rcnt %d), GRP2(res %d, rcnt %d)",
+ device->group_3aa.id,
+ groupmgr->group_smp_res[device->group_3aa.id].count,
+ atomic_read(&device->group_3aa.rcount),
+ groupmgr->group_smp_res[device->group_isp.id].count,
+ atomic_read(&device->group_isp.rcount));
+ fimc_is_gframe_print_free(gframemgr);
+ spin_unlock_irq(&gframemgr->frame_slock);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state) &&
+ (ldr_frame->fcount != group->fcount)) {
+ if (ldr_frame->fcount > group->fcount) {
+ warn("grp%d shot mismatch(%d != %d)", group->id,
+ ldr_frame->fcount, group->fcount);
+ group->fcount = ldr_frame->fcount;
+ } else {
+ spin_unlock_irq(&gframemgr->frame_slock);
+ err("grp%d shot mismatch(%d, %d)", group->id,
+ ldr_frame->fcount, group->fcount);
+ group->fcount--;
+ ret = -EINVAL;
+ goto p_err;
+ }
+ }
+
+ gframe->fcount = ldr_frame->fcount;
+ spin_unlock_irq(&gframemgr->frame_slock);
+ }
+
+#ifdef DEBUG_AA
+ fimc_is_group_debug_aa_shot(group, ldr_frame);
+#endif
+#ifdef CONFIG_USE_VENDER_FEATURE
+ /* Flash Mode Control */
+ fimc_is_group_set_torch(group, ldr_frame);
+#endif
+
+#ifdef ENABLE_DVFS
+ mutex_lock(&resourcemgr->dvfs_ctrl.lock);
+ if ((!pm_qos_request_active(&device->user_qos)) &&
+ (sysfs_debug.en_dvfs)) {
+ /* try to find dynamic scenario to apply */
+ scenario_id = fimc_is_dvfs_sel_scenario(FIMC_IS_DYNAMIC_SN, device, ldr_frame);
+
+ if (scenario_id > 0) {
+ struct fimc_is_dvfs_scenario_ctrl *dynamic_ctrl = resourcemgr->dvfs_ctrl.dynamic_ctrl;
+ info("GRP:%d dynamic scenario(%d)-[%s]\n",
+ group->id, scenario_id,
+ dynamic_ctrl->scenarios[dynamic_ctrl->cur_scenario_idx].scenario_nm);
+ fimc_is_set_dvfs(device, scenario_id);
+ }
+
+ if ((scenario_id < 0) && (resourcemgr->dvfs_ctrl.dynamic_ctrl->cur_frame_tick == 0)) {
+ struct fimc_is_dvfs_scenario_ctrl *static_ctrl = resourcemgr->dvfs_ctrl.static_ctrl;
+ info("GRP:%d restore scenario(%d)-[%s]\n",
+ group->id, static_ctrl->cur_scenario_id,
+ static_ctrl->scenarios[static_ctrl->cur_scenario_idx].scenario_nm);
+ fimc_is_set_dvfs(device, static_ctrl->cur_scenario_id);
+ }
+ }
+ mutex_unlock(&resourcemgr->dvfs_ctrl.lock);
+#endif
+
+ PROGRAM_COUNT(6);
+ ret = group->start_callback(group->device, ldr_frame);
+ if (ret) {
+ merr("start_callback is fail", group);
+ fimc_is_group_cancel(group, ldr_frame);
+ fimc_is_group_done(groupmgr, group, ldr_frame, VB2_BUF_STATE_ERROR);
+ } else {
+ atomic_inc(&group->scount);
+ }
+
+ clear_bit(FIMC_IS_GROUP_SHOT, &group->state);
+ PROGRAM_COUNT(7);
+ return ret;
+
+p_err:
+ if (!test_bit(FIMC_IS_GGROUP_REQUEST_STOP, &groupmgr->group_state[group->id]))
+ fimc_is_group_cancel(group, ldr_frame);
+
+ if (try_sdown) {
+ atomic_inc(&group->smp_shot_count);
+ up(&group->smp_shot);
+ }
+
+ if (try_rdown)
+ up(&groupmgr->group_smp_res[group->id]);
+
+ clear_bit(FIMC_IS_GROUP_SHOT, &group->state);
+ PROGRAM_COUNT(8);
+
+ return ret;
+}
+
+int fimc_is_group_done(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_frame *ldr_frame,
+ u32 done_state)
+{
+ int ret = 0;
+ u32 resources;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(!ldr_frame);
+ BUG_ON(group->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(group->id >= GROUP_ID_MAX);
+ BUG_ON(!group->device);
+
+#ifdef ENABLE_VDIS
+ /* current group notify to next group that shot done is arrvied */
+ /* HACK */
+ if (group->next && (group->id == GROUP_ID_ISP) &&
+ test_bit(FIMC_IS_GROUP_ACTIVE, &group->next->state))
+ up(&group->next->smp_trigger);
+#endif
+
+ /* check shot & resource count validation */
+ resources = group->async_shots + group->sync_shots;
+
+ if (group->smp_shot.count >= resources) {
+ merr("G%d, shot count is invalid(%d >= %d+%d)", group,
+ group->id, group->smp_shot.count, group->async_shots,
+ group->sync_shots);
+ atomic_set(&group->smp_shot_count, resources - 1);
+ sema_init(&group->smp_shot, resources - 1);
+ }
+
+ if (groupmgr->group_smp_res[group->id].count >= resources) {
+ merr("G%d, resource count is invalid(%d >= %d+%d)", group,
+ group->id, groupmgr->group_smp_res[group->id].count,
+ group->async_shots, group->sync_shots);
+ sema_init(&groupmgr->group_smp_res[group->id], resources - 1);
+ }
+
+ device = group->device;
+ if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state) &&
+ (done_state != VB2_BUF_STATE_DONE)) {
+ merr("GRP%d NOT DONE(reprocessing)\n", group, group->id);
+ fimc_is_hw_logdump(device->interface);
+ }
+
+#ifdef DEBUG_AA
+ fimc_is_group_debug_aa_done(group, ldr_frame);
+#endif
+
+ clear_bit(FIMC_IS_GROUP_RUN, &group->state);
+ atomic_inc(&group->smp_shot_count);
+ up(&group->smp_shot);
+ up(&groupmgr->group_smp_res[group->id]);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_GROUP_MGR_H
+#define FIMC_IS_GROUP_MGR_H
+
+#include "fimc-is-config.h"
+#include "fimc-is-time.h"
+#include "fimc-is-subdev-ctrl.h"
+#include "fimc-is-video.h"
+
+/* #define DEBUG_AA */
+/* #define DEBUG_FLASH */
+
+#define TRACE_GROUP
+#define GROUP_ID_3A0 0 /* hardware : CH0 */
+#define GROUP_ID_3A1 1 /* hardware : 3AA */
+#define GROUP_ID_ISP 2 /* hardware : CH1 */
+#define GROUP_ID_DIS 3
+#define GROUP_ID_MAX 4
+#define GROUP_ID_INVALID 5
+#define GROUP_ID_PARM_MASK (0xF)
+#define GROUP_ID_SHIFT (16)
+#define GROUP_ID_MASK (0xFFFF)
+#define GROUP_ID(id) (1 << id)
+
+#define FIMC_IS_MAX_GFRAME 15 /* max shot buffer of F/W */
+#define MIN_OF_ASYNC_SHOTS 1
+#define MIN_OF_SYNC_SHOTS 2
+#define MIN_OF_SHOT_RSC (MIN_OF_ASYNC_SHOTS + MIN_OF_SYNC_SHOTS)
+
+enum fimc_is_group_state {
+ FIMC_IS_GROUP_OPEN,
+ FIMC_IS_GROUP_INIT,
+ FIMC_IS_GROUP_READY,
+ FIMC_IS_GROUP_ACTIVE,
+ FIMC_IS_GROUP_RUN,
+ FIMC_IS_GROUP_SHOT,
+ FIMC_IS_GROUP_REQUEST_FSTOP,
+ FIMC_IS_GROUP_FORCE_STOP,
+ FIMC_IS_GROUP_OTF_INPUT
+};
+
+enum fimc_is_global_group_state {
+ FIMC_IS_GGROUP_INIT,
+ FIMC_IS_GGROUP_START,
+ FIMC_IS_GGROUP_REQUEST_STOP
+};
+
+struct fimc_is_frame;
+struct fimc_is_device_ischain;
+typedef int (*fimc_is_start_callback)(struct fimc_is_device_ischain *device,
+ struct fimc_is_frame *frame);
+
+struct fimc_is_group_frame {
+ struct list_head list;
+ u32 fcount;
+ struct camera2_node_group group_cfg[GROUP_ID_MAX];
+};
+
+struct fimc_is_group_framemgr {
+ struct fimc_is_group_frame frame[FIMC_IS_MAX_GFRAME];
+ spinlock_t frame_slock;
+ struct list_head frame_free_head;
+ u32 frame_free_cnt;
+};
+
+struct fimc_is_group {
+ struct fimc_is_group *next;
+ struct fimc_is_group *prev;
+
+ struct fimc_is_subdev leader;
+ struct fimc_is_subdev *subdev[ENTRY_END];
+ struct kthread_worker *worker;
+
+ /* for otf interface */
+ atomic_t sensor_fcount;
+ atomic_t backup_fcount;
+ struct semaphore smp_trigger;
+ struct semaphore smp_shot;
+ atomic_t smp_shot_count;
+ u32 async_shots;
+ u32 sync_shots;
+ struct camera2_ctl fast_ctl;
+ struct camera2_ctl intent_ctl;
+
+ u32 id; /* group id */
+ u32 instance; /* device instance */
+ u32 source_vid; /* source video id */
+ u32 pcount; /* program count */
+ u32 fcount; /* frame count */
+ atomic_t scount; /* shot count */
+ atomic_t rcount; /* request count */
+ unsigned long state;
+
+ struct list_head frame_group_head;
+ u32 frame_group_cnt;
+
+ fimc_is_start_callback start_callback;
+ struct fimc_is_device_ischain *device;
+
+#ifdef DEBUG_AA
+#ifdef DEBUG_FLASH
+ enum aa_ae_flashmode flashmode;
+ struct camera2_flash_dm flash;
+#endif
+#endif
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ struct fimc_is_time time;
+#endif
+#endif
+ u32 aeflashMode; /* Flash Mode Control */
+};
+
+struct fimc_is_groupmgr {
+ struct fimc_is_group_framemgr framemgr[FIMC_IS_MAX_NODES];
+ struct fimc_is_group *group[FIMC_IS_MAX_NODES][GROUP_ID_MAX];
+ struct kthread_worker group_worker[GROUP_ID_MAX];
+ struct task_struct *group_task[GROUP_ID_MAX];
+ struct semaphore group_smp_res[GROUP_ID_MAX];
+ unsigned long group_state[GROUP_ID_MAX];
+ atomic_t group_refcount[GROUP_ID_MAX];
+};
+
+int fimc_is_groupmgr_probe(struct fimc_is_groupmgr *groupmgr);
+int fimc_is_group_probe(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ u32 entry);
+int fimc_is_group_open(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group, u32 id, u32 instance,
+ struct fimc_is_video_ctx *vctx,
+ struct fimc_is_device_ischain *device,
+ fimc_is_start_callback start_callback);
+int fimc_is_group_close(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group);
+int fimc_is_group_init(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ bool otf_input,
+ u32 video_id);
+int fimc_is_group_process_start(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_queue *queue);
+int fimc_is_group_process_stop(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_queue *queue);
+int fimc_is_group_buffer_queue(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_queue *queue,
+ u32 index);
+int fimc_is_group_buffer_finish(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group, u32 index);
+int fimc_is_group_start(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_frame *frame);
+int fimc_is_group_done(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_frame *ldr_frame,
+ u32 done_state);
+
+int fimc_is_gframe_cancel(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group, u32 target_fcount);
+
+#define PROGRAM_COUNT(count) (group->pcount = count)
+
+#define GET_GROUP_FRAMEMGR(group) \
+ (((group) && (group)->leader.vctx) ? (&(group)->leader.vctx->q_src->framemgr) : NULL)
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/exynos5-mipiphy.h>
+
+#include "fimc-is-config.h"
+#include "fimc-is-type.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-hw.h"
+
+#if (FIMC_IS_CSI_VERSION == CSI_VERSION_0310_0100)
+#define CSI_REG_CTRL (0x00)
+#define CSI_REG_DPHYCTRL (0x04)
+#define CSI_REG_INTMSK (0x10)
+#define CSI_REG_INTSRC (0x14)
+#define CSI_REG_CONFIG0 (0x08)
+#define CSI_REG_CONFIG1 (0x40)
+#define CSI_REG_CONFIG2 (0x50)
+#define CSI_REG_CONFIG3 (0x60)
+#define CSI_REG_RESOL0 (0x2c)
+#define CSI_REG_RESOL1 (0x44)
+#define CSI_REG_RESOL2 (0x54)
+#define CSI_REG_RESOL3 (0x64)
+#define CSI_REG_DPHYCTRL0 (0x20)
+#define CSI_REG_DPHYCTRL1 (0x24)
+#else
+/* CSIS global control */
+#define S5PCSIS_CTRL (0x00)
+#define S5PCSIS_CTRL_DPDN_SWAP_CLOCK_DEFAULT (0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP_CLOCK (1 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP_DATA_DEFAULT (0 << 30)
+#define S5PCSIS_CTRL_DPDN_SWAP_DATA (1 << 30)
+#define S5PCSIS_CTRL_INTERLEAVE_MODE(x) ((x & 0x3) << 22)
+#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW(x) ((1 << (x)) << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8)
+#define S5PCSIS_CTRL_RESET (1 << 4)
+#define S5PCSIS_CTRL_NUMOFDATALANE(x) ((x) << 2)
+#define S5PCSIS_CTRL_ENABLE (1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL (0x04)
+#define S5PCSIS_DPHYCTRL_DPHY_ON(lanes) ((~(0x1f << (lanes + 1))) & 0x1f)
+#if defined(CONFIG_SOC_EXYNOS5260)
+#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27)
+#else
+#define S5PCSIS_DPHYCTRL_HSS_MASK (0xff << 24)
+#define S5PCSIS_DPHYCTRL_CLKSETTLEMASK (0x3 << 22)
+#endif
+
+/* Configuration */
+#define S5PCSIS_CONFIG (0x08)
+#define S5PCSIS_CONFIG_CH1 (0x40)
+#define S5PCSIS_CONFIG_CH2 (0x50)
+#define S5PCSIS_CONFIG_CH3 (0x60)
+#define S5PCSIS_CFG_LINE_INTERVAL(x) (x << 26)
+#define S5PCSIS_CFG_START_INTERVAL(x) (x << 20)
+#define S5PCSIS_CFG_END_INTERVAL(x) (x << 8)
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK (0x3f << 2)
+#define S5PCSIS_CFG_VIRTUAL_CH(x) (x << 0)
+#define S5PCSIS_CFG_NR_LANE_MASK (3)
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK (0x10)
+#if defined(CONFIG_SOC_EXYNOS5260)
+#define S5PCSIS_INTMSK_EN_ALL (0xfc00103f)
+#else
+#define S5PCSIS_INTMSK_EN_ALL (0xf1101117)
+#endif
+#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31)
+#define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30)
+#define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29)
+#define S5PCSIS_INTMSK_ODD_AFTER (1 << 28)
+#define S5PCSIS_INTMSK_FRAME_START_CH3 (1 << 27)
+#define S5PCSIS_INTMSK_FRAME_START_CH2 (1 << 26)
+#define S5PCSIS_INTMSK_FRAME_START_CH1 (1 << 25)
+#define S5PCSIS_INTMSK_FRAME_START_CH0 (1 << 24)
+#define S5PCSIS_INTMSK_FRAME_END_CH3 (1 << 23)
+#define S5PCSIS_INTMSK_FRAME_END_CH2 (1 << 22)
+#define S5PCSIS_INTMSK_FRAME_END_CH1 (1 << 21)
+#define S5PCSIS_INTMSK_FRAME_END_CH0 (1 << 20)
+#define S5PCSIS_INTMSK_ERR_SOT_HS (1 << 16)
+#define S5PCSIS_INTMSK_ERR_LOST_FS_CH3 (1 << 15)
+#define S5PCSIS_INTMSK_ERR_LOST_FS_CH2 (1 << 14)
+#define S5PCSIS_INTMSK_ERR_LOST_FS_CH1 (1 << 13)
+#define S5PCSIS_INTMSK_ERR_LOST_FS_CH0 (1 << 12)
+#define S5PCSIS_INTMSK_ERR_LOST_FE_CH3 (1 << 11)
+#define S5PCSIS_INTMSK_ERR_LOST_FE_CH2 (1 << 10)
+#define S5PCSIS_INTMSK_ERR_LOST_FE_CH1 (1 << 9)
+#define S5PCSIS_INTMSK_ERR_LOST_FE_CH0 (1 << 8)
+#define S5PCSIS_INTMSK_ERR_OVER_CH3 (1 << 7)
+#define S5PCSIS_INTMSK_ERR_OVER_CH2 (1 << 6)
+#define S5PCSIS_INTMSK_ERR_OVER_CH1 (1 << 5)
+#define S5PCSIS_INTMSK_ERR_OVER_CH0 (1 << 4)
+#define S5PCSIS_INTMSK_ERR_ECC (1 << 2)
+#define S5PCSIS_INTMSK_ERR_CRC (1 << 1)
+#define S5PCSIS_INTMSK_ERR_ID (1 << 0)
+
+/* Interrupt source */
+#define S5PCSIS_INTSRC (0x14)
+#define S5PCSIS_INTSRC_EVEN_BEFORE (1 << 31)
+#define S5PCSIS_INTSRC_EVEN_AFTER (1 << 30)
+#define S5PCSIS_INTSRC_EVEN (0x3 << 30)
+#define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29)
+#define S5PCSIS_INTSRC_ODD_AFTER (1 << 28)
+#define S5PCSIS_INTSRC_ODD (0x3 << 28)
+#define S5PCSIS_INTSRC_FRAME_START (0xf << 24)
+#define S5PCSIS_INTSRC_FRAME_END (0xf << 20)
+#define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 16)
+#define S5PCSIS_INTSRC_ERR_LOST_FS (0xf << 12)
+#define S5PCSIS_INTSRC_ERR_LOST_FE (0xf << 8)
+#define S5PCSIS_INTSRC_ERR_OVER (0xf << 4)
+#define S5PCSIS_INTSRC_ERR_ECC (1 << 2)
+#define S5PCSIS_INTSRC_ERR_CRC (1 << 1)
+#define S5PCSIS_INTSRC_ERR_ID (1 << 0)
+#define S5PCSIS_INTSRC_ERRORS (0xf1111117)
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL (0x2c)
+#define CSIS_MAX_PIX_WIDTH (0xffff)
+#define CSIS_MAX_PIX_HEIGHT (0xffff)
+#endif
+
+#if (FIMC_IS_CSI_VERSION == CSI_VERSION_0310_0100)
+
+int csi_hw_reset(unsigned long __iomem *base_reg)
+{
+ int ret = 0;
+ u32 retry = 10;
+ u32 val;
+
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+ writel(val | (1 << 4), base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+
+ while (--retry) {
+ udelay(10);
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+ if (!(val & (1 << 4)))
+ break;
+ }
+
+ if (!retry) {
+ err("reset is fail(%d)", retry);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int csi_hw_s_settle(unsigned long __iomem *base_reg,
+ u32 settle)
+{
+ u32 val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL));
+ val = (val & ~(0xFF << 24)) | (settle << 24);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL));
+
+ return 0;
+}
+
+int csi_hw_s_dphyctrl0(unsigned long __iomem *base_reg,
+ u32 ctrl)
+{
+ u32 val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL0));
+ val = (val & ~(0xFFFFFFFF << 0)) | (ctrl << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL0));
+
+ return 0;
+}
+
+int csi_hw_s_dphyctrl1(unsigned long __iomem *base_reg,
+ u32 ctrl)
+{
+ u32 val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL1));
+ val = (val & ~(0xFFFFFFFF << 0)) | (ctrl << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL1));
+
+ return 0;
+}
+
+int csi_hw_s_control(unsigned long __iomem *base_reg,
+ u32 pixelformat, u32 mode, u32 lanes)
+{
+ int ret = 0;
+ u32 val;
+
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+ val = (val & ~(0x3 << 2)) | (lanes << 2);
+ val = (val & ~(0x3 << 22)) | (mode << 22);
+
+ /* all channel use extclk for wrapper clock source */
+ val |= (0xF << 8);
+
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ case V4L2_PIX_FMT_SBGGR16:
+ case V4L2_PIX_FMT_JPEG:
+ /* output width of CH0 is not 32 bits(normal output) */
+ val &= ~(1 << 20);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_YUYV:
+ /* output width of CH0 is 32 bits(32bit align) */
+ val |= (1 << 20);
+ break;
+ default:
+ err("unsupported format(%X)", pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ break;
+ }
+
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+
+p_err:
+ return ret;
+}
+
+int csi_hw_s_config(unsigned long __iomem *base_reg,
+ u32 vc_src, u32 vc_dst, u32 pixelformat, u32 width, u32 height)
+{
+ int ret = 0;
+ u32 val, format;
+
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ format = HW_FORMAT_RAW8;
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ format = HW_FORMAT_RAW10;
+ break;
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ format = HW_FORMAT_RAW10;
+ /* HACK : format = HW_FORMAT_RAW12; */
+ break;
+ case V4L2_PIX_FMT_SBGGR16:
+ format = HW_FORMAT_RAW10;
+ /* HACK : format = HW_FORMAT_RAW12; */
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_NV21:
+ format = HW_FORMAT_YUV420_8BIT;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ format = HW_FORMAT_YUV422_8BIT;
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ format = HW_FORMAT_USER;
+ break;
+ default:
+ err("unsupported format(%X)", pixelformat);
+ ret = -EINVAL;
+ goto p_err;
+ break;
+ }
+
+ switch (vc_src) {
+ case CSI_VIRTUAL_CH_0:
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG0));
+ val = (val & ~(0x3 << 0)) | (vc_dst << 0);
+ val = (val & ~(0x3f << 2)) | (format << 2);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG0));
+
+ val = (width << 16) | (height << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_RESOL0));
+ break;
+ case CSI_VIRTUAL_CH_1:
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG1));
+ val = (val & ~(0x3 << 0)) | (vc_dst << 0);
+ val = (val & ~(0x3f << 2)) | (format << 2);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG1));
+
+ val = (width << 16) | (height << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_RESOL1));
+ break;
+ case CSI_VIRTUAL_CH_2:
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG2));
+ val = (val & ~(0x3 << 0)) | (vc_dst << 0);
+ val = (val & ~(0x3f << 2)) | (format << 2);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG2));
+
+ val = (width << 16) | (height << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_RESOL2));
+ break;
+ case CSI_VIRTUAL_CH_3:
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG3));
+ val = (val & ~(0x3 << 0)) | (vc_dst << 0);
+ val = (val & ~(0x3f << 2)) | (format << 2);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CONFIG3));
+
+ val = (width << 16) | (height << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_RESOL3));
+ break;
+ default:
+ err("invalid channel(%d)", vc_src);
+ ret = -EINVAL;
+ goto p_err;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+int csi_hw_s_interrupt(unsigned long __iomem *base_reg, bool on)
+{
+ u32 val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_INTMSK));
+ val = on ? (val | 0xFFF1FFF7) : (val & ~0xFFF1FFF7);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_INTMSK));
+
+ return 0;
+}
+
+int csi_hw_g_interrupt(unsigned long __iomem *base_reg)
+{
+ u32 val;
+
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_INTSRC));
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_INTSRC));
+
+ return val;
+}
+
+int csi_hw_enable(unsigned long __iomem *base_reg)
+{
+ u32 val;
+
+ /* update shadow */
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+ val |= (0xF << 16);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+
+ /* DPHY on */
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL));
+ val |= (0x1f << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL));
+
+ /* csi enable */
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+ val |= (0x1 << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+
+ return 0;
+}
+
+int csi_hw_disable(unsigned long __iomem *base_reg)
+{
+ u32 val;
+
+ /* DPHY on */
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL));
+ val &= ~(0x1f << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_DPHYCTRL));
+
+ /* csi enable */
+ val = readl(base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+ val &= ~(0x1 << 0);
+ writel(val, base_reg + TO_WORD_OFFSET(CSI_REG_CTRL));
+
+ return 0;
+}
+
+#else
+
+void s5pcsis_enable_interrupts(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image, bool on)
+{
+ u32 val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_INTMSK));
+
+ val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+ val & ~S5PCSIS_INTMSK_EN_ALL;
+
+ if (image->format.field == V4L2_FIELD_INTERLACED) {
+ if (on) {
+ val |= S5PCSIS_INTMSK_FRAME_START_CH2;
+ val |= S5PCSIS_INTMSK_FRAME_END_CH2;
+ } else {
+ val &= ~S5PCSIS_INTMSK_FRAME_START_CH2;
+ val &= ~S5PCSIS_INTMSK_FRAME_END_CH2;
+ }
+ }
+
+#if defined(CONFIG_SOC_EXYNOS5260)
+ /* FIXME: hard coded, only for rhea */
+ writel(0xFFF01037, base_reg + TO_WORD_OFFSET(S5PCSIS_INTMSK));
+#else
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_INTMSK));
+#endif
+}
+
+void s5pcsis_reset(unsigned long __iomem *base_reg)
+{
+ u32 val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+
+ writel(val | S5PCSIS_CTRL_RESET, base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+ udelay(10);
+}
+
+void s5pcsis_system_enable(unsigned long __iomem *base_reg, int on, u32 lanes)
+{
+ u32 val;
+
+ val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433) || defined(CONFIG_SOC_EXYNOS5422)
+ val |= S5PCSIS_CTRL_WCLK_EXTCLK;
+#endif
+
+ if (on) {
+ val |= S5PCSIS_CTRL_ENABLE;
+ val |= S5PCSIS_CTRL_WCLK_EXTCLK;
+ } else
+ val &= ~S5PCSIS_CTRL_ENABLE;
+#if defined(CONFIG_SOC_EXYNOS5260)
+ /* FIXME: hard coded, only for rhea */
+ writel(0x0000010D, base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+#else
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+#endif
+
+ val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_DPHYCTRL));
+ if (on)
+ val |= S5PCSIS_DPHYCTRL_DPHY_ON(lanes);
+ else
+ val &= ~S5PCSIS_DPHYCTRL_DPHY_ON(lanes);
+#if defined(CONFIG_SOC_EXYNOS5260)
+ /* FIXME: hard coded, only for rhea */
+ writel(0x0E00001F, base_reg + TO_WORD_OFFSET(S5PCSIS_DPHYCTRL));
+#else
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_DPHYCTRL));
+#endif
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image)
+{
+ u32 val;
+
+ BUG_ON(!image);
+
+ /* Color format */
+ val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_CONFIG));
+
+ if (image->format.pixelformat == V4L2_PIX_FMT_SGRBG8)
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | S5PCSIS_CFG_FMT_RAW8;
+ else
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | S5PCSIS_CFG_FMT_RAW10;
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433) || defined(CONFIG_SOC_EXYNOS5422)
+ val |= S5PCSIS_CFG_END_INTERVAL(1);
+#endif
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_CONFIG));
+
+ /* Pixel resolution */
+ val = (image->window.o_width << 16) | image->window.o_height;
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_RESOL));
+
+ /* Output channel2 for DT */
+ if (image->format.field == V4L2_FIELD_INTERLACED) {
+ val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_CONFIG_CH2));
+ val |= S5PCSIS_CFG_VIRTUAL_CH(2);
+ val |= S5PCSIS_CFG_END_INTERVAL(1);
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | S5PCSIS_CFG_FMT_USER(1);
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_CONFIG_CH2));
+ }
+}
+
+void s5pcsis_set_hsync_settle(unsigned long __iomem *base_reg, u32 settle)
+{
+ u32 val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_DPHYCTRL));
+
+ val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 24);
+
+#if defined(CONFIG_SOC_EXYNOS5260)
+ /* FIXME: hard coded, only for rhea */
+ writel(0x0E00001F, base_reg + TO_WORD_OFFSET(S5PCSIS_DPHYCTRL));
+#else
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_DPHYCTRL));
+#endif
+}
+
+void s5pcsis_set_params(unsigned long __iomem *base_reg,
+ struct fimc_is_image *image, u32 lanes)
+{
+ u32 val;
+
+#if defined(CONFIG_SOC_EXYNOS3470)
+ writel(0x000000AC, base_reg + TO_WORD_OFFSET(S5PCSIS_CONFIG)); /* only for carmen */
+#endif
+ __s5pcsis_set_format(base_reg, image);
+
+ val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+ val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+
+ val |= S5PCSIS_CTRL_NUMOFDATALANE(lanes);
+
+ /* Interleaved data */
+ if (image->format.field == V4L2_FIELD_INTERLACED) {
+ pr_info("set DT only\n");
+ val |= S5PCSIS_CTRL_INTERLEAVE_MODE(1); /* DT only */
+ val |= S5PCSIS_CTRL_UPDATE_SHADOW(2); /* ch2 shadow reg */
+ }
+
+ /* Not using external clock. */
+ val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
+
+ writel(val, base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+
+ /* Update the shadow register. */
+ val = readl(base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+ writel(val | S5PCSIS_CTRL_UPDATE_SHADOW(0), base_reg + TO_WORD_OFFSET(S5PCSIS_CTRL));
+}
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/devfreq.h>
+#include <mach/bts.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/exynos5-mipiphy.h>
+
+#include "fimc-is-config.h"
+#include "fimc-is-type.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-core.h"
+#include "fimc-is-dvfs.h"
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+#define PM_QOS_CAM_THROUGHPUT PM_QOS_RESERVED
+#endif
+extern struct pm_qos_request exynos_isp_qos_cpu_min;
+extern struct pm_qos_request exynos_isp_qos_cpu_max;
+extern struct pm_qos_request exynos_isp_qos_int;
+extern struct pm_qos_request exynos_isp_qos_mem;
+extern struct pm_qos_request exynos_isp_qos_cam;
+extern struct pm_qos_request exynos_isp_qos_disp;
+#if defined(CONFIG_SOC_EXYNOS5422) || defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+extern struct pm_qos_request max_cpu_qos;
+#endif
+
+#if defined(CONFIG_ARGOS)
+extern void argos_block_enable(char *req_name, bool set);
+#endif
+
+#if defined(CONFIG_PM_DEVFREQ)
+inline static void fimc_is_set_qos_init(struct fimc_is_core *core, bool on)
+{
+ int cpu_min_qos, cpu_max_qos, int_qos, mif_qos, cam_qos, disp_qos;
+
+ cpu_min_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CPU_MIN, START_DVFS_LEVEL);
+ cpu_max_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CPU_MAX, START_DVFS_LEVEL);
+ int_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_INT, START_DVFS_LEVEL);
+ mif_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_MIF, START_DVFS_LEVEL);
+ cam_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_CAM, START_DVFS_LEVEL);
+ disp_qos = fimc_is_get_qos(core, FIMC_IS_DVFS_DISP, START_DVFS_LEVEL);
+
+ core->resourcemgr.dvfs_ctrl.cur_cpu_min_qos = cpu_min_qos;
+ core->resourcemgr.dvfs_ctrl.cur_cpu_max_qos = cpu_max_qos;
+ core->resourcemgr.dvfs_ctrl.cur_int_qos = int_qos;
+ core->resourcemgr.dvfs_ctrl.cur_mif_qos = mif_qos;
+ core->resourcemgr.dvfs_ctrl.cur_cam_qos = cam_qos;
+ core->resourcemgr.dvfs_ctrl.cur_disp_qos = disp_qos;
+
+ if (on) {
+ /* DEVFREQ lock */
+ if (cpu_min_qos > 0)
+ pm_qos_add_request(&exynos_isp_qos_cpu_min, PM_QOS_CPU_FREQ_MIN, cpu_min_qos);
+ if (cpu_max_qos > 0)
+ pm_qos_add_request(&exynos_isp_qos_cpu_max, PM_QOS_CPU_FREQ_MAX, cpu_max_qos);
+ if (int_qos > 0)
+ pm_qos_add_request(&exynos_isp_qos_int, PM_QOS_DEVICE_THROUGHPUT, int_qos);
+ if (mif_qos > 0)
+ pm_qos_add_request(&exynos_isp_qos_mem, PM_QOS_BUS_THROUGHPUT, mif_qos);
+ if (cam_qos > 0)
+ pm_qos_add_request(&exynos_isp_qos_cam, PM_QOS_CAM_THROUGHPUT, cam_qos);
+ if (disp_qos > 0)
+ pm_qos_add_request(&exynos_isp_qos_disp, PM_QOS_DISPLAY_THROUGHPUT, disp_qos);
+
+ pr_info("[RSC] %s: QoS LOCK [INT(%d), MIF(%d), CAM(%d), DISP(%d) CPU(%d/%d)]\n",
+ __func__, int_qos, mif_qos, cam_qos, disp_qos, cpu_min_qos, cpu_max_qos);
+ } else {
+ /* DEVFREQ unlock */
+ if (cpu_min_qos > 0)
+ pm_qos_remove_request(&exynos_isp_qos_cpu_min);
+ if (cpu_max_qos > 0)
+ pm_qos_remove_request(&exynos_isp_qos_cpu_max);
+ if (int_qos > 0)
+ pm_qos_remove_request(&exynos_isp_qos_int);
+ if (mif_qos > 0)
+ pm_qos_remove_request(&exynos_isp_qos_mem);
+ if (cam_qos > 0)
+ pm_qos_remove_request(&exynos_isp_qos_cam);
+ if (disp_qos > 0)
+ pm_qos_remove_request(&exynos_isp_qos_disp);
+
+ pr_info("[RSC] %s: QoS UNLOCK\n", __func__);
+ }
+}
+#endif
+
+
+#if (FIMC_IS_VERSION == FIMC_IS_VERSION_250)
+int fimc_is_runtime_suspend_post(struct device *dev)
+{
+ int ret = 0;
+ u32 timeout;
+
+ timeout = 1000;
+ while ((readl(PMUREG_ISP0_STATUS) & 0x1) && timeout) {
+ timeout--;
+ usleep_range(1000, 1000);
+ }
+ if (timeout == 0)
+ err("ISP0 power down failed(0x%08x)\n", readl(PMUREG_ISP0_STATUS));
+
+ timeout = 1000;
+ while ((readl(PMUREG_ISP1_STATUS) & 0x1) && timeout) {
+ timeout--;
+ usleep_range(1000, 1000);
+ }
+ if (timeout == 0)
+ err("ISP0 power down failed(0x%08x)\n", readl(PMUREG_ISP1_STATUS));
+
+ return ret;
+}
+
+int fimc_is_runtime_suspend(struct device *dev)
+{
+#ifndef CONFIG_PM_RUNTIME
+ int ret = 0;
+ u32 val;
+#endif
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(pdev);
+
+ BUG_ON(!core);
+ BUG_ON(!core->pdata);
+ BUG_ON(!core->pdata->clk_off);
+
+ info("FIMC_IS runtime suspend in\n");
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (core->mem.alloc_ctx)
+ vb2_ion_detach_iommu(core->mem.alloc_ctx);
+#endif
+
+#if defined(CONFIG_FIMC_IS_BUS_DEVFREQ)
+ exynos5_update_media_layers(TYPE_FIMC_LITE, false);
+#endif
+
+#ifndef CONFIG_PM_RUNTIME
+ /* ISP1 */
+ /* 1. set internal clock reset */
+ val = __raw_readl(PMUREG_CMU_RESET_ISP1_SYS_PWR);
+ val = (val & ~(0x1 << 0)) | (0x0 << 0);
+ __raw_writel(val, PMUREG_CMU_RESET_ISP1_SYS_PWR);
+
+ /* 2. change to OSCCLK */
+ ret = core->pdata->clk_off(pdev);
+ if (ret)
+ warn("clk_off is fail(%d)", ret);
+
+ /* 3. set feedback mode */
+ val = __raw_readl(PMUREG_ISP1_OPTION);
+ val = (val & ~(0x3 << 0)) | (0x2 << 0);
+ __raw_writel(val, PMUREG_ISP1_OPTION);
+
+ /* 4. power off */
+ val = __raw_readl(PMUREG_ISP1_CONFIGURATION);
+ val = (val & ~(0x7 << 0)) | (0x0 << 0);
+ __raw_writel(val, PMUREG_ISP1_CONFIGURATION);
+
+ /* ISP0 */
+ /* 1. set internal clock reset */
+ val = __raw_readl(PMUREG_CMU_RESET_ISP0_SYS_PWR);
+ val = (val & ~(0x1 << 0)) | (0x0 << 0);
+ __raw_writel(val, PMUREG_CMU_RESET_ISP0_SYS_PWR);
+
+ /* 2. set standbywfi a5 */
+ val = __raw_readl(PMUREG_CENTRAL_SEQ_OPTION);
+ val = (val & ~(0x1 << 18)) | (0x1 << 18);
+ __raw_writel(val, PMUREG_CENTRAL_SEQ_OPTION);
+
+ /* 3. stop a5 */
+ __raw_writel(0x00010000, PMUREG_ISP_ARM_OPTION);
+
+ /* 4. reset a5 */
+ val = __raw_readl(PMUREG_ISP_ARM_SYS_PWR_REG);
+ val = (val & ~(0x1 << 0)) | (0x1 << 0);
+ __raw_writel(val, PMUREG_ISP_ARM_SYS_PWR_REG);
+
+ /* 5. change to OSCCLK */
+
+ /* 6. set feedback mode */
+ val = __raw_readl(PMUREG_ISP0_OPTION);
+ val = (val & ~(0x3 << 0)) | (0x2 << 0);
+ __raw_writel(val, PMUREG_ISP0_OPTION);
+
+ /* 7. power off */
+ val = __raw_readl(PMUREG_ISP0_CONFIGURATION);
+ val = (val & ~(0x7 << 0)) | (0x0 << 0);
+ __raw_writel(val, PMUREG_ISP0_CONFIGURATION);
+
+ /* 8. a5 power off */
+ val = __raw_readl(PMUREG_ISP_ARM_CONFIGURATION);
+ val = (val & ~(0x1 << 0)) | (0x0 << 0);
+ __raw_writel(val, PMUREG_ISP_ARM_CONFIGURATION);
+#endif
+
+#if defined(CONFIG_PM_DEVFREQ)
+ /* DEVFREQ release */
+ fimc_is_set_qos_init(core, false);
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+ if (CALL_POPS(core, clk_off, pdev) < 0)
+ warn("clk_off is fail\n");
+#endif
+
+ info("FIMC_IS runtime suspend out\n");
+ pm_relax(dev);
+ return 0;
+}
+
+int fimc_is_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ u32 val;
+
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(pdev);
+
+ BUG_ON(!core);
+ BUG_ON(!core->pdata);
+ BUG_ON(!core->pdata->clk_cfg);
+ BUG_ON(!core->pdata->clk_on);
+
+ info("FIMC_IS runtime resume in\n");
+
+ val = __raw_readl(PMUREG_ISP0_STATUS);
+ if((val & 0x7) != 0x7){
+ err("FIMC_IS runtime resume ISP0 : %d Power down\n",val);
+ BUG();
+ }
+
+ val = __raw_readl(PMUREG_ISP1_STATUS);
+ if((val & 0x7) != 0x7){
+ err("FIMC_IS runtime resume ISP1 : %d Power down\n",val);
+ BUG();
+ }
+
+#ifndef CONFIG_PM_RUNTIME
+ /* ISP0 */
+ /* 1. set feedback mode */
+ val = __raw_readl(PMUREG_ISP0_OPTION);
+ val = (val & ~(0x3<< 0)) | (0x2 << 0);
+ __raw_writel(val, PMUREG_ISP0_OPTION);
+
+ /* 2. power on isp0 */
+ val = __raw_readl(PMUREG_ISP0_CONFIGURATION);
+ val = (val & ~(0x7 << 0)) | (0x7 << 0);
+ __raw_writel(val, PMUREG_ISP0_CONFIGURATION);
+
+ /* ISP1 */
+ /* 3. set feedback mode */
+ val = __raw_readl(PMUREG_ISP1_OPTION);
+ val = (val & ~(0x3<< 0)) | (0x2 << 0);
+ __raw_writel(val, PMUREG_ISP1_OPTION);
+
+ /* 4. power on isp1 */
+ val = __raw_readl(PMUREG_ISP1_CONFIGURATION);
+ val = (val & ~(0x7 << 0)) | (0x7 << 0);
+ __raw_writel(val, PMUREG_ISP1_CONFIGURATION);
+#endif
+
+ ret = core->pdata->clk_cfg(pdev);
+ if (ret) {
+ err("clk_cfg is fail(%d)", ret);
+ goto p_err;
+ }
+
+ /* HACK: DVFS lock sequence is change.
+ * DVFS level should be locked after power on.
+ */
+#if defined(CONFIG_PM_DEVFREQ)
+ /* DEVFREQ set */
+ fimc_is_set_qos_init(core, true);
+#endif
+
+ /* Clock on */
+ ret = core->pdata->clk_on(pdev);
+ if (ret) {
+ err("clk_on is fail(%d)", ret);
+ goto p_err;
+ }
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (core->mem.alloc_ctx)
+ vb2_ion_attach_iommu(core->mem.alloc_ctx);
+#endif
+
+#if defined(CONFIG_FIMC_IS_BUS_DEVFREQ)
+ exynos5_update_media_layers(TYPE_FIMC_LITE, true);
+#endif
+
+ pm_stay_awake(dev);
+
+p_err:
+ info("FIMC-IS runtime resume out\n");
+ return ret;
+}
+
+#else
+int fimc_is_runtime_suspend_post(struct device *dev)
+{
+ int ret = 0;
+ u32 timeout;
+
+ timeout = 2000;
+ while ((readl(PMUREG_ISP_STATUS) & 0x1) && timeout) {
+ timeout--;
+ usleep_range(1000, 1000);
+ }
+ if (timeout == 0)
+ err("ISP power down failed(0x%08x)\n",
+ readl(PMUREG_ISP_STATUS));
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ timeout = 1000;
+ while ((readl(PMUREG_CAM0_STATUS) & 0x1) && timeout) {
+ timeout--;
+ usleep_range(1000, 1000);
+ }
+ if (timeout == 0)
+ err("CAM0 power down failed(0x%08x)\n",
+ readl(PMUREG_CAM0_STATUS));
+
+ timeout = 2000;
+ while ((readl(PMUREG_CAM1_STATUS) & 0x1) && timeout) {
+ timeout--;
+ usleep_range(1000, 1000);
+ }
+ if (timeout == 0)
+ err("CAM1 power down failed(CAM1:0x%08x, A5:0x%08x)\n",
+ readl(PMUREG_CAM1_STATUS), readl(PMUREG_ISP_ARM_STATUS));
+#endif /* defined(CONFIG_SOC_EXYNOS5430) */
+
+#if defined(CONFIG_SOC_EXYNOS5422)
+#endif /* defined(CONFIG_SOC_EXYNOS5422) */
+
+ return ret;
+}
+
+int fimc_is_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_core *core
+ = (struct fimc_is_core *)platform_get_drvdata(pdev);
+
+ BUG_ON(!core);
+ BUG_ON(!core->pdata);
+ BUG_ON(!core->pdata->clk_off);
+
+ pr_info("FIMC_IS runtime suspend in\n");
+
+#if !(defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433))
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (core->mem.alloc_ctx)
+ vb2_ion_detach_iommu(core->mem.alloc_ctx);
+#endif
+#endif
+
+#if defined(CONFIG_PM_DEVFREQ)
+ /* DEVFREQ set */
+ fimc_is_set_qos_init(core, false);
+#endif
+
+#if defined(CONFIG_ARGOS)
+ argos_block_enable("EMMC", false);
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5422) || defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+ /* EGL Release */
+ pm_qos_update_request(&max_cpu_qos, PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE);
+ pm_qos_remove_request(&max_cpu_qos);
+#endif /* CONFIG_SOC_EXYNOS5422 */
+
+#if defined(CONFIG_FIMC_IS_BUS_DEVFREQ)
+ /* BTS */
+#if defined(CONFIG_SOC_EXYNOS5260)
+ bts_initialize("spd-flite-a", false);
+ bts_initialize("spd-flite-b", false);
+#elif defined(CONFIG_SOC_EXYNOS3470)
+ bts_initialize("pd-cam", false);
+#else
+ bts_initialize("pd-fimclite", false);
+#endif
+ /* media layer */
+ exynos5_update_media_layers(TYPE_FIMC_LITE, false);
+#endif /* CONFIG_FIMC_IS_BUS_DEVFREQ */
+
+ if (CALL_POPS(core, clk_off, pdev) < 0)
+ warn("clk_off is fail\n");
+
+ pr_info("FIMC_IS runtime suspend out\n");
+
+ pm_relax(dev);
+ return 0;
+}
+
+int fimc_is_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_core *core
+ = (struct fimc_is_core *)platform_get_drvdata(pdev);
+
+ pm_stay_awake(dev);
+ pr_info("FIMC_IS runtime resume in\n");
+
+#if defined(CONFIG_ARGOS)
+ argos_block_enable("EMMC", true);
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5422) || defined(CONFIG_SOC_EXYNOS5430)
+ /* EGL Lock */
+ pm_qos_add_request(&max_cpu_qos, PM_QOS_CPU_FREQ_MAX, 1600000);
+#elif defined(CONFIG_SOC_EXYNOS5433)
+ /* EGL Lock */
+ pm_qos_add_request(&max_cpu_qos, PM_QOS_CPU_FREQ_MAX, 1700000);
+#endif /* CONFIG_SOC_EXYNOS5422 */
+
+ /* HACK: DVFS lock sequence is change.
+ * DVFS level should be locked after power on.
+ */
+#if defined(CONFIG_PM_DEVFREQ)
+ /* DEVFREQ set */
+ fimc_is_set_qos_init(core, true);
+#endif
+
+ /* Low clock setting */
+ if (CALL_POPS(core, clk_cfg, core->pdev) < 0) {
+ err("clk_cfg is fail\n");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* Clock on */
+ if (CALL_POPS(core, clk_on, core->pdev) < 0) {
+ err("clk_on is fail\n");
+ ret = -EINVAL;
+ goto p_err;
+ }
+#if !(defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433))
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (core->mem.alloc_ctx)
+ vb2_ion_attach_iommu(core->mem.alloc_ctx);
+#endif
+#endif
+
+#if defined(CONFIG_FIMC_IS_BUS_DEVFREQ)
+ /* BTS */
+#if defined(CONFIG_SOC_EXYNOS5260)
+ bts_initialize("spd-flite-a", true);
+ bts_initialize("spd-flite-b", true);
+#elif defined(CONFIG_SOC_EXYNOS3470)
+ bts_initialize("pd-cam", true);
+#else
+ bts_initialize("pd-fimclite", true);
+#endif
+ /* media layer */
+ exynos5_update_media_layers(TYPE_FIMC_LITE, true);
+#endif /* CONFIG_FIMC_IS_BUS_DEVFREQ */
+
+ pr_info("FIMC-IS runtime resume out\n");
+
+ return 0;
+
+p_err:
+ pm_relax(dev);
+ return ret;
+}
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_HW_H
+#define FIMC_IS_HW_H
+
+#define CSI_VIRTUAL_CH_0 0
+#define CSI_VIRTUAL_CH_1 1
+#define CSI_VIRTUAL_CH_2 2
+#define CSI_VIRTUAL_CH_3 3
+#define CSI_VIRTUAL_CH_MAX 4
+
+#define CSI_DATA_LANES_1 0
+#define CSI_DATA_LANES_2 1
+#define CSI_DATA_LANES_3 2
+#define CSI_DATA_LANES_4 3
+
+#define CSI_MODE_CH0_ONLY 0
+#define CSI_MODE_DT_ONLY 1
+#define CSI_MODE_VC_ONLY 2
+#define CSI_MODE_VC_DT 3
+
+#define HW_FORMAT_YUV420_8BIT 0x18
+#define HW_FORMAT_YUV420_10BIT 0x19
+#define HW_FORMAT_YUV422_8BIT 0x1E
+#define HW_FORMAT_YUV422_10BIT 0x1F
+#define HW_FORMAT_RGB565 0x22
+#define HW_FORMAT_RGB666 0x23
+#define HW_FORMAT_RGB888 0x24
+#define HW_FORMAT_RAW6 0x28
+#define HW_FORMAT_RAW7 0x29
+#define HW_FORMAT_RAW8 0x2A
+#define HW_FORMAT_RAW10 0x2B
+#define HW_FORMAT_RAW12 0x2C
+#define HW_FORMAT_RAW14 0x2D
+#define HW_FORMAT_USER 0x30
+
+struct fimc_is_vci {
+ u32 pixelformat;
+ u32 vc_map[CSI_VIRTUAL_CH_MAX];
+};
+
+int csi_hw_reset(unsigned long __iomem *base_reg);
+int csi_hw_s_settle(unsigned long __iomem *base_reg, u32 settle);
+int csi_hw_s_control(unsigned long __iomem *base_reg, u32 pixelformat, u32 mode, u32 lanes);
+int csi_hw_s_config(unsigned long __iomem *base_reg, u32 vc_src, u32 vc_dst, u32 pixelformat, u32 width, u32 height);
+int csi_hw_s_interrupt(unsigned long __iomem *base_reg, bool on);
+int csi_hw_g_interrupt(unsigned long __iomem *base_reg);
+int csi_hw_enable(unsigned long __iomem *base_reg);
+int csi_hw_disable(unsigned long __iomem *base_reg);
+
+int fimc_is_runtime_suspend_post(struct device *dev);
+int fimc_is_runtime_suspend(struct device *dev);
+int fimc_is_runtime_resume(struct device *dev);
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * The header file related to camera
+ *
+ * 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/workqueue.h>
+#include <linux/bug.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-groupmgr.h"
+
+#include "fimc-is-interface.h"
+#include "fimc-is-clk-gate.h"
+
+u32 __iomem *notify_fcount_sen0;
+u32 __iomem *notify_fcount_sen1;
+u32 __iomem *notify_fcount_sen2;
+u32 __iomem *last_fcount0;
+u32 __iomem *last_fcount1;
+
+#define init_request_barrier(itf) mutex_init(&itf->request_barrier)
+#define enter_request_barrier(itf) mutex_lock(&itf->request_barrier);
+#define exit_request_barrier(itf) mutex_unlock(&itf->request_barrier);
+#define init_process_barrier(itf) spin_lock_init(&itf->process_barrier);
+#define enter_process_barrier(itf) spin_lock_irq(&itf->process_barrier);
+#define exit_process_barrier(itf) spin_unlock_irq(&itf->process_barrier);
+
+extern struct fimc_is_sysfs_debug sysfs_debug;
+
+/* func to register error report callback */
+int fimc_is_set_err_report_vendor(struct fimc_is_interface *itf,
+ void *err_report_data,
+ int (*err_report_vendor)(void *data, u32 err_report_type))
+{
+ if (itf) {
+ itf->err_report_data = err_report_data;
+ itf->err_report_vendor = err_report_vendor;
+ }
+
+ return 0;
+}
+
+/* main func to handle error report */
+static int fimc_is_err_report_handler(struct fimc_is_interface *itf, struct fimc_is_msg *msg)
+{
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_core *core;
+ unsigned long dtp_wait_time;
+
+ core = itf->core;
+ device = &core->ischain[msg->instance];
+ dtp_wait_time = device->sensor->dtp_timer.expires;
+
+ err("IHC_REPORT_ERR(%d,%d,%d,%d,%d) is occured",
+ msg->instance,
+ msg->group,
+ msg->parameter1,
+ msg->parameter2,
+ msg->parameter3);
+
+ /*
+ * if vendor error report func was registered,
+ * call the func.
+ */
+ if (itf->err_report_vendor)
+ itf->err_report_vendor(itf->err_report_data, msg->parameter2);
+
+ switch (msg->parameter2) {
+ case REPORT_ERR_CIS_ID:
+ warn("Occured the ERR_ID");
+ break;
+ case REPORT_ERR_CIS_ECC:
+ warn("Occured the ERR_ECC");
+ case REPORT_ERR_CIS_CRC:
+ warn("Occured the ERR_CRC");
+#ifdef ENABLE_DTP
+ if (dtp_wait_time >= jiffies)
+ set_bit(FIMC_IS_BAD_FRAME_STOP, &device->sensor->force_stop);
+#endif
+ break;
+ case REPORT_ERR_CIS_OVERFLOW_VC0:
+ warn("Occured the OVERFLOW_VC0");
+ break;
+ case REPORT_ERR_CIS_LOST_FE_VC0:
+ warn("Occured the LOST_FE_VC0");
+ break;
+ case REPORT_ERR_CIS_LOST_FS_VC0:
+ warn("Occured the LOST_FS_VC0");
+ break;
+ case REPORT_ERR_CIS_SOT_VC0:
+ warn("Occured the SOT_VC0");
+ break;
+ case REPORT_ERR_CIS_SOT_VC1:
+ warn("Occured the SOT_VC1");
+ break;
+ case REPORT_ERR_CIS_SOT_VC2:
+ warn("Occured the SOT_VC2");
+ break;
+ case REPORT_ERR_CIS_SOT_VC3:
+ warn("Occured the SOT_VC3");
+ break;
+ case REPORT_ERR_3AA_OVERFLOW:
+ warn("Occured the 3AA_OVERFLOW");
+ break;
+ case REPORT_ERR_FLITE_D_OVERFLOW:
+ warn("Occured the FLITE_D_OVERFLOW");
+ break;
+ case REPORT_ERR_COMPANION_LOST_FRAME:
+ warn("Occured the COMPANION_LOST_FRAME");
+ break;
+ case REPORT_ERR_3A_ALGORITHM_DELAYED:
+ warn("Occured the 3A_ALGORITHM_DELAYED");
+ break;
+
+ default:
+ warn("parameter is default");
+ break;
+ }
+
+ return 0;
+}
+
+int print_fre_work_list(struct fimc_is_work_list *this)
+{
+ struct list_head *temp;
+ struct fimc_is_work *work;
+
+ if (!(this->id & TRACE_WORK_ID_MASK))
+ return 0;
+
+ printk(KERN_ERR "[INF] fre(%02X, %02d) :",
+ this->id, this->work_free_cnt);
+
+ list_for_each(temp, &this->work_free_head) {
+ work = list_entry(temp, struct fimc_is_work, list);
+ printk(KERN_CONT "%X(%d)->", work->msg.command, work->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+
+ return 0;
+}
+
+static int set_free_work(struct fimc_is_work_list *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_free, flags);
+
+ list_add_tail(&work->list, &this->work_free_head);
+ this->work_free_cnt++;
+#ifdef TRACE_WORK
+ print_fre_work_list(this);
+#endif
+
+ spin_unlock_irqrestore(&this->slock_free, flags);
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static int get_free_work(struct fimc_is_work_list *this,
+ struct fimc_is_work **work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_free, flags);
+
+ if (this->work_free_cnt) {
+ *work = container_of(this->work_free_head.next,
+ struct fimc_is_work, list);
+ list_del(&(*work)->list);
+ this->work_free_cnt--;
+ } else
+ *work = NULL;
+
+ spin_unlock_irqrestore(&this->slock_free, flags);
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr");
+ }
+
+ return ret;
+}
+
+static int get_free_work_irq(struct fimc_is_work_list *this,
+ struct fimc_is_work **work)
+{
+ int ret = 0;
+
+ if (work) {
+ spin_lock(&this->slock_free);
+
+ if (this->work_free_cnt) {
+ *work = container_of(this->work_free_head.next,
+ struct fimc_is_work, list);
+ list_del(&(*work)->list);
+ this->work_free_cnt--;
+ } else
+ *work = NULL;
+
+ spin_unlock(&this->slock_free);
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr");
+ }
+
+ return ret;
+}
+
+int print_req_work_list(struct fimc_is_work_list *this)
+{
+ struct list_head *temp;
+ struct fimc_is_work *work;
+
+ if (!(this->id & TRACE_WORK_ID_MASK))
+ return 0;
+
+ printk(KERN_ERR "[INF] req(%02X, %02d) :",
+ this->id, this->work_request_cnt);
+
+ list_for_each(temp, &this->work_request_head) {
+ work = list_entry(temp, struct fimc_is_work, list);
+ printk(KERN_CONT "%X(%d)->", work->msg.command, work->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+
+ return 0;
+}
+
+static int print_work_data_state(struct fimc_is_interface *this)
+{
+ struct work_struct *work;
+ unsigned long *bits = NULL;
+
+ work = &this->work_wq[INTR_GENERAL];
+ bits = (work_data_bits(work));
+ info("INTR_GENERAL wq state : (0x%lx)", *bits);
+ work = &this->work_wq[INTR_3A0C_FDONE];
+ bits = (work_data_bits(work));
+ info("INTR_3A0C_FDONE wq state : (0x%lx)", *bits);
+ work = &this->work_wq[INTR_3A1C_FDONE];
+ bits = (work_data_bits(work));
+ info("INTR_3A1C_FDONE wq state : (0x%lx)", *bits);
+ work = &this->work_wq[INTR_SCC_FDONE];
+ bits = (work_data_bits(work));
+ info("INTR_SCC_FDONE wq state : (0x%lx)", *bits);
+ work = &this->work_wq[INTR_DIS_FDONE];
+ bits = (work_data_bits(work));
+ info("INTR_DIS_FDONE wq state : (0x%lx)", *bits);
+ work = &this->work_wq[INTR_SCP_FDONE];
+ bits = (work_data_bits(work));
+ info("INTR_SCP_FDONE wq state : (0x%lx)", *bits);
+ work = &this->work_wq[INTR_SHOT_DONE];
+ bits = (work_data_bits(work));
+ info("INTR_SHOT_DONE wq state : (0x%lx)", *bits);
+
+ return 0;
+}
+
+static int set_req_work(struct fimc_is_work_list *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_request, flags);
+
+ list_add_tail(&work->list, &this->work_request_head);
+ this->work_request_cnt++;
+#ifdef TRACE_WORK
+ print_req_work_list(this);
+#endif
+
+ spin_unlock_irqrestore(&this->slock_request, flags);
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static int set_req_work_irq(struct fimc_is_work_list *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+
+ if (work) {
+ spin_lock(&this->slock_request);
+
+ list_add_tail(&work->list, &this->work_request_head);
+ this->work_request_cnt++;
+#ifdef TRACE_WORK
+ print_req_work_list(this);
+#endif
+
+ spin_unlock(&this->slock_request);
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static int get_req_work(struct fimc_is_work_list *this,
+ struct fimc_is_work **work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_request, flags);
+
+ if (this->work_request_cnt) {
+ *work = container_of(this->work_request_head.next,
+ struct fimc_is_work, list);
+ list_del(&(*work)->list);
+ this->work_request_cnt--;
+ } else
+ *work = NULL;
+
+ spin_unlock_irqrestore(&this->slock_request, flags);
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static void init_work_list(struct fimc_is_work_list *this, u32 id, u32 count)
+{
+ u32 i;
+
+ this->id = id;
+ this->work_free_cnt = 0;
+ this->work_request_cnt = 0;
+ INIT_LIST_HEAD(&this->work_free_head);
+ INIT_LIST_HEAD(&this->work_request_head);
+ spin_lock_init(&this->slock_free);
+ spin_lock_init(&this->slock_request);
+ for (i = 0; i < count; ++i)
+ set_free_work(this, &this->work[i]);
+
+ init_waitqueue_head(&this->wait_queue);
+}
+
+static int set_busystate(struct fimc_is_interface *this,
+ u32 command)
+{
+ int ret;
+
+ ret = test_and_set_bit(IS_IF_STATE_BUSY, &this->state);
+ if (ret)
+ warn("%d command : busy state is already set", command);
+
+ return ret;
+}
+
+static int clr_busystate(struct fimc_is_interface *this,
+ u32 command)
+{
+ int ret;
+
+ ret = test_and_clear_bit(IS_IF_STATE_BUSY, &this->state);
+ if (!ret)
+ warn("%d command : busy state is already clr", command);
+
+ return !ret;
+}
+
+static int test_busystate(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ ret = test_bit(IS_IF_STATE_BUSY, &this->state);
+
+ return ret;
+}
+
+static int wait_lockstate(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(this->lock_wait_queue,
+ !atomic_read(&this->lock_pid), FIMC_IS_COMMAND_TIMEOUT);
+ if (ret) {
+ ret = 0;
+ } else {
+ err("timeout");
+ ret = -ETIME;
+ }
+
+ return ret;
+}
+
+static int wait_idlestate(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(this->idle_wait_queue,
+ !test_busystate(this), FIMC_IS_COMMAND_TIMEOUT);
+ if (ret) {
+ ret = 0;
+ } else {
+ err("timeout");
+ ret = -ETIME;
+ }
+
+ return ret;
+}
+
+static int wait_initstate(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(this->init_wait_queue,
+ test_bit(IS_IF_STATE_START, &this->state),
+ FIMC_IS_STARTUP_TIMEOUT);
+ if (ret) {
+ ret = 0;
+ } else {
+ err("timeout");
+ ret = -ETIME;
+ }
+
+ return ret;
+}
+
+static void testnclr_wakeup(struct fimc_is_interface *this,
+ u32 command)
+{
+ int ret = 0;
+
+ ret = clr_busystate(this, command);
+ if (ret)
+ err("current state is invalid(%ld)", this->state);
+
+ wake_up(&this->idle_wait_queue);
+}
+
+static int waiting_is_ready(struct fimc_is_interface *interface)
+{
+ int ret = 0;
+ u32 try_count = TRY_RECV_AWARE_COUNT;
+ u32 cfg = readl(interface->regs + INTMSR0);
+ u32 status = INTMSR0_GET_INTMSD0(cfg);
+
+ while (status) {
+ cfg = readl(interface->regs + INTMSR0);
+ status = INTMSR0_GET_INTMSD0(cfg);
+ udelay(100);
+ dbg("Retry to read INTMSR0(%d)\n", try_count);
+
+ if (--try_count == 0) {
+ err("INTMSR0's 0 bit is not cleared.");
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void send_interrupt(struct fimc_is_interface *interface)
+{
+ writel(INTGR0_INTGD0, interface->regs + INTGR0);
+}
+
+static int fimc_is_set_cmd(struct fimc_is_interface *itf,
+ struct fimc_is_msg *msg,
+ struct fimc_is_msg *reply)
+{
+ int ret = 0;
+ int wait_lock = 0;
+ u32 lock_pid = 0;
+ u32 id;
+ volatile struct is_common_reg __iomem *com_regs;
+#ifdef MEASURE_TIME
+#ifdef INTERFACE_TIME
+ struct timeval measure_str, measure_end;
+#endif
+#endif
+
+ BUG_ON(!itf);
+ BUG_ON(!msg);
+ BUG_ON(msg->instance >= FIMC_IS_MAX_NODES);
+ BUG_ON(msg->command >= HIC_COMMAND_END);
+ BUG_ON(!reply);
+
+ if (!test_bit(IS_IF_STATE_OPEN, &itf->state)) {
+ warn("interface close, %d cmd is cancel", msg->command);
+ goto exit;
+ }
+
+ lock_pid = atomic_read(&itf->lock_pid);
+ if (lock_pid && (lock_pid != current->pid)) {
+ pr_info("itf LOCK, %d(%d) wait\n", current->pid, msg->command);
+ wait_lock = wait_lockstate(itf);
+ pr_info("itf UNLOCK, %d(%d) go\n", current->pid, msg->command);
+ if (wait_lock) {
+ err("wait_lockstate is fail, lock reset");
+ atomic_set(&itf->lock_pid, 0);
+ }
+ }
+
+ dbg_interface("TP#1\n");
+ enter_request_barrier(itf);
+ dbg_interface("TP#2\n");
+
+#ifdef MEASURE_TIME
+#ifdef INTERFACE_TIME
+ do_gettimeofday(&measure_str);
+#endif
+#endif
+
+ switch (msg->command) {
+ case HIC_STREAM_ON:
+ if (itf->streaming[msg->instance] == IS_IF_STREAMING_ON)
+ warn("already stream on");
+ break;
+ case HIC_STREAM_OFF:
+ if (itf->streaming[msg->instance] == IS_IF_STREAMING_OFF)
+ warn("already stream off");
+ break;
+ case HIC_PROCESS_START:
+ if (itf->processing[msg->instance] == IS_IF_PROCESSING_ON)
+ warn("already process on");
+ break;
+ case HIC_PROCESS_STOP:
+ if (itf->processing[msg->instance] == IS_IF_PROCESSING_OFF)
+ warn("already process off");
+ break;
+ case HIC_POWER_DOWN:
+ if (itf->pdown_ready == IS_IF_POWER_DOWN_READY)
+ warn("already powerdown ready");
+ break;
+ default:
+ if (itf->pdown_ready == IS_IF_POWER_DOWN_READY) {
+ exit_request_barrier(itf);
+ warn("already powerdown ready, %d cmd is cancel",
+ msg->command);
+ goto exit;
+ }
+ break;
+ }
+
+ enter_process_barrier(itf);
+
+ ret = waiting_is_ready(itf);
+ if (ret) {
+ exit_request_barrier(itf);
+ exit_process_barrier(itf);
+ err("waiting for ready is fail");
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ set_busystate(itf, msg->command);
+ com_regs = itf->com_regs;
+ id = (msg->group << GROUP_ID_SHIFT) | msg->instance;
+ writel(msg->command, &com_regs->hicmd);
+ writel(id, &com_regs->hic_sensorid);
+ writel(msg->parameter1, &com_regs->hic_param1);
+ writel(msg->parameter2, &com_regs->hic_param2);
+ writel(msg->parameter3, &com_regs->hic_param3);
+ writel(msg->parameter4, &com_regs->hic_param4);
+ send_interrupt(itf);
+
+ exit_process_barrier(itf);
+
+ ret = wait_idlestate(itf);
+ if (ret) {
+ exit_request_barrier(itf);
+ err("%d command is timeout", msg->command);
+ fimc_is_hw_regdump(itf);
+ print_req_work_list(&itf->work_list[INTR_GENERAL]);
+ print_work_data_state(itf);
+ clr_busystate(itf, msg->command);
+ ret = -ETIME;
+ goto exit;
+ }
+
+ reply->command = itf->reply.command;
+ reply->group = itf->reply.group;
+ reply->instance = itf->reply.instance;
+ reply->parameter1 = itf->reply.parameter1;
+ reply->parameter2 = itf->reply.parameter2;
+ reply->parameter3 = itf->reply.parameter3;
+ reply->parameter4 = itf->reply.parameter4;
+
+ if (reply->command == ISR_DONE) {
+ if (msg->command != reply->parameter1) {
+ exit_request_barrier(itf);
+ err("invalid command reply(%d != %d)", msg->command, reply->parameter1);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (msg->command) {
+ case HIC_STREAM_ON:
+ itf->streaming[msg->instance] = IS_IF_STREAMING_ON;
+ break;
+ case HIC_STREAM_OFF:
+ itf->streaming[msg->instance] = IS_IF_STREAMING_OFF;
+ break;
+ case HIC_PROCESS_START:
+ itf->processing[msg->instance] = IS_IF_PROCESSING_ON;
+ break;
+ case HIC_PROCESS_STOP:
+ itf->processing[msg->instance] = IS_IF_PROCESSING_OFF;
+ break;
+ case HIC_POWER_DOWN:
+ itf->pdown_ready = IS_IF_POWER_DOWN_READY;
+ break;
+ case HIC_OPEN_SENSOR:
+ if (reply->parameter1 == HIC_POWER_DOWN) {
+ err("firmware power down");
+ itf->pdown_ready = IS_IF_POWER_DOWN_READY;
+ ret = -ECANCELED;
+ } else {
+ itf->pdown_ready = IS_IF_POWER_DOWN_NREADY;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ err("ISR_NDONE is occured");
+ ret = -EINVAL;
+ }
+
+#ifdef MEASURE_TIME
+#ifdef INTERFACE_TIME
+ do_gettimeofday(&measure_end);
+ measure_time(&itf->time[msg->command],
+ msg->instance,
+ msg->group,
+ &measure_str,
+ &measure_end);
+#endif
+#endif
+
+ exit_request_barrier(itf);
+
+exit:
+ if (ret)
+ fimc_is_hw_logdump(itf);
+
+ return ret;
+}
+
+static int fimc_is_set_cmd_shot(struct fimc_is_interface *this,
+ struct fimc_is_msg *msg)
+{
+ int ret = 0;
+ u32 id;
+ volatile struct is_common_reg __iomem *com_regs;
+
+ BUG_ON(!this);
+ BUG_ON(!msg);
+ BUG_ON(msg->instance >= FIMC_IS_MAX_NODES);
+
+ if (!test_bit(IS_IF_STATE_OPEN, &this->state)) {
+ warn("interface close, %d cmd is cancel", msg->command);
+ goto exit;
+ }
+
+ enter_process_barrier(this);
+
+ ret = waiting_is_ready(this);
+ if (ret) {
+ exit_process_barrier(this);
+ err("waiting for ready is fail");
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ spin_lock_irq(&this->shot_check_lock);
+ atomic_set(&this->shot_check[msg->instance], 1);
+ spin_unlock_irq(&this->shot_check_lock);
+
+ com_regs = this->com_regs;
+ id = (msg->group << GROUP_ID_SHIFT) | msg->instance;
+ writel(msg->command, &com_regs->hicmd);
+ writel(id, &com_regs->hic_sensorid);
+ writel(msg->parameter1, &com_regs->hic_param1);
+ writel(msg->parameter2, &com_regs->hic_param2);
+ writel(msg->parameter3, &com_regs->hic_param3);
+ writel(msg->parameter4, &com_regs->hic_param4);
+ send_interrupt(this);
+
+ exit_process_barrier(this);
+
+exit:
+ return ret;
+}
+
+static int fimc_is_set_cmd_nblk(struct fimc_is_interface *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+ u32 id;
+ struct fimc_is_msg *msg;
+ volatile struct is_common_reg __iomem *com_regs;
+
+ msg = &work->msg;
+ switch (msg->command) {
+ case HIC_SET_CAM_CONTROL:
+ set_req_work(&this->nblk_cam_ctrl, work);
+ break;
+ case HIC_MSG_TEST:
+ break;
+ default:
+ err("unresolved command\n");
+ break;
+ }
+
+ enter_process_barrier(this);
+
+ ret = waiting_is_ready(this);
+ if (ret) {
+ err("waiting for ready is fail");
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ com_regs = this->com_regs;
+ id = (msg->group << GROUP_ID_SHIFT) | msg->instance;
+ writel(msg->command, &com_regs->hicmd);
+ writel(id, &com_regs->hic_sensorid);
+ writel(msg->parameter1, &com_regs->hic_param1);
+ writel(msg->parameter2, &com_regs->hic_param2);
+ writel(msg->parameter3, &com_regs->hic_param3);
+ writel(msg->parameter4, &com_regs->hic_param4);
+ send_interrupt(this);
+
+exit:
+ exit_process_barrier(this);
+ return ret;
+}
+
+static inline void fimc_is_get_cmd(struct fimc_is_interface *itf,
+ struct fimc_is_msg *msg, u32 index)
+{
+ volatile struct is_common_reg __iomem *com_regs = itf->com_regs;
+
+ switch (index) {
+ case INTR_GENERAL:
+ msg->id = 0;
+ msg->command = readl(&com_regs->ihcmd);
+ msg->instance = readl(&com_regs->ihc_sensorid);
+ msg->parameter1 = readl(&com_regs->ihc_param1);
+ msg->parameter2 = readl(&com_regs->ihc_param2);
+ msg->parameter3 = readl(&com_regs->ihc_param3);
+ msg->parameter4 = readl(&com_regs->ihc_param4);
+ break;
+ case INTR_3A0C_FDONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = readl(&com_regs->taa0c_sensor_id);
+ msg->parameter1 = readl(&com_regs->taa0c_param1);
+ msg->parameter2 = readl(&com_regs->taa0c_param2);
+ msg->parameter3 = readl(&com_regs->taa0c_param3);
+ msg->parameter4 = 0;
+ break;
+ case INTR_3A1C_FDONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = readl(&com_regs->taa1c_sensor_id);
+ msg->parameter1 = readl(&com_regs->taa1c_param1);
+ msg->parameter2 = readl(&com_regs->taa1c_param2);
+ msg->parameter3 = readl(&com_regs->taa1c_param3);
+ msg->parameter4 = 0;
+ break;
+ case INTR_SCC_FDONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = readl(&com_regs->scc_sensor_id);
+ msg->parameter1 = readl(&com_regs->scc_param1);
+ msg->parameter2 = readl(&com_regs->scc_param2);
+ msg->parameter3 = readl(&com_regs->scc_param3);
+ msg->parameter4 = 0;
+ break;
+ case INTR_DIS_FDONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = readl(&com_regs->dis_sensor_id);
+ msg->parameter1 = readl(&com_regs->dis_param1);
+ msg->parameter2 = readl(&com_regs->dis_param2);
+ msg->parameter3 = readl(&com_regs->dis_param3);
+ msg->parameter4 = 0;
+ break;
+ case INTR_SCP_FDONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = readl(&com_regs->scp_sensor_id);
+ msg->parameter1 = readl(&com_regs->scp_param1);
+ msg->parameter2 = readl(&com_regs->scp_param2);
+ msg->parameter3 = readl(&com_regs->scp_param3);
+ msg->parameter4 = 0;
+ break;
+ case INTR_SHOT_DONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = readl(&com_regs->shot_sensor_id);
+ msg->parameter1 = readl(&com_regs->shot_param1);
+ msg->parameter2 = readl(&com_regs->shot_param2);
+ msg->parameter3 = readl(&com_regs->shot_param3);
+ msg->parameter4 = 0;
+ break;
+ default:
+ msg->id = 0;
+ msg->command = 0;
+ msg->instance = 0;
+ msg->parameter1 = 0;
+ msg->parameter2 = 0;
+ msg->parameter3 = 0;
+ msg->parameter4 = 0;
+ err("unknown command getting\n");
+ break;
+ }
+
+ msg->group = msg->instance >> GROUP_ID_SHIFT;
+ msg->instance = msg->instance & GROUP_ID_MASK;
+}
+
+static inline u32 fimc_is_get_intr(struct fimc_is_interface *itf)
+{
+ u32 status = 0;
+ volatile struct is_common_reg __iomem *com_regs = itf->com_regs;
+
+ if (itf->need_iflag) {
+ status = readl(&com_regs->ihcmd_iflag) |
+ readl(&com_regs->taa0c_iflag) |
+ readl(&com_regs->taa1c_iflag) |
+ readl(&com_regs->scc_iflag) |
+ readl(&com_regs->dis_iflag) |
+ readl(&com_regs->scp_iflag) |
+ readl(&com_regs->shot_iflag);
+ }
+
+ status |= readl(itf->regs + INTMSR1);
+
+ return status;
+}
+
+static inline void fimc_is_clr_intr(struct fimc_is_interface *itf,
+ u32 index)
+{
+ volatile struct is_common_reg __iomem *com_regs = itf->com_regs;
+
+ writel((1 << index), itf->regs + INTCR1);
+
+ if (itf->need_iflag) {
+ switch (index) {
+ case INTR_GENERAL:
+ writel(0, &com_regs->ihcmd_iflag);
+ break;
+ case INTR_3A0C_FDONE:
+ writel(0, &com_regs->taa0c_iflag);
+ break;
+ case INTR_3A1C_FDONE:
+ writel(0, &com_regs->taa1c_iflag);
+ break;
+ case INTR_SCC_FDONE:
+ writel(0, &com_regs->scc_iflag);
+ break;
+ case INTR_DIS_FDONE:
+ writel(0, &com_regs->dis_iflag);
+ break;
+ case INTR_SCP_FDONE:
+ writel(0, &com_regs->scp_iflag);
+ break;
+ case INTR_SHOT_DONE:
+ writel(0, &com_regs->shot_iflag);
+ break;
+ default:
+ err("unknown command clear\n");
+ break;
+ }
+ }
+}
+
+static void wq_func_general(struct work_struct *data)
+{
+ struct fimc_is_interface *itf;
+ struct fimc_is_msg *msg;
+ struct fimc_is_work *work;
+ struct fimc_is_work *nblk_work;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_wq[INTR_GENERAL]);
+
+ get_req_work(&itf->work_list[INTR_GENERAL], &work);
+ while (work) {
+ msg = &work->msg;
+ switch (msg->command) {
+ case IHC_GET_SENSOR_NUMBER:
+ info("IS Version: %d.%d [0x%02x]\n",
+ ISDRV_VERSION, msg->parameter1,
+ get_drv_clock_gate() |
+ get_drv_dvfs());
+ set_bit(IS_IF_STATE_START, &itf->state);
+ itf->pdown_ready = IS_IF_POWER_DOWN_NREADY;
+ wake_up(&itf->init_wait_queue);
+ break;
+ case ISR_DONE:
+ switch (msg->parameter1) {
+ case HIC_OPEN_SENSOR:
+ dbg_interface("open done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_CLOSE_SENSOR:
+ dbg_interface("close done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_GET_SET_FILE_ADDR:
+ dbg_interface("saddr(%p) done\n",
+ (void *)msg->parameter2);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_LOAD_SET_FILE:
+ dbg_interface("setfile done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_SET_A5_MAP:
+ dbg_interface("mapping done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_SET_A5_UNMAP:
+ dbg_interface("unmapping done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_PROCESS_START:
+ dbg_interface("process_on done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_PROCESS_STOP:
+ dbg_interface("process_off done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_STREAM_ON:
+ dbg_interface("stream_on done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_STREAM_OFF:
+ dbg_interface("stream_off done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_SET_PARAMETER:
+ dbg_interface("s_param done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_GET_STATIC_METADATA:
+ dbg_interface("g_capability done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_PREVIEW_STILL:
+ dbg_interface("a_param(%dx%d) done\n",
+ msg->parameter2,
+ msg->parameter3);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_POWER_DOWN:
+ dbg_interface("powerdown done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ case HIC_I2C_CONTROL_LOCK:
+ dbg_interface("i2c lock done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+#if (FW_HAS_SYS_CTRL_CMD)
+ case HIC_SYSTEM_CONTROL:
+ dbg_interface("system control done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+#endif
+#if (FW_HAS_SENSOR_MODE_CMD)
+ case HIC_SENSOR_MODE_CHANGE:
+ dbg_interface("sensor mode change done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+#endif
+ /*non-blocking command*/
+ case HIC_SHOT:
+ err("shot done is not acceptable\n");
+ break;
+ case HIC_SET_CAM_CONTROL:
+ /* this code will be used latter */
+#if 0
+ dbg_interface("camctrl done\n");
+ get_req_work(&itf->nblk_cam_ctrl , &nblk_work);
+ if (nblk_work) {
+ nblk_work->msg.command = ISR_DONE;
+ set_free_work(&itf->nblk_cam_ctrl,
+ nblk_work);
+ } else {
+ err("nblk camctrl request is empty");
+ print_fre_work_list(
+ &itf->nblk_cam_ctrl);
+ print_req_work_list(
+ &itf->nblk_cam_ctrl);
+ }
+#else
+ err("camctrl is not acceptable\n");
+#endif
+ break;
+ default:
+ err("unknown done is invokded\n");
+ break;
+ }
+ break;
+ case ISR_NDONE:
+ switch (msg->parameter1) {
+ case HIC_SHOT:
+ err("[ITF:%d] shot NDONE is not acceptable",
+ msg->instance);
+ break;
+ case HIC_SET_CAM_CONTROL:
+ dbg_interface("camctrl NOT done\n");
+ get_req_work(&itf->nblk_cam_ctrl , &nblk_work);
+ nblk_work->msg.command = ISR_NDONE;
+ set_free_work(&itf->nblk_cam_ctrl, nblk_work);
+ break;
+ case HIC_SET_PARAMETER:
+ err("s_param NOT done");
+ err("param2 : 0x%08X", msg->parameter2);
+ err("param3 : 0x%08X", msg->parameter3);
+ err("param4 : 0x%08X", msg->parameter4);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ default:
+ err("a command(%d) not done", msg->parameter1);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf, msg->parameter1);
+ break;
+ }
+ break;
+ case IHC_SET_FACE_MARK:
+ err("FACE_MARK(%d,%d,%d) is not acceptable\n",
+ msg->parameter1,
+ msg->parameter2,
+ msg->parameter3);
+ break;
+ case IHC_AA_DONE:
+ err("AA_DONE(%d,%d,%d) is not acceptable\n",
+ msg->parameter1,
+ msg->parameter2,
+ msg->parameter3);
+ break;
+ case IHC_FLASH_READY:
+ err("IHC_FLASH_READY is not acceptable");
+ break;
+ case IHC_NOT_READY:
+ err("IHC_NOT_READY is occured, need reset");
+ fimc_is_hw_logdump(itf);
+ break;
+#if (FW_HAS_REPORT_ERR_CMD)
+ case IHC_REPORT_ERR:
+ err("IHC_REPORT_ERR is occured");
+ fimc_is_err_report_handler(itf, msg);
+ break;
+#endif
+ default:
+ err("func_general unknown(0x%08X) end\n", msg->command);
+ break;
+ }
+
+ set_free_work(&itf->work_list[INTR_GENERAL], work);
+ get_req_work(&itf->work_list[INTR_GENERAL], &work);
+ }
+}
+
+static void wq_func_subdev(struct fimc_is_subdev *leader,
+ struct fimc_is_subdev *subdev,
+ u32 fcount, u32 rcount, u32 status, u32 instance)
+{
+ u32 findex, out_flag;
+ u32 capture_vid, capture_id;
+ char name;
+ unsigned long flags;
+ struct fimc_is_video_ctx *ldr_vctx, *sub_vctx;
+ struct fimc_is_framemgr *ldr_framemgr, *sub_framemgr;
+ struct fimc_is_frame *ldr_frame, *sub_frame;
+ struct camera2_node *capture;
+
+ BUG_ON(!leader);
+ BUG_ON(!subdev);
+
+ ldr_vctx = leader->vctx;
+ if (!ldr_vctx) {
+ err("ldr_vctx is NULL");
+ return;
+ }
+
+ sub_vctx = subdev->vctx;
+ if (!sub_vctx) {
+ err("sub_vctx is NULL");
+ return;
+ }
+
+ if (!sub_vctx->video) {
+ err("video is NULL");
+ return;
+ }
+
+ ldr_framemgr = GET_SRC_FRAMEMGR(ldr_vctx);
+ sub_framemgr = GET_DST_FRAMEMGR(sub_vctx);
+
+ capture_vid = sub_vctx->video->id;
+ switch (capture_vid) {
+ case FIMC_IS_VIDEO_SCC_NUM:
+ out_flag = OUT_SCC_FRAME;
+ name = 'C';
+ break;
+ case FIMC_IS_VIDEO_VDC_NUM:
+ out_flag = OUT_DIS_FRAME;
+ name = 'D';
+ break;
+ case FIMC_IS_VIDEO_SCP_NUM:
+ out_flag = OUT_SCP_FRAME;
+ name = 'P';
+ break;
+ case FIMC_IS_VIDEO_3A0C_NUM:
+ out_flag = OUT_3AAC_FRAME;
+ name = '0';
+ break;
+ case FIMC_IS_VIDEO_3A1C_NUM:
+ out_flag = OUT_3AAC_FRAME;
+ name = '1';
+ break;
+ default:
+ err("video node is invalid(%d)", sub_vctx->video->id);
+ return;
+ }
+
+ framemgr_e_barrier_irqs(sub_framemgr, 0, flags);
+
+ fimc_is_frame_process_head(sub_framemgr, &sub_frame);
+ if (sub_frame && test_bit(REQ_FRAME, &sub_frame->req_flag)) {
+
+#ifdef DBG_STREAMING
+ info("[%c:D:%d] %d(%d,%d)\n", name, instance,
+ sub_frame->index, fcount, rcount);
+#endif
+
+ if (!sub_frame->stream) {
+ err("stream is NULL, critical error");
+ goto p_err;
+ }
+
+ findex = sub_frame->stream->findex;
+ if (findex >= ldr_vctx->q_src->buf_maxcount) {
+ err("findex(%d) is invalid(max : %d)",
+ findex, ldr_vctx->q_src->buf_maxcount);
+ sub_frame->stream->fvalid = 0;
+ goto done;
+ }
+
+ ldr_frame = &ldr_framemgr->frame[findex];
+ if (status) {
+ info("[%c:D:%d] FRM%d NOT DONE(%d)\n", name,
+ instance, fcount, status);
+ sub_frame->stream->fvalid = 0;
+ clear_bit(out_flag, &ldr_frame->out_flag);
+ goto done;
+ }
+
+ if (ldr_frame->fcount != fcount) {
+ err("%c frame mismatched(ldr%d, sub%d)", name,
+ ldr_frame->fcount, fcount);
+ sub_frame->stream->fvalid = 0;
+ } else {
+ sub_frame->stream->fvalid = 1;
+ clear_bit(out_flag, &ldr_frame->out_flag);
+ }
+
+ for (capture_id = 0; capture_id < CAPTURE_NODE_MAX; ++capture_id) {
+ capture = &ldr_frame->shot_ext->node_group.capture[capture_id];
+ if (capture_vid == capture->vid) {
+ sub_frame->stream->output_crop_region[0] = capture->output.cropRegion[0];
+ sub_frame->stream->output_crop_region[1] = capture->output.cropRegion[1];
+ sub_frame->stream->output_crop_region[2] = capture->output.cropRegion[2];
+ sub_frame->stream->output_crop_region[3] = capture->output.cropRegion[3];
+
+ sub_frame->stream->input_crop_region[0] = capture->input.cropRegion[0];
+ sub_frame->stream->input_crop_region[1] = capture->input.cropRegion[1];
+ sub_frame->stream->input_crop_region[2] = capture->input.cropRegion[2];
+ sub_frame->stream->input_crop_region[3] = capture->input.cropRegion[3];
+ break;
+ }
+ }
+
+ if (capture_id >= CAPTURE_NODE_MAX) {
+ err("can't find capture stream(%d > %d)", capture_id, CAPTURE_NODE_MAX);
+ sub_frame->stream->output_crop_region[0] = 0;
+ sub_frame->stream->output_crop_region[1] = 0;
+ sub_frame->stream->output_crop_region[2] = 0;
+ sub_frame->stream->output_crop_region[3] = 0;
+ }
+
+done:
+ clear_bit(REQ_FRAME, &sub_frame->req_flag);
+ sub_frame->stream->fcount = fcount;
+ sub_frame->stream->rcount = rcount;
+
+ fimc_is_frame_trans_pro_to_com(sub_framemgr, sub_frame);
+ buffer_done(sub_vctx, sub_frame->index);
+ } else
+ err("done(%p) is occured without request", sub_frame);
+
+p_err:
+ framemgr_x_barrier_irqr(sub_framemgr, 0, flags);
+}
+
+static void wq_func_3a0c(struct work_struct *data)
+{
+ u32 instance, fcount, rcount, status;
+ struct fimc_is_interface *itf;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader, *subdev;
+ struct fimc_is_work *work;
+ struct fimc_is_msg *msg;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_wq[INTR_3A0C_FDONE]);
+
+ get_req_work(&itf->work_list[INTR_3A0C_FDONE], &work);
+ while (work) {
+ msg = &work->msg;
+ instance = msg->instance;
+ fcount = msg->parameter1;
+ status = msg->parameter2;
+ rcount = msg->parameter3;
+
+ if (instance >= FIMC_IS_MAX_NODES) {
+ err("instance is invalid(%d)", instance);
+ goto p_err;
+ }
+
+ device = &((struct fimc_is_core *)itf->core)->ischain[instance];
+ if (!device) {
+ err("device is NULL");
+ goto p_err;
+ }
+
+ subdev = &device->taac;
+ leader = subdev->leader;
+
+ wq_func_subdev(leader, subdev, fcount, rcount, status, instance);
+
+p_err:
+ set_free_work(&itf->work_list[INTR_3A0C_FDONE], work);
+ get_req_work(&itf->work_list[INTR_3A0C_FDONE], &work);
+ }
+}
+
+static void wq_func_3a1c(struct work_struct *data)
+{
+ u32 instance, fcount, rcount, status;
+ struct fimc_is_interface *itf;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader, *subdev;
+ struct fimc_is_work *work;
+ struct fimc_is_msg *msg;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_wq[INTR_3A1C_FDONE]);
+
+ get_req_work(&itf->work_list[INTR_3A1C_FDONE], &work);
+ while (work) {
+ msg = &work->msg;
+ instance = msg->instance;
+ fcount = msg->parameter1;
+ status = msg->parameter2;
+ rcount = msg->parameter3;
+
+ if (instance >= FIMC_IS_MAX_NODES) {
+ err("instance is invalid(%d)", instance);
+ goto p_err;
+ }
+
+ device = &((struct fimc_is_core *)itf->core)->ischain[instance];
+ if (!device) {
+ err("device is NULL");
+ goto p_err;
+ }
+
+ subdev = &device->taac;
+ leader = subdev->leader;
+
+ wq_func_subdev(leader, subdev, fcount, rcount, status, instance);
+
+p_err:
+ set_free_work(&itf->work_list[INTR_3A1C_FDONE], work);
+ get_req_work(&itf->work_list[INTR_3A1C_FDONE], &work);
+ }
+}
+
+static void wq_func_scc(struct work_struct *data)
+{
+ u32 instance, fcount, rcount, status;
+ struct fimc_is_interface *itf;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader, *subdev;
+ struct fimc_is_work *work;
+ struct fimc_is_msg *msg;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_wq[INTR_SCC_FDONE]);
+
+ get_req_work(&itf->work_list[INTR_SCC_FDONE], &work);
+ while (work) {
+ msg = &work->msg;
+ instance = msg->instance;
+ fcount = msg->parameter1;
+ status = msg->parameter2;
+ rcount = msg->parameter3;
+
+ if (instance >= FIMC_IS_MAX_NODES) {
+ err("instance is invalid(%d)", instance);
+ goto p_err;
+ }
+
+ device = &((struct fimc_is_core *)itf->core)->ischain[instance];
+ if (!device) {
+ err("device is NULL");
+ goto p_err;
+ }
+
+ subdev = &device->scc;
+ leader = subdev->leader;
+
+ wq_func_subdev(leader, subdev, fcount, rcount, status, instance);
+
+p_err:
+ set_free_work(&itf->work_list[INTR_SCC_FDONE], work);
+ get_req_work(&itf->work_list[INTR_SCC_FDONE], &work);
+ }
+}
+
+static void wq_func_dis(struct work_struct *data)
+{
+ u32 instance, fcount, rcount, status;
+ struct fimc_is_interface *itf;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader, *subdev;
+ struct fimc_is_work *work;
+ struct fimc_is_msg *msg;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_wq[INTR_DIS_FDONE]);
+
+ get_req_work(&itf->work_list[INTR_DIS_FDONE], &work);
+ while (work) {
+ msg = &work->msg;
+ instance = msg->instance;
+ fcount = msg->parameter1;
+ status = msg->parameter2;
+ rcount = msg->parameter3;
+
+ if (instance >= FIMC_IS_MAX_NODES) {
+ err("instance is invalid(%d)", instance);
+ goto p_err;
+ }
+
+ device = &((struct fimc_is_core *)itf->core)->ischain[instance];
+ if (!device) {
+ err("device is NULL");
+ goto p_err;
+ }
+
+ subdev = &device->dis;
+ leader = subdev->leader;
+
+ wq_func_subdev(leader, subdev, fcount, rcount, status, instance);
+
+p_err:
+ set_free_work(&itf->work_list[INTR_DIS_FDONE], work);
+ get_req_work(&itf->work_list[INTR_DIS_FDONE], &work);
+ }
+}
+
+static void wq_func_scp(struct work_struct *data)
+{
+ u32 instance, fcount, rcount, status;
+ struct fimc_is_interface *itf;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader, *subdev;
+ struct fimc_is_work *work;
+ struct fimc_is_msg *msg;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_wq[INTR_SCP_FDONE]);
+
+ get_req_work(&itf->work_list[INTR_SCP_FDONE], &work);
+ while (work) {
+ msg = &work->msg;
+ instance = msg->instance;
+ fcount = msg->parameter1;
+ status = msg->parameter2;
+ rcount = msg->parameter3;
+
+ if (instance >= FIMC_IS_MAX_NODES) {
+ err("instance is invalid(%d)", instance);
+ goto p_err;
+ }
+
+ device = &((struct fimc_is_core *)itf->core)->ischain[instance];
+ if (!device) {
+ err("device is NULL");
+ goto p_err;
+ }
+
+ subdev = &device->scp;
+ leader = subdev->leader;
+
+ wq_func_subdev(leader, subdev, fcount, rcount, status, instance);
+
+p_err:
+ set_free_work(&itf->work_list[INTR_SCP_FDONE], work);
+ get_req_work(&itf->work_list[INTR_SCP_FDONE], &work);
+ }
+}
+
+static void wq_func_group_3a0(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_framemgr *ldr_framemgr,
+ struct fimc_is_frame *ldr_frame,
+ struct fimc_is_framemgr *sub_framemgr,
+ struct fimc_is_video_ctx *vctx,
+ u32 status)
+{
+ u32 done_state = VB2_BUF_STATE_DONE;
+ unsigned long flags;
+ struct fimc_is_queue *src_queue, *dst_queue;
+ struct fimc_is_frame *sub_frame;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ldr_framemgr);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!sub_framemgr);
+
+ if (status != ISR_DONE) {
+ info("[3A0:D:%d] GRP0 NOT DONE(%d, %d)\n", group->instance,
+ ldr_frame->fcount, ldr_frame->index);
+ done_state = VB2_BUF_STATE_ERROR;
+ } else if ((group->device->taa_size_forceset) &&
+ (ldr_frame->fcount >= group->device->taa_size_changed_fcount)) {
+ /* Acknowledge the group size change settings */
+ group->device->taa_size_forceset = 0;
+ group->device->taa_size_changed_fcount = 0;
+ }
+
+#ifdef DBG_STREAMING
+ if (status == ISR_DONE)
+ info("[3A0:D:%d] GRP0 DONE(%d)\n", group->instance,
+ ldr_frame->fcount);
+#endif
+
+ src_queue = GET_SRC_QUEUE(vctx);
+ dst_queue = GET_DST_QUEUE(vctx);
+
+ /* 1. sub frame done */
+ framemgr_e_barrier_irqs(sub_framemgr, 0, flags);
+
+ fimc_is_frame_process_head(sub_framemgr, &sub_frame);
+ if (sub_frame && test_bit(REQ_FRAME, &sub_frame->req_flag)) {
+ clear_bit(REQ_FRAME, &sub_frame->req_flag);
+
+ sub_frame->stream->fvalid = 1;
+ sub_frame->stream->fcount = ldr_frame->fcount;
+ sub_frame->stream->rcount = ldr_frame->rcount;
+
+ fimc_is_frame_trans_pro_to_com(sub_framemgr, sub_frame);
+ queue_done(vctx, dst_queue, sub_frame->index, done_state);
+ } else
+ err("done is occured without request(%p, %d)", sub_frame, ldr_frame->fcount);
+
+ framemgr_x_barrier_irqr(sub_framemgr, 0, flags);
+
+ /* 2. leader frame done */
+ fimc_is_ischain_meta_invalid(ldr_frame);
+
+ fimc_is_frame_trans_pro_to_com(ldr_framemgr, ldr_frame);
+ fimc_is_group_done(groupmgr, group, ldr_frame, done_state);
+ queue_done(vctx, src_queue, ldr_frame->index, done_state);
+}
+
+static void wq_func_group_3a1(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_framemgr *ldr_framemgr,
+ struct fimc_is_frame *ldr_frame,
+ struct fimc_is_framemgr *sub_framemgr,
+ struct fimc_is_video_ctx *vctx,
+ u32 status)
+{
+ u32 done_state = VB2_BUF_STATE_DONE;
+ unsigned long flags;
+ struct fimc_is_queue *src_queue, *dst_queue;
+ struct fimc_is_frame *sub_frame;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ldr_framemgr);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!sub_framemgr);
+
+ if (status != ISR_DONE) {
+ info("[3A1:D:%d] GRP1 NOT DONE(%d, %d)\n", group->instance,
+ ldr_frame->fcount, ldr_frame->index);
+ done_state = VB2_BUF_STATE_ERROR;
+ } else if ((group->device->taa_size_forceset) &&
+ (ldr_frame->fcount >= group->device->taa_size_changed_fcount)) {
+ /* Acknowledge the group size change settings */
+ group->device->taa_size_forceset = 0;
+ group->device->taa_size_changed_fcount = 0;
+ }
+
+#ifdef DBG_STREAMING
+ if (status == ISR_DONE)
+ info("[3A1:D:%d] GRP1 DONE(%d)\n", group->instance,
+ ldr_frame->fcount);
+#endif
+
+ src_queue = GET_SRC_QUEUE(vctx);
+ dst_queue = GET_DST_QUEUE(vctx);
+
+ /* 1. sub frame done */
+ framemgr_e_barrier_irqs(sub_framemgr, 0, flags);
+
+ fimc_is_frame_process_head(sub_framemgr, &sub_frame);
+ if (sub_frame && test_bit(REQ_FRAME, &sub_frame->req_flag)) {
+ clear_bit(REQ_FRAME, &sub_frame->req_flag);
+
+ sub_frame->stream->fvalid = 1;
+ sub_frame->stream->fcount = ldr_frame->fcount;
+ sub_frame->stream->rcount = ldr_frame->rcount;
+
+ fimc_is_frame_trans_pro_to_com(sub_framemgr, sub_frame);
+ queue_done(vctx, dst_queue, sub_frame->index, done_state);
+ } else
+ err("done is occured without request(%p)", sub_frame);
+
+ framemgr_x_barrier_irqr(sub_framemgr, 0, flags);
+
+ /* 2. leader frame done */
+ fimc_is_ischain_meta_invalid(ldr_frame);
+
+ fimc_is_frame_trans_pro_to_com(ldr_framemgr, ldr_frame);
+ fimc_is_group_done(groupmgr, group, ldr_frame, done_state);
+ queue_done(vctx, src_queue, ldr_frame->index, done_state);
+}
+
+static void wq_func_group_isp(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_framemgr *framemgr,
+ struct fimc_is_frame *frame,
+ struct fimc_is_video_ctx *vctx,
+ u32 status)
+{
+ u32 done_state = VB2_BUF_STATE_DONE;
+ struct fimc_is_queue *queue;
+#ifdef ENABLE_SENSOR_DRIVER
+ struct camera2_lens_uctl *isp_lens_uctl;
+ struct camera2_lens_uctl *lens_uctl;
+ struct camera2_sensor_uctl *isp_sensor_uctl;
+ struct camera2_sensor_uctl *sensor_uctl;
+ struct camera2_flash_uctl *isp_flash_uctl;
+ struct camera2_flash_uctl *flash_uctl;
+#endif
+
+ BUG_ON(!framemgr);
+ BUG_ON(!frame);
+
+ if (status != ISR_DONE) {
+ info("[ISP:D:%d] GRP2 NOT DONE(%d, %d)\n", group->instance,
+ frame->fcount, frame->index);
+ done_state = VB2_BUF_STATE_ERROR;
+ } else if ((group->device->isp_size_forceset) &&
+ (frame->fcount >= group->device->isp_size_changed_fcount)) {
+ /* Acknowledge the group size change settings */
+ group->device->isp_size_forceset = 0;
+ group->device->isp_size_changed_fcount = 0;
+ }
+
+#ifdef DBG_STREAMING
+ if (status == ISR_DONE)
+ info("[ISP:D:%d] GRP2 DONE(%d)\n", group->instance,
+ frame->fcount);
+#endif
+
+ queue = GET_SRC_QUEUE(vctx);
+
+ /* Cache Invalidation */
+ fimc_is_ischain_meta_invalid(frame);
+
+#ifdef ENABLE_SENSOR_DRIVER
+ isp_lens_uctl = &itf->isp_peri_ctl.lensUd;
+ isp_sensor_uctl = &itf->isp_peri_ctl.sensorUd;
+ isp_flash_uctl = &itf->isp_peri_ctl.flashUd;
+
+ if (frame->shot->uctl.uUpdateBitMap & CAM_SENSOR_CMD) {
+ sensor_uctl = &frame->shot->uctl.sensorUd;
+ isp_sensor_uctl->ctl.exposureTime =
+ sensor_uctl->ctl.exposureTime;
+ isp_sensor_uctl->ctl.frameDuration =
+ sensor_uctl->ctl.frameDuration;
+ isp_sensor_uctl->ctl.sensitivity =
+ sensor_uctl->ctl.sensitivity;
+
+ frame->shot->uctl.uUpdateBitMap &=
+ ~CAM_SENSOR_CMD;
+ }
+
+ if (frame->shot->uctl.uUpdateBitMap & CAM_LENS_CMD) {
+ lens_uctl = &frame->shot->uctl.lensUd;
+ isp_lens_uctl->ctl.focusDistance =
+ lens_uctl->ctl.focusDistance;
+ isp_lens_uctl->maxPos =
+ lens_uctl->maxPos;
+ isp_lens_uctl->slewRate =
+ lens_uctl->slewRate;
+
+ frame->shot->uctl.uUpdateBitMap &=
+ ~CAM_LENS_CMD;
+ }
+
+ if (frame->shot->uctl.uUpdateBitMap & CAM_FLASH_CMD) {
+ flash_uctl = &frame->shot->uctl.flashUd;
+ isp_flash_uctl->ctl.flashMode =
+ flash_uctl->ctl.flashMode;
+ isp_flash_uctl->ctl.firingPower =
+ flash_uctl->ctl.firingPower;
+ isp_flash_uctl->ctl.firingTime =
+ flash_uctl->ctl.firingTime;
+
+ frame->shot->uctl.uUpdateBitMap &=
+ ~CAM_FLASH_CMD;
+ }
+#endif
+
+ fimc_is_frame_trans_pro_to_com(framemgr, frame);
+ fimc_is_group_done(groupmgr, group, frame, done_state);
+ queue_done(vctx, queue, frame->index, done_state);
+}
+
+static void wq_func_group_dis(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_framemgr *framemgr,
+ struct fimc_is_frame *frame,
+ struct fimc_is_video_ctx *vctx,
+ u32 status)
+{
+ u32 done_state = VB2_BUF_STATE_DONE;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!framemgr);
+ BUG_ON(!frame);
+
+ if (status != ISR_DONE) {
+ info("[DIS:D:%d] GRP3 NOT DONE(%d, %d)\n", group->instance,
+ frame->fcount, frame->index);
+ done_state = VB2_BUF_STATE_ERROR;
+ }
+
+#ifdef DBG_STREAMING
+ if (status == ISR_DONE)
+ info("[DIS:D:%d] GRP3 DONE(%d)\n", group->instance,
+ frame->fcount);
+#endif
+
+ queue = GET_SRC_QUEUE(vctx);
+
+ /* Cache Invalidation */
+ fimc_is_ischain_meta_invalid(frame);
+
+ fimc_is_frame_trans_pro_to_com(framemgr, frame);
+ fimc_is_group_done(groupmgr, group, frame, done_state);
+ queue_done(vctx, queue, frame->index, done_state);
+}
+
+void wq_func_group(struct fimc_is_groupmgr *groupmgr,
+ struct fimc_is_group *group,
+ struct fimc_is_framemgr *ldr_framemgr,
+ struct fimc_is_frame *ldr_frame,
+ struct fimc_is_video_ctx *vctx,
+ u32 status1, u32 status2, u32 fcount)
+{
+ u32 lindex, hindex;
+ struct fimc_is_framemgr *sub_framemgr;
+
+ BUG_ON(!groupmgr);
+ BUG_ON(!group);
+ BUG_ON(!ldr_framemgr);
+ BUG_ON(!ldr_frame);
+ BUG_ON(!vctx);
+
+ /*
+ * complete count should be lower than 3 when
+ * buffer is queued or overflow can be occured
+ */
+ if (ldr_framemgr->frame_com_cnt >= 2)
+ warn("remained completes is %d(%X)", (ldr_framemgr->frame_com_cnt + 1), group->id);
+
+ if (status2 != IS_SHOT_SUCCESS) {
+ lindex = ldr_frame->shot->ctl.entry.lowIndexParam;
+ lindex &= ~ldr_frame->shot->dm.entry.lowIndexParam;
+ hindex = ldr_frame->shot->ctl.entry.highIndexParam;
+ hindex &= ~ldr_frame->shot->dm.entry.highIndexParam;
+ if (lindex || hindex)
+ err("cause : %d : invalid parameter(%08X %08X)", status2, lindex, hindex);
+ else
+ err("cause : %d", status2);
+ }
+
+ switch (group->id) {
+ case GROUP_ID_3A0:
+ sub_framemgr = GET_DST_FRAMEMGR(vctx);
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ /*
+ * When OTF is enabled, 3A0 can have 2 more shots
+ * done is reported to hal if frame count is same
+ * not done is reported to hal if driver frame count is
+ * less than firmware frame count
+ * this correction is repeated
+ */
+ if (fcount != ldr_frame->fcount) {
+ while (ldr_frame) {
+ if (fcount == ldr_frame->fcount) {
+ status1 = ISR_NDONE;
+ wq_func_group_3a0(groupmgr, group,
+ ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+ break;
+ } else if (fcount > ldr_frame->fcount) {
+ err("cause: mismatch(%d != %d)",
+ fcount,
+ ldr_frame->fcount);
+ status1 = ISR_NDONE;
+ wq_func_group_3a0(groupmgr, group,
+ ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+
+ /* get next leader frame */
+ fimc_is_frame_process_head(ldr_framemgr,
+ &ldr_frame);
+ } else {
+ warn("%d done is ignored", fcount);
+ break;
+ }
+ }
+ } else {
+ wq_func_group_3a0(groupmgr, group,
+ ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+ }
+ } else {
+ if (fcount != ldr_frame->fcount) {
+ err("cause : mismatch(%d != %d)", fcount, ldr_frame->fcount);
+ status1 = ISR_NDONE;
+ }
+
+ wq_func_group_3a0(groupmgr, group, ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+ }
+ break;
+ case GROUP_ID_3A1:
+ sub_framemgr = GET_DST_FRAMEMGR(vctx);
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ /*
+ * When OTF is enabled, 3A1 can have 2 more shots
+ * done is reported to hal if frame count is same
+ * not done is reported to hal if driver frame count is
+ * less than firmware frame count
+ * this correction is repeated
+ */
+ if (fcount != ldr_frame->fcount) {
+
+ while (ldr_frame) {
+ if (fcount == ldr_frame->fcount) {
+ status1 = ISR_NDONE;
+ wq_func_group_3a1(groupmgr, group,
+ ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+ break;
+ } else if (fcount > ldr_frame->fcount) {
+ err("cause : mismatch(%d != %d)", fcount,
+ ldr_frame->fcount);
+ status1 = ISR_NDONE;
+ wq_func_group_3a1(groupmgr, group,
+ ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+
+ /* get next leader frame */
+ fimc_is_frame_process_head(ldr_framemgr,
+ &ldr_frame);
+ } else {
+ warn("%d done is ignored", fcount);
+ break;
+ }
+ }
+ } else {
+ wq_func_group_3a1(groupmgr, group,
+ ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+ }
+ } else {
+ if (fcount != ldr_frame->fcount) {
+ err("cause : mismatch(%d != %d)", fcount, ldr_frame->fcount);
+ status1 = ISR_NDONE;
+ }
+
+ wq_func_group_3a1(groupmgr, group, ldr_framemgr, ldr_frame,
+ sub_framemgr, vctx, status1);
+
+ }
+ break;
+ case GROUP_ID_ISP:
+ if (fcount != ldr_frame->fcount) {
+ err("cause : mismatch(%d != %d)", fcount,
+ ldr_frame->fcount);
+ status1 = ISR_NDONE;
+ }
+
+ wq_func_group_isp(groupmgr, group, ldr_framemgr, ldr_frame,
+ vctx, status1);
+ break;
+ case GROUP_ID_DIS:
+ if (fcount != ldr_frame->fcount) {
+ err("cause : mismatch(%d != %d)", fcount,
+ ldr_frame->fcount);
+ status1 = ISR_NDONE;
+ }
+
+ wq_func_group_dis(groupmgr, group, ldr_framemgr, ldr_frame,
+ vctx, status1);
+ break;
+ default:
+ err("unresolved group id %d", group->id);
+ break;
+ }
+}
+
+static void wq_func_shot(struct work_struct *data)
+{
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_interface *itf;
+ struct fimc_is_msg *msg;
+ struct fimc_is_framemgr *grp_framemgr;
+ struct fimc_is_frame *frame;
+ struct fimc_is_groupmgr *groupmgr;
+ struct fimc_is_group *group;
+ struct fimc_is_work_list *work_list;
+ struct fimc_is_work *work;
+ struct fimc_is_video_ctx *vctx;
+ unsigned long flags;
+ u32 req_flag;
+ u32 fcount;
+ u32 status1, status2;
+ int instance;
+ int group_id;
+ struct fimc_is_core *core;
+
+ BUG_ON(!data);
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_wq[INTR_SHOT_DONE]);
+ work_list = &itf->work_list[INTR_SHOT_DONE];
+ group = NULL;
+ vctx = NULL;
+ grp_framemgr = NULL;
+
+ get_req_work(work_list, &work);
+ while (work) {
+ core = (struct fimc_is_core *)itf->core;
+ instance = work->msg.instance;
+ group_id = work->msg.group;
+ device = &((struct fimc_is_core *)itf->core)->ischain[instance];
+ groupmgr = device->groupmgr;
+
+ msg = &work->msg;
+ fcount = msg->parameter1;
+ status1 = msg->parameter2;
+ status2 = msg->parameter3;
+
+ switch (group_id) {
+ case GROUP_ID(GROUP_ID_3A0):
+ /* if there's no entry to 3a1 */
+ if (GET_FIMC_IS_NUM_OF_SUBIP(core, 3a0)) {
+ req_flag = REQ_3AA_SHOT;
+ group = &device->group_3aa;
+ } else {
+ req_flag = REQ_ISP_SHOT;
+ group = &device->group_isp;
+ }
+ break;
+ case GROUP_ID(GROUP_ID_3A1):
+ req_flag = REQ_3AA_SHOT;
+ group = &device->group_3aa;
+ break;
+ case GROUP_ID(GROUP_ID_ISP):
+ req_flag = REQ_ISP_SHOT;
+ group = &device->group_isp;
+ break;
+ case GROUP_ID(GROUP_ID_DIS):
+ req_flag = REQ_DIS_SHOT;
+ group = &device->group_dis;
+ break;
+ default:
+ merr("unresolved group id %d", device, group_id);
+ group = NULL;
+ vctx = NULL;
+ grp_framemgr = NULL;
+ goto remain;
+ }
+
+ if (!group) {
+ merr("group is NULL", device);
+ goto remain;
+ }
+
+ vctx = group->leader.vctx;
+ if (!vctx) {
+ merr("vctx is NULL", device);
+ goto remain;
+ }
+
+ grp_framemgr = GET_SRC_FRAMEMGR(vctx);
+ if (!grp_framemgr) {
+ merr("grp_framemgr is NULL", device);
+ goto remain;
+ }
+
+ framemgr_e_barrier_irqs(grp_framemgr, FMGR_IDX_7, flags);
+
+ fimc_is_frame_process_head(grp_framemgr, &frame);
+
+ if (frame) {
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_shotdone);
+#endif
+#ifdef EXTERNAL_TIME
+ do_gettimeofday(&frame->tzone[TM_SHOT_D]);
+#endif
+#endif
+
+ clear_bit(req_flag, &frame->req_flag);
+ if (frame->req_flag)
+ merr("group(%d) req flag is not clear all(%X)",
+ device, group->id, (u32)frame->req_flag);
+
+#ifdef ENABLE_CLOCK_GATE
+ /* dynamic clock off */
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_set(core, group->id, false, false, true);
+#endif
+ wq_func_group(groupmgr, group, grp_framemgr, frame,
+ vctx, status1, status2, fcount);
+ } else {
+ merr("GRP%d DONE(%d) is occured without request",
+ device, group->id, fcount);
+ fimc_is_frame_print_all(grp_framemgr);
+ }
+
+ framemgr_x_barrier_irqr(grp_framemgr, FMGR_IDX_7, flags);
+#ifdef ENABLE_CLOCK_GATE
+ if (fcount == 1 &&
+ sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_lock_set(core, instance, false);
+#endif
+remain:
+ set_free_work(work_list, work);
+ get_req_work(work_list, &work);
+ }
+}
+
+static inline void wq_func_schedule(struct fimc_is_interface *itf,
+ struct work_struct *work_wq)
+{
+ if (itf->workqueue)
+ queue_work(itf->workqueue, work_wq);
+ else
+ schedule_work(work_wq);
+}
+
+static void interface_timer(unsigned long data)
+{
+ u32 shot_count, scount_3ax, scount_isp;
+ u32 fcount, i;
+ unsigned long flags;
+ struct fimc_is_interface *itf = (struct fimc_is_interface *)data;
+ struct fimc_is_core *core;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_device_sensor *sensor;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_work_list *work_list;
+ struct work_struct *work_wq;
+
+ BUG_ON(!itf);
+ BUG_ON(!itf->core);
+
+ if (!test_bit(IS_IF_STATE_OPEN, &itf->state)) {
+ pr_info("shot timer is terminated\n");
+ return;
+ }
+
+ core = itf->core;
+
+ for (i = 0; i < FIMC_IS_MAX_NODES; ++i) {
+ device = &core->ischain[i];
+ shot_count = 0;
+ scount_3ax = 0;
+ scount_isp = 0;
+
+ sensor = device->sensor;
+ if (!sensor)
+ continue;
+
+ if (!test_bit(FIMC_IS_SENSOR_FRONT_START, &sensor->state))
+ continue;
+
+ if (test_bit(FIMC_IS_ISCHAIN_OPEN_SENSOR, &device->state)) {
+ spin_lock_irq(&itf->shot_check_lock);
+ if (atomic_read(&itf->shot_check[i])) {
+ atomic_set(&itf->shot_check[i], 0);
+ atomic_set(&itf->shot_timeout[i], 0);
+ spin_unlock_irq(&itf->shot_check_lock);
+ continue;
+ }
+ spin_unlock_irq(&itf->shot_check_lock);
+
+ if (test_bit(FIMC_IS_GROUP_READY, &device->group_3aa.state)) {
+ framemgr = GET_GROUP_FRAMEMGR(&device->group_3aa);
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ scount_3ax = framemgr->frame_pro_cnt;
+ shot_count += scount_3ax;
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+
+ if (test_bit(FIMC_IS_GROUP_READY, &device->group_isp.state)) {
+ framemgr = GET_GROUP_FRAMEMGR(&device->group_isp);
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ scount_isp = framemgr->frame_pro_cnt;
+ shot_count += scount_isp;
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+
+ if (test_bit(FIMC_IS_GROUP_READY, &device->group_dis.state)) {
+ framemgr = GET_GROUP_FRAMEMGR(&device->group_dis);
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ shot_count += framemgr->frame_pro_cnt;
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+ }
+
+ if (shot_count) {
+ atomic_inc(&itf->shot_timeout[i]);
+ pr_err ("shot timer[%d] is increased to %d\n", i,
+ atomic_read(&itf->shot_timeout[i]));
+ }
+
+ if (atomic_read(&itf->shot_timeout[i]) > TRY_TIMEOUT_COUNT) {
+ merr("shot command is timeout(%d, %d(%d+%d))", device,
+ atomic_read(&itf->shot_timeout[i]),
+ shot_count, scount_3ax, scount_isp);
+
+ pr_err("\n### 3ax framemgr info ###\n");
+ if (scount_3ax) {
+ framemgr = GET_GROUP_FRAMEMGR(&device->group_3aa);
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ pr_err("\n### isp framemgr info ###\n");
+ if (scount_isp) {
+ framemgr = GET_GROUP_FRAMEMGR(&device->group_isp);
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ pr_err("\n### work list info ###\n");
+ work_list = &itf->work_list[INTR_SHOT_DONE];
+ print_fre_work_list(work_list);
+ print_req_work_list(work_list);
+
+ if (work_list->work_request_cnt > 0) {
+ pr_err("\n### processing work lately ###\n");
+ work_wq = &itf->work_wq[INTR_SHOT_DONE];
+ wq_func_shot(work_wq);
+
+ atomic_set(&itf->shot_check[i], 0);
+ atomic_set(&itf->shot_timeout[i], 0);
+ } else {
+ fimc_is_hw_logdump(itf);
+ fimc_is_hw_regdump(itf);
+
+ if (itf->need_iflag &&
+ readl(&itf->com_regs->shot_iflag)) {
+ pr_err("\n### MCUCTL check ###\n");
+ fimc_is_clr_intr(itf, INTR_SHOT_DONE);
+ fimc_is_hw_regdump(itf);
+ }
+#ifdef BUG_ON_ENABLE
+ BUG();
+#endif
+ return;
+ }
+ }
+ }
+
+ for (i = 0; i < FIMC_IS_MAX_NODES; ++i) {
+ sensor = &core->sensor[i];
+
+ if (!test_bit(FIMC_IS_SENSOR_FRONT_START, &sensor->state))
+ continue;
+
+ fcount = fimc_is_sensor_g_fcount(sensor);
+ if (fcount == atomic_read(&itf->sensor_check[i])) {
+ atomic_inc(&itf->sensor_timeout[i]);
+ pr_err ("sensor timer[%d] is increased to %d(fcount : %d)\n", i,
+ atomic_read(&itf->sensor_timeout[i]), fcount);
+ } else {
+ atomic_set(&itf->sensor_timeout[i], 0);
+ atomic_set(&itf->sensor_check[i], fcount);
+ }
+
+ if (atomic_read(&itf->sensor_timeout[i]) > SENSOR_TIMEOUT_COUNT) {
+ merr("sensor is timeout(%d, %d)", sensor,
+ atomic_read(&itf->sensor_timeout[i]),
+ atomic_read(&itf->sensor_check[i]));
+
+ /* print sensor clk , pwr state */
+ CALL_POPS(core, print_clk, device->pdev);
+ CALL_POPS(core, print_pwr, device->pdev);
+
+ /* print sensor info */
+ merr("sensor fcount : %d , framerate : %d\n", sensor,
+ fimc_is_sensor_g_fcount(sensor),
+ fimc_is_sensor_g_framerate(sensor));
+ merr("sensor w: %d , h: %d, bns_w: %d, bns_h: %d\n", sensor,
+ fimc_is_sensor_g_width(sensor),
+ fimc_is_sensor_g_height(sensor),
+ fimc_is_sensor_g_bns_width(sensor),
+ fimc_is_sensor_g_bns_height(sensor));
+
+ fimc_is_hw_logdump(itf);
+ fimc_is_hw_regdump(itf);
+#ifdef BUG_ON_ENABLE
+ BUG();
+#endif
+ return;
+ }
+ }
+
+ mod_timer(&itf->timer, jiffies + (FIMC_IS_COMMAND_TIMEOUT/TRY_TIMEOUT_COUNT));
+}
+
+static irqreturn_t interface_isr(int irq, void *data)
+{
+ struct fimc_is_interface *itf;
+ struct work_struct *work_wq;
+ struct fimc_is_work_list *work_list;
+ struct fimc_is_work *work;
+ u32 status;
+
+ itf = (struct fimc_is_interface *)data;
+ status = fimc_is_get_intr(itf);
+
+ if (status & (1<<INTR_SHOT_DONE)) {
+ work_wq = &itf->work_wq[INTR_SHOT_DONE];
+ work_list = &itf->work_list[INTR_SHOT_DONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_SHOT_DONE);
+ work->fcount = work->msg.parameter1;
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_wq))
+ wq_func_schedule(itf, work_wq);
+ } else
+ err("free work item is empty5");
+
+ status &= ~(1<<INTR_SHOT_DONE);
+ fimc_is_clr_intr(itf, INTR_SHOT_DONE);
+ }
+
+ if (status & (1<<INTR_GENERAL)) {
+ work_wq = &itf->work_wq[INTR_GENERAL];
+ work_list = &itf->work_list[INTR_GENERAL];
+
+ get_free_work_irq(&itf->work_list[INTR_GENERAL], &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_GENERAL);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_wq))
+ wq_func_schedule(itf, work_wq);
+ } else
+ err("free work item is empty1");
+
+ status &= ~(1<<INTR_GENERAL);
+ fimc_is_clr_intr(itf, INTR_GENERAL);
+ }
+
+ if (status & (1<<INTR_3A0C_FDONE)) {
+ work_wq = &itf->work_wq[INTR_3A0C_FDONE];
+ work_list = &itf->work_list[INTR_3A0C_FDONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_3A0C_FDONE);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_wq))
+ wq_func_schedule(itf, work_wq);
+ } else
+ err("free work item is empty2");
+
+ status &= ~(1<<INTR_3A0C_FDONE);
+ fimc_is_clr_intr(itf, INTR_3A0C_FDONE);
+ }
+
+ if (status & (1<<INTR_3A1C_FDONE)) {
+ work_wq = &itf->work_wq[INTR_3A1C_FDONE];
+ work_list = &itf->work_list[INTR_3A1C_FDONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_3A1C_FDONE);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_wq))
+ wq_func_schedule(itf, work_wq);
+ } else
+ err("free work item is empty2");
+
+ status &= ~(1<<INTR_3A1C_FDONE);
+ fimc_is_clr_intr(itf, INTR_3A1C_FDONE);
+ }
+
+ if (status & (1<<INTR_SCC_FDONE)) {
+ work_wq = &itf->work_wq[INTR_SCC_FDONE];
+ work_list = &itf->work_list[INTR_SCC_FDONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_SCC_FDONE);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_wq))
+ wq_func_schedule(itf, work_wq);
+ } else
+ err("free work item is empty2");
+
+ status &= ~(1<<INTR_SCC_FDONE);
+ fimc_is_clr_intr(itf, INTR_SCC_FDONE);
+ }
+
+ if (status & (1<<INTR_DIS_FDONE)) {
+ work_wq = &itf->work_wq[INTR_DIS_FDONE];
+ work_list = &itf->work_list[INTR_DIS_FDONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_DIS_FDONE);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_wq))
+ wq_func_schedule(itf, work_wq);
+ } else {
+ err("free work item is empty3");
+ }
+
+ status &= ~(1<<INTR_DIS_FDONE);
+ fimc_is_clr_intr(itf, INTR_DIS_FDONE);
+ }
+
+ if (status & (1<<INTR_SCP_FDONE)) {
+ work_wq = &itf->work_wq[INTR_SCP_FDONE];
+ work_list = &itf->work_list[INTR_SCP_FDONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_SCP_FDONE);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_wq))
+ wq_func_schedule(itf, work_wq);
+ } else {
+ err("free work item is empty4");
+ }
+
+ status &= ~(1<<INTR_SCP_FDONE);
+ fimc_is_clr_intr(itf, INTR_SCP_FDONE);
+ }
+
+ if (status != 0)
+ err("status is NOT all clear(0x%08X)", status);
+
+ return IRQ_HANDLED;
+}
+
+#define VERSION_OF_NO_NEED_IFLAG 221
+int fimc_is_interface_probe(struct fimc_is_interface *this,
+ u32 regs,
+ u32 irq,
+ void *core_data)
+{
+ int ret = 0;
+ struct fimc_is_core *core = (struct fimc_is_core *)core_data;
+
+ dbg_interface("%s\n", __func__);
+
+ init_request_barrier(this);
+ init_process_barrier(this);
+ init_waitqueue_head(&this->lock_wait_queue);
+ init_waitqueue_head(&this->init_wait_queue);
+ init_waitqueue_head(&this->idle_wait_queue);
+ spin_lock_init(&this->shot_check_lock);
+
+ this->workqueue = alloc_workqueue("fimc-is/highpri", WQ_HIGHPRI, 0);
+ if (!this->workqueue)
+ warn("failed to alloc own workqueue, will be use global one");
+
+ INIT_WORK(&this->work_wq[INTR_GENERAL], wq_func_general);
+ INIT_WORK(&this->work_wq[INTR_3A0C_FDONE], wq_func_3a0c);
+ INIT_WORK(&this->work_wq[INTR_3A1C_FDONE], wq_func_3a1c);
+ INIT_WORK(&this->work_wq[INTR_SCC_FDONE], wq_func_scc);
+ INIT_WORK(&this->work_wq[INTR_DIS_FDONE], wq_func_dis);
+ INIT_WORK(&this->work_wq[INTR_SCP_FDONE], wq_func_scp);
+ INIT_WORK(&this->work_wq[INTR_SHOT_DONE], wq_func_shot);
+
+ this->regs = (void *)regs;
+ this->com_regs = (struct is_common_reg *)(regs + ISSR0);
+
+ if (GET_FIMC_IS_VER_OF_SUBIP(core, mcuctl) < VERSION_OF_NO_NEED_IFLAG)
+ this->need_iflag = true;
+ else
+ this->need_iflag = false;
+
+ ret = request_irq(irq, interface_isr, 0, "mcuctl", this);
+ if (ret)
+ err("request_irq failed\n");
+
+ notify_fcount_sen0 = &this->com_regs->fcount_sen0;
+ notify_fcount_sen1 = &this->com_regs->fcount_sen1;
+ notify_fcount_sen2 = &this->com_regs->fcount_sen2;
+ last_fcount1 = &this->com_regs->fcount_sen3;
+ last_fcount0 = &this->com_regs->grp1_done_frame_num;
+ this->core = (void *)core;
+ clear_bit(IS_IF_STATE_OPEN, &this->state);
+ clear_bit(IS_IF_STATE_START, &this->state);
+ clear_bit(IS_IF_STATE_BUSY, &this->state);
+ clear_bit(IS_IF_STATE_READY, &this->state);
+
+ init_work_list(&this->nblk_cam_ctrl,
+ TRACE_WORK_ID_CAMCTRL, MAX_NBLOCKING_COUNT);
+ init_work_list(&this->work_list[INTR_GENERAL],
+ TRACE_WORK_ID_GENERAL, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_3A0C_FDONE],
+ TRACE_WORK_ID_3A0C, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_3A1C_FDONE],
+ TRACE_WORK_ID_3A1C, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_SCC_FDONE],
+ TRACE_WORK_ID_SCC, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_DIS_FDONE],
+ TRACE_WORK_ID_DIS, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_SCP_FDONE],
+ TRACE_WORK_ID_SCP, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_SHOT_DONE],
+ TRACE_WORK_ID_SHOT, MAX_WORK_COUNT);
+
+ this->err_report_vendor = NULL;
+#ifdef MEASURE_TIME
+#ifdef INTERFACE_TIME
+ {
+ u32 i;
+ for (i = 0; i < HIC_COMMAND_END; ++i)
+ measure_init(&this->time[i], i);
+ }
+#endif
+#endif
+
+ return ret;
+}
+
+int fimc_is_interface_open(struct fimc_is_interface *this)
+{
+ int i;
+ int ret = 0;
+
+ if (test_bit(IS_IF_STATE_OPEN, &this->state)) {
+ err("already open");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ dbg_interface("%s\n", __func__);
+
+ for (i = 0; i < FIMC_IS_MAX_NODES; i++) {
+ this->streaming[i] = IS_IF_STREAMING_INIT;
+ this->processing[i] = IS_IF_PROCESSING_INIT;
+ atomic_set(&this->shot_check[i], 0);
+ atomic_set(&this->shot_timeout[i], 0);
+ atomic_set(&this->sensor_check[i], 0);
+ atomic_set(&this->sensor_timeout[i], 0);
+ }
+ this->pdown_ready = IS_IF_POWER_DOWN_READY;
+ atomic_set(&this->lock_pid, 0);
+ clear_bit(IS_IF_STATE_START, &this->state);
+ clear_bit(IS_IF_STATE_BUSY, &this->state);
+ clear_bit(IS_IF_STATE_READY, &this->state);
+
+ init_timer(&this->timer);
+ this->timer.expires = jiffies +
+ (FIMC_IS_COMMAND_TIMEOUT/TRY_TIMEOUT_COUNT);
+ this->timer.data = (unsigned long)this;
+ this->timer.function = interface_timer;
+ add_timer(&this->timer);
+
+ set_bit(IS_IF_STATE_OPEN, &this->state);
+
+exit:
+ return ret;
+}
+
+int fimc_is_interface_close(struct fimc_is_interface *this)
+{
+ int ret = 0;
+ int retry;
+
+ if (!test_bit(IS_IF_STATE_OPEN, &this->state)) {
+ err("already close");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ retry = 10;
+ while (test_busystate(this) && retry) {
+ err("interface is busy");
+ msleep(20);
+ retry--;
+ }
+ if (!retry)
+ err("waiting idle is fail");
+
+ del_timer_sync(&this->timer);
+ dbg_interface("%s\n", __func__);
+
+ clear_bit(IS_IF_STATE_OPEN, &this->state);
+
+exit:
+ return ret;
+}
+
+void fimc_is_interface_lock(struct fimc_is_interface *this)
+{
+ atomic_set(&this->lock_pid, current->pid);
+}
+
+void fimc_is_interface_unlock(struct fimc_is_interface *this)
+{
+ atomic_set(&this->lock_pid, 0);
+ wake_up(&this->lock_wait_queue);
+}
+
+void fimc_is_interface_reset(struct fimc_is_interface *this)
+{
+ if (this->need_iflag) {
+ writel(0, &this->com_regs->ihcmd_iflag);
+ writel(0, &this->com_regs->taa0c_iflag);
+ writel(0, &this->com_regs->taa1c_iflag);
+ writel(0, &this->com_regs->scc_iflag);
+ writel(0, &this->com_regs->dis_iflag);
+ writel(0, &this->com_regs->scp_iflag);
+ writel(0, &this->com_regs->shot_iflag);
+ }
+}
+
+int fimc_is_hw_logdump(struct fimc_is_interface *this)
+{
+ int debug_cnt, sentence_i;
+ char *debug;
+ char letter;
+ char sentence[250];
+ int count = 0, i;
+ struct fimc_is_core *core;
+
+ if (!test_bit(IS_IF_STATE_OPEN, &this->state)) {
+ warn("interface is closed");
+ count = -EINVAL;
+ goto p_err;
+ }
+
+ pr_err("\n### firmware messsage dump ###\n");
+
+ core = (struct fimc_is_core *)this->core;
+ sentence_i = 0;
+
+ vb2_ion_sync_for_device(core->minfo.fw_cookie,
+ DEBUG_OFFSET, DEBUG_CNT, DMA_FROM_DEVICE);
+
+ debug = (char *)(core->minfo.kvaddr + DEBUG_OFFSET);
+ debug_cnt = *((int *)(core->minfo.kvaddr + DEBUGCTL_OFFSET))
+ - DEBUG_OFFSET;
+
+ if (core->debug_cnt > debug_cnt)
+ count = (DEBUG_CNT - core->debug_cnt) + debug_cnt;
+ else
+ count = debug_cnt - core->debug_cnt;
+
+ if (count) {
+ printk(KERN_ERR "start(%d %d)\n", debug_cnt, count);
+ for (i = core->debug_cnt; count > 0; count--) {
+ letter = debug[i];
+ if (letter) {
+ sentence[sentence_i] = letter;
+ if (sentence_i >= 247) {
+ sentence[sentence_i + 1] = '\n';
+ sentence[sentence_i + 2] = 0;
+ printk(KERN_ERR "%s", sentence);
+ sentence_i = 0;
+ } else if (letter == '\n') {
+ sentence[sentence_i + 1] = 0;
+ printk(KERN_ERR "%s", sentence);
+ sentence_i = 0;
+ } else {
+ sentence_i++;
+ }
+ }
+ i++;
+ if (i > DEBUG_CNT)
+ i = 0;
+ }
+ core->debug_cnt = debug_cnt;
+ printk(KERN_ERR "end\n");
+ }
+
+p_err:
+ return count;
+}
+
+int fimc_is_hw_regdump(struct fimc_is_interface *this)
+{
+ int ret = 0;
+ u32 i;
+ void __iomem *regs;
+
+ if (!test_bit(IS_IF_STATE_OPEN, &this->state)) {
+ warn("interface is closed");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("\n### MCUCTL Raw Dump ###\n");
+ regs = (this->regs);
+ for (i = 0; i < 16; ++i)
+ info("MCTL Raw[%d] : %08X\n", i, readl(regs + (4 * i)));
+
+ info("\n### COMMON REGS dump ###\n");
+ regs = this->com_regs;
+ for (i = 0; i < 64; ++i)
+ info("MCTL[%d] : %08X\n", i, readl(regs + (4 * i)));
+
+p_err:
+ return ret;
+}
+
+int fimc_is_hw_memdump(struct fimc_is_interface *this,
+ u32 start,
+ u32 end)
+{
+ int ret = 0;
+ u32 *cur;
+ u32 items, offset;
+ char term[50], sentence[250];
+
+ if (!test_bit(IS_IF_STATE_OPEN, &this->state)) {
+ warn("interface is closed");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ cur = (u32 *)start;
+ items = 0;
+ offset = 0;
+
+ memset(sentence, 0, sizeof(sentence));
+ printk(KERN_ERR "Memory Dump(0x%08X ~ 0x%08X)\n", start, end);
+
+ while ((u32)cur <= end) {
+ if (!(items % 8)) {
+ printk(KERN_ERR "%s", sentence);
+ offset = 0;
+ snprintf(term, sizeof(term), "%p: ", cur);
+ snprintf(&sentence[offset], sizeof(sentence) - offset, "%s", term);
+ offset += strlen(term);
+ }
+
+ snprintf(term, sizeof(term), "%08X ", *cur);
+ snprintf(&sentence[offset], sizeof(sentence) - offset, "%s", term);
+ offset += strlen(term);
+ cur++;
+ items++;
+ }
+
+ ret = (u32)cur - end;
+
+p_err:
+ return ret;
+}
+
+int fimc_is_hw_msg_test(struct fimc_is_interface *this, u32 sync_id, u32 msg_test_id)
+{
+ int ret = 0;
+ struct fimc_is_work work;
+ struct fimc_is_msg *msg;
+
+ dbg_interface("msg_test_nblk(%d)\n", msg_test_id);
+
+ msg = &work.msg;
+ msg->id = 0;
+ msg->command = HIC_MSG_TEST;
+ msg->instance = 0;
+ msg->group = 0;
+ msg->parameter1 = msg_test_id;
+ msg->parameter2 = sync_id;
+ msg->parameter3 = 0;
+ msg->parameter4 = 0;
+
+ ret = fimc_is_set_cmd_nblk(this, &work);
+
+ return ret;
+}
+
+int fimc_is_hw_enum(struct fimc_is_interface *this)
+{
+ int ret = 0;
+ struct fimc_is_msg msg;
+ volatile struct is_common_reg __iomem *com_regs;
+
+ dbg_interface("enum()\n");
+
+ /* check if hw_enum is already operated */
+ if (test_bit(IS_IF_STATE_READY, &this->state))
+ goto exit;
+
+ ret = wait_initstate(this);
+ if (ret) {
+ err("enum time out");
+ ret = -ETIME;
+ goto exit;
+ }
+
+ msg.id = 0;
+ msg.command = ISR_DONE;
+ msg.instance = 0;
+ msg.group = 0;
+ msg.parameter1 = IHC_GET_SENSOR_NUMBER;
+ /*
+ * this mean sensor numbers
+ * signel sensor: 1, dual sensor: 2, triple sensor: 3
+ */
+ msg.parameter2 = 3;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ waiting_is_ready(this);
+ com_regs = this->com_regs;
+ writel(msg.command, &com_regs->hicmd);
+ writel(msg.instance, &com_regs->hic_sensorid);
+ writel(msg.parameter1, &com_regs->hic_param1);
+ writel(msg.parameter2, &com_regs->hic_param2);
+ writel(msg.parameter3, &com_regs->hic_param3);
+ writel(msg.parameter4, &com_regs->hic_param4);
+ send_interrupt(this);
+
+ set_bit(IS_IF_STATE_READY, &this->state);
+
+exit:
+ return ret;
+}
+
+int fimc_is_hw_saddr(struct fimc_is_interface *this,
+ u32 instance, u32 *setfile_addr)
+{
+ int ret = 0;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("saddr(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_GET_SET_FILE_ADDR;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+ *setfile_addr = reply.parameter2;
+
+ return ret;
+}
+
+int fimc_is_hw_setfile(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret = 0;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("setfile(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_LOAD_SET_FILE;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_open(struct fimc_is_interface *this,
+ u32 instance,
+ u32 module_id,
+ u32 info,
+ u32 group,
+ u32 flag,
+ u32 *mwidth,
+ u32 *mheight)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("open(%d,%d,%08X)\n", module_id, group, flag);
+
+ msg.id = 0;
+ msg.command = HIC_OPEN_SENSOR;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = module_id;
+ msg.parameter2 = info;
+ msg.parameter3 = group;
+ msg.parameter4 = flag;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ *mwidth = reply.parameter2;
+ *mheight = reply.parameter3;
+
+ return ret;
+}
+
+int fimc_is_hw_close(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("close sensor(instance:%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_CLOSE_SENSOR;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_stream_on(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ BUG_ON(!this);
+
+ dbg_interface("stream_on(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_STREAM_ON;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_stream_off(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("stream_off(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_STREAM_OFF;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_process_on(struct fimc_is_interface *this,
+ u32 instance, u32 group)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("process_on(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_PROCESS_START;
+ msg.instance = instance;
+ msg.group = group;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_process_off(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 mode)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ WARN_ON(mode >= 2);
+
+ dbg_interface("process_off(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_PROCESS_STOP;
+ msg.instance = instance;
+ msg.group = group;
+ msg.parameter1 = mode;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_i2c_lock(struct fimc_is_interface *this,
+ u32 instance, int i2c_clk, bool lock)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("i2c_lock(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_I2C_CONTROL_LOCK;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = lock;
+ msg.parameter2 = i2c_clk;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_s_param(struct fimc_is_interface *this,
+ u32 instance, u32 lindex, u32 hindex, u32 indexes)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("s_param(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_SET_PARAMETER;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = ISS_PREVIEW_STILL;
+ msg.parameter2 = indexes;
+ msg.parameter3 = lindex;
+ msg.parameter4 = hindex;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_a_param(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 sub_mode)
+{
+ int ret = 0;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("a_param(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_PREVIEW_STILL;
+ msg.instance = instance;
+ msg.group = group;
+ msg.parameter1 = sub_mode;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_g_capability(struct fimc_is_interface *this,
+ u32 instance, u32 address)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("g_capability(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_GET_STATIC_METADATA;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = address;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_map(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 address, u32 size)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("[%d][%d] map(%08X, %X)\n", instance, group, address, size);
+
+ msg.id = 0;
+ msg.command = HIC_SET_A5_MAP;
+ msg.instance = instance;
+ msg.group = group;
+ msg.parameter1 = address;
+ msg.parameter2 = size;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_unmap(struct fimc_is_interface *this,
+ u32 instance, u32 group)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("[%d][%d] unmap\n", instance, group);
+
+ msg.id = 0;
+ msg.command = HIC_SET_A5_UNMAP;
+ msg.instance = instance;
+ msg.group = group;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+int fimc_is_hw_power_down(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret = 0;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("pwr_down(%d)\n", instance);
+
+ if (!test_bit(IS_IF_STATE_START, &this->state)) {
+ warn("instance(%d): FW is not initialized, wait\n", instance);
+ ret = fimc_is_hw_enum(this);
+ if (ret)
+ err("fimc_is_itf_enum is fail(%d)", ret);
+ }
+
+ msg.id = 0;
+ msg.command = HIC_POWER_DOWN;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+
+#if (FW_HAS_SYS_CTRL_CMD)
+int fimc_is_hw_sys_ctl(struct fimc_is_interface *this,
+ u32 instance, int cmd, int val)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("sys_ctl(cmd(%d), val(%d))\n", cmd, val);
+
+ msg.id = 0;
+ msg.command = HIC_SYSTEM_CONTROL;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = cmd;
+ msg.parameter2 = val;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+#else
+int fimc_is_hw_sys_ctl(struct fimc_is_interface *this,
+ u32 instance, int cmd, int val)
+{
+ return 0;
+}
+#endif
+
+#if (FW_HAS_SENSOR_MODE_CMD)
+int fimc_is_hw_sensor_mode(struct fimc_is_interface *this,
+ u32 instance, int cfg)
+{
+ int ret;
+ struct fimc_is_msg msg, reply;
+
+ dbg_interface("sensor mode(%d): %d\n", instance, cfg);
+
+ msg.id = 0;
+ msg.command = HIC_SENSOR_MODE_CHANGE;
+ msg.instance = instance;
+ msg.group = 0;
+ msg.parameter1 = cfg;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg, &reply);
+
+ return ret;
+}
+#else
+int fimc_is_hw_sensor_mode(struct fimc_is_interface *this,
+ u32 instance, int cfg)
+{
+ return 0;
+}
+#endif
+
+int fimc_is_hw_shot_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 bayer, u32 shot, u32 fcount, u32 rcount)
+{
+ int ret = 0;
+ struct fimc_is_msg msg;
+
+ /*dbg_interface("shot_nblk(%d, %d)\n", instance, fcount);*/
+
+ msg.id = 0;
+ msg.command = HIC_SHOT;
+ msg.instance = instance;
+ msg.group = group;
+ msg.parameter1 = bayer;
+ msg.parameter2 = shot;
+ msg.parameter3 = fcount;
+ msg.parameter4 = rcount;
+
+ ret = fimc_is_set_cmd_shot(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_s_camctrl_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 address, u32 fcount)
+{
+ int ret = 0;
+ struct fimc_is_work *work;
+ struct fimc_is_msg *msg;
+
+ dbg_interface("cam_ctrl_nblk(%d)\n", instance);
+
+ get_free_work(&this->nblk_cam_ctrl, &work);
+
+ if (work) {
+ work->fcount = fcount;
+ msg = &work->msg;
+ msg->id = 0;
+ msg->command = HIC_SET_CAM_CONTROL;
+ msg->instance = instance;
+ msg->group = 0;
+ msg->parameter1 = address;
+ msg->parameter2 = fcount;
+ msg->parameter3 = 0;
+ msg->parameter4 = 0;
+
+ ret = fimc_is_set_cmd_nblk(this, work);
+ } else {
+ err("g_free_nblk return NULL");
+ print_fre_work_list(&this->nblk_cam_ctrl);
+ print_req_work_list(&this->nblk_cam_ctrl);
+ ret = 1;
+ }
+
+ return ret;
+}
--- /dev/null
+/*
+ * drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * The header file related to camera
+ *
+ * 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 FIMC_IS_INTERFACE_H
+#define FIMC_IS_INTERFACE_H
+
+#include "fimc-is-metadata.h"
+#include "fimc-is-framemgr.h"
+#include "fimc-is-video.h"
+#include "fimc-is-time.h"
+#include "fimc-is-cmd.h"
+
+/*#define TRACE_WORK*/
+/* cam_ctrl : 1
+ shot : 2 */
+#define TRACE_WORK_ID_CAMCTRL 0x1
+#define TRACE_WORK_ID_SHOT 0x2
+#define TRACE_WORK_ID_GENERAL 0x4
+#define TRACE_WORK_ID_3A0C 0x8
+#define TRACE_WORK_ID_3A1C 0x10
+#define TRACE_WORK_ID_SCC 0x20
+#define TRACE_WORK_ID_DIS 0x40
+#define TRACE_WORK_ID_SCP 0x80
+#define TRACE_WORK_ID_MASK 0xFF
+
+#define MAX_NBLOCKING_COUNT 3
+#define MAX_WORK_COUNT 10
+
+#define TRY_TIMEOUT_COUNT 2
+#define SENSOR_TIMEOUT_COUNT 2
+#define TRY_RECV_AWARE_COUNT 100
+
+#define LOWBIT_OF(num) (num >= 32 ? 0 : (u32)1<<num)
+#define HIGHBIT_OF(num) (num >= 32 ? (u32)1<<(num-32) : 0)
+
+enum fimc_is_interface_state {
+ IS_IF_STATE_OPEN,
+ IS_IF_STATE_START,
+ IS_IF_STATE_BUSY,
+ IS_IF_STATE_READY
+};
+
+enum interrupt_map {
+ INTR_GENERAL = 0,
+ INTR_ISP_FDONE = 1,
+ INTR_3A0C_FDONE = 2,
+ INTR_3A1C_FDONE = 3,
+ INTR_SCC_FDONE = 4,
+ INTR_DIS_FDONE = 5,
+ INTR_SCP_FDONE = 6,
+ INTR_SHOT_DONE = 7,
+ INTR_MAX_MAP
+};
+
+enum streaming_state {
+ IS_IF_STREAMING_INIT,
+ IS_IF_STREAMING_OFF,
+ IS_IF_STREAMING_ON
+};
+
+enum processing_state {
+ IS_IF_PROCESSING_INIT,
+ IS_IF_PROCESSING_OFF,
+ IS_IF_PROCESSING_ON
+};
+
+enum pdown_ready_state {
+ IS_IF_POWER_DOWN_READY,
+ IS_IF_POWER_DOWN_NREADY
+};
+
+struct fimc_is_msg {
+ u32 id;
+ u32 command;
+ u32 instance;
+ u32 group;
+ u32 parameter1;
+ u32 parameter2;
+ u32 parameter3;
+ u32 parameter4;
+};
+
+struct fimc_is_work {
+ struct list_head list;
+ struct fimc_is_msg msg;
+ u32 fcount;
+ struct fimc_is_frame *frame;
+};
+
+struct fimc_is_work_list {
+ u32 id;
+ struct fimc_is_work work[MAX_WORK_COUNT];
+ spinlock_t slock_free;
+ spinlock_t slock_request;
+ struct list_head work_free_head;
+ u32 work_free_cnt;
+ struct list_head work_request_head;
+ u32 work_request_cnt;
+ wait_queue_head_t wait_queue;
+};
+
+struct fimc_is_interface {
+ void __iomem *regs;
+ struct is_common_reg __iomem *com_regs;
+ bool need_iflag;
+ unsigned long state;
+ spinlock_t process_barrier;
+ struct mutex request_barrier;
+
+ atomic_t lock_pid;
+ wait_queue_head_t lock_wait_queue;
+ wait_queue_head_t init_wait_queue;
+ wait_queue_head_t idle_wait_queue;
+ struct fimc_is_msg reply;
+#ifdef MEASURE_TIME
+#ifdef INTERFACE_TIME
+ struct fimc_is_interface_time time[HIC_COMMAND_END];
+#endif
+#endif
+
+ struct workqueue_struct *workqueue;
+ struct work_struct work_wq[INTR_MAX_MAP];
+ struct fimc_is_work_list work_list[INTR_MAX_MAP];
+
+ /* sensor streaming flag */
+ enum streaming_state streaming[FIMC_IS_MAX_NODES];
+ /* firmware processing flag */
+ enum processing_state processing[FIMC_IS_MAX_NODES];
+ /* frrmware power down ready flag */
+ enum pdown_ready_state pdown_ready;
+
+ struct fimc_is_framemgr *framemgr;
+
+ struct fimc_is_work_list nblk_cam_ctrl;
+
+ /* shot timeout check */
+ spinlock_t shot_check_lock;
+ atomic_t shot_check[FIMC_IS_MAX_NODES];
+ atomic_t shot_timeout[FIMC_IS_MAX_NODES];
+ /* sensor timeout check */
+ atomic_t sensor_check[FIMC_IS_MAX_NODES];
+ atomic_t sensor_timeout[FIMC_IS_MAX_NODES];
+ struct timer_list timer;
+
+ /* callback func to handle error report for specific purpose */
+ void *err_report_data;
+ int (*err_report_vendor)(void *data, u32 err_report_type);
+
+ struct camera2_uctl isp_peri_ctl;
+ void *core;
+};
+
+int fimc_is_interface_probe(struct fimc_is_interface *this,
+ u32 regs,
+ u32 irq,
+ void *core_data);
+int fimc_is_interface_open(struct fimc_is_interface *this);
+int fimc_is_interface_close(struct fimc_is_interface *this);
+void fimc_is_interface_lock(struct fimc_is_interface *this);
+void fimc_is_interface_unlock(struct fimc_is_interface *this);
+void fimc_is_interface_reset(struct fimc_is_interface *this);
+
+/*for debugging*/
+int print_fre_work_list(struct fimc_is_work_list *this);
+int print_req_work_list(struct fimc_is_work_list *this);
+
+int fimc_is_hw_msg_test(struct fimc_is_interface *this, u32 sync_id, u32 msg_test_id);
+int fimc_is_hw_logdump(struct fimc_is_interface *this);
+int fimc_is_hw_regdump(struct fimc_is_interface *this);
+int fimc_is_hw_memdump(struct fimc_is_interface *this,
+ u32 start,
+ u32 end);
+int fimc_is_hw_enum(struct fimc_is_interface *this);
+int fimc_is_hw_open(struct fimc_is_interface *this,
+ u32 instance, u32 module, u32 info, u32 group, u32 flag,
+ u32 *mwidth, u32 *mheight);
+int fimc_is_hw_close(struct fimc_is_interface *this,
+ u32 instance);
+int fimc_is_hw_saddr(struct fimc_is_interface *interface,
+ u32 instance, u32 *setfile_addr);
+int fimc_is_hw_setfile(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_process_on(struct fimc_is_interface *this,
+ u32 instance, u32 group);
+int fimc_is_hw_process_off(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 mode);
+int fimc_is_hw_stream_on(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_stream_off(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_s_param(struct fimc_is_interface *interface,
+ u32 instance, u32 lindex, u32 hindex, u32 indexes);
+int fimc_is_hw_a_param(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 sub_mode);
+int fimc_is_hw_g_capability(struct fimc_is_interface *this,
+ u32 instance, u32 address);
+int fimc_is_hw_map(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 address, u32 size);
+int fimc_is_hw_unmap(struct fimc_is_interface *this,
+ u32 instance, u32 group);
+int fimc_is_hw_power_down(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_i2c_lock(struct fimc_is_interface *interface,
+ u32 instance, int clk, bool lock);
+int fimc_is_hw_sys_ctl(struct fimc_is_interface *this,
+ u32 instance, int cmd, int val);
+int fimc_is_hw_sensor_mode(struct fimc_is_interface *this,
+ u32 instance, int cfg);
+
+int fimc_is_hw_shot_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 group, u32 bayer, u32 shot, u32 fcount, u32 rcount);
+int fimc_is_hw_s_camctrl_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 address, u32 fcount);
+
+/* func to register error report callback */
+int fimc_is_set_err_report_vendor(struct fimc_is_interface *itf,
+ void *err_report_data,
+ int (*err_report_vendor)(void *data, u32 err_report_type));
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#include <linux/exynos_iovmm.h>
+#else
+#include <plat/iovmm.h>
+#endif
+
+static void *fimc_is_ion_init(struct platform_device *pdev)
+{
+ return vb2_ion_create_context(&pdev->dev, SZ_4K,
+ VB2ION_CTX_IOMMU |
+ VB2ION_CTX_VMCONTIG |
+ VB2ION_CTX_KVA_ONDEMAND);
+}
+
+static unsigned long plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+
+static unsigned long plane_kvaddr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *kvaddr = vb2_plane_vaddr(vb, plane_no);
+
+ return (unsigned long)kvaddr;
+}
+
+const struct fimc_is_vb2 fimc_is_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = fimc_is_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = plane_addr,
+ .plane_kvaddr = plane_kvaddr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .set_cacheable = vb2_ion_set_cached,
+};
+
+int fimc_is_mem_probe(struct fimc_is_mem *this,
+ struct platform_device *pdev)
+{
+ u32 ret = 0;
+
+ this->vb2 = &fimc_is_vb2_ion;
+
+ this->alloc_ctx = this->vb2->init(pdev);
+ if (IS_ERR(this->alloc_ctx)) {
+ ret = PTR_ERR(this->alloc_ctx);
+ goto p_err;
+ }
+
+ /* FIXME: should be different by device type */
+ exynos_create_iovmm(&pdev->dev, 1, 4);
+
+p_err:
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_MEM_H
+#define FIMC_IS_MEM_H
+
+#include <linux/platform_device.h>
+#include <media/videobuf2-core.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+struct fimc_is_minfo {
+ dma_addr_t base; /* buffer base */
+ size_t size; /* total length */
+ dma_addr_t vaddr_base; /* buffer base */
+ dma_addr_t vaddr_curr; /* current addr */
+ void *bitproc_buf;
+ void *fw_cookie;
+
+ u32 dvaddr;
+ u32 kvaddr;
+ u32 dvaddr_debug;
+ u32 kvaddr_debug;
+ u32 dvaddr_fshared;
+ u32 kvaddr_fshared;
+ u32 dvaddr_region;
+ u32 kvaddr_region;
+ u32 dvaddr_shared; /*shared region of is region*/
+ u32 kvaddr_shared;
+ u32 dvaddr_odc;
+ u32 kvaddr_odc;
+ u32 dvaddr_dis;
+ u32 kvaddr_dis;
+ u32 dvaddr_3dnr;
+ u32 kvaddr_3dnr;
+};
+
+struct fimc_is_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct platform_device *pdev);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+ unsigned long (*plane_kvaddr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+};
+
+struct fimc_is_mem {
+ struct platform_device *pdev;
+ struct vb2_alloc_ctx *alloc_ctx;
+
+ const struct fimc_is_vb2 *vb2;
+};
+
+int fimc_is_mem_probe(struct fimc_is_mem *this,
+ struct platform_device *pdev);
+
+#endif
--- /dev/null
+/* Copyright (c) 2011 Samsung Electronics Co, Ltd.
+ *
+ * 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.
+
+ *
+
+ * Alternatively, Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ */
+
+#ifndef FIMC_IS_METADATA_H_
+#define FIMC_IS_METADATA_H_
+
+#ifndef _LINUX_TYPES_H
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#endif
+
+struct rational {
+ uint32_t num;
+ uint32_t den;
+};
+
+#define CAMERA2_MAX_AVAILABLE_MODE 21
+#define CAMERA2_MAX_FACES 16
+#define CAMERA2_MAX_VENDER_LENGTH 400
+#define CAPTURE_NODE_MAX 2
+#define CAMERA2_MAX_PDAF_MULTIROI_COLUMN 9
+#define CAMERA2_MAX_PDAF_MULTIROI_ROW 5
+
+#define OPEN_MAGIC_NUMBER 0x01020304
+#define SHOT_MAGIC_NUMBER 0x23456789
+
+/*
+ *controls/dynamic metadata
+*/
+
+/* android.request */
+
+enum metadata_mode {
+ METADATA_MODE_NONE,
+ METADATA_MODE_FULL
+};
+
+struct camera2_request_ctl {
+ uint32_t id;
+ enum metadata_mode metadataMode;
+ uint8_t outputStreams[16];
+ uint32_t frameCount;
+ uint32_t requestCount;
+};
+
+struct camera2_request_dm {
+ uint32_t id;
+ enum metadata_mode metadataMode;
+ uint32_t frameCount;
+ uint32_t requestCount;
+};
+
+struct camera2_entry_ctl {
+ /** \brief
+ per-frame control for entry control
+ \remarks
+ low parameter is 0bit ~ 31bit flag
+ high parameter is 32bit ~ 63bit flag
+ */
+ uint32_t lowIndexParam;
+ uint32_t highIndexParam;
+ uint32_t parameter[2048];
+};
+
+struct camera2_entry_dm {
+ uint32_t lowIndexParam;
+ uint32_t highIndexParam;
+};
+
+/* android.lens */
+
+enum optical_stabilization_mode {
+ OPTICAL_STABILIZATION_MODE_OFF = 1,
+ OPTICAL_STABILIZATION_MODE_ON = 2,
+ OPTICAL_STABILIZATION_MODE_STILL = 3, // Still mode
+ OPTICAL_STABILIZATION_MODE_STILL_ZOOM = 4, // Still Zoom mode
+ OPTICAL_STABILIZATION_MODE_VIDEO = 5, // Recording mode
+ OPTICAL_STABILIZATION_MODE_SINE_X = 6, // factory mode x
+ OPTICAL_STABILIZATION_MODE_SINE_Y = 7, // factory mode y
+ OPTICAL_STABILIZATION_MODE_CENTERING = 8 // Centering mode
+};
+
+enum lens_facing {
+ LENS_FACING_BACK,
+ LENS_FACING_FRONT
+};
+
+struct camera2_lens_ctl {
+ uint32_t focusDistance;
+ float aperture;
+ float focalLength;
+ float filterDensity;
+ enum optical_stabilization_mode opticalStabilizationMode;
+
+};
+
+struct camera2_lens_dm {
+ uint32_t focusDistance;
+ float aperture;
+ float focalLength;
+ float filterDensity;
+ enum optical_stabilization_mode opticalStabilizationMode;
+ float focusRange[2];
+};
+
+struct camera2_lens_sm {
+ float minimumFocusDistance;
+ float hyperfocalDistance;
+ float availableFocalLength[2];
+ float availableApertures;
+ /*assuming 1 aperture*/
+ float availableFilterDensities;
+ /*assuming 1 ND filter value*/
+ enum optical_stabilization_mode availableOpticalStabilization;
+ /*assuming 1*/
+ uint32_t shadingMapSize;
+ float shadingMap[3][40][30];
+ uint32_t geometricCorrectionMapSize;
+ float geometricCorrectionMap[2][3][40][30];
+ enum lens_facing facing;
+ float position[2];
+};
+
+/* android.sensor */
+
+enum sensor_colorfilterarrangement {
+ SENSOR_COLORFILTERARRANGEMENT_RGGB,
+ SENSOR_COLORFILTERARRANGEMENT_GRBG,
+ SENSOR_COLORFILTERARRANGEMENT_GBRG,
+ SENSOR_COLORFILTERARRANGEMENT_BGGR,
+ SENSOR_COLORFILTERARRANGEMENT_RGB
+};
+
+enum sensor_ref_illuminant {
+ SENSOR_ILLUMINANT_DAYLIGHT = 1,
+ SENSOR_ILLUMINANT_FLUORESCENT = 2,
+ SENSOR_ILLUMINANT_TUNGSTEN = 3,
+ SENSOR_ILLUMINANT_FLASH = 4,
+ SENSOR_ILLUMINANT_FINE_WEATHER = 9,
+ SENSOR_ILLUMINANT_CLOUDY_WEATHER = 10,
+ SENSOR_ILLUMINANT_SHADE = 11,
+ SENSOR_ILLUMINANT_DAYLIGHT_FLUORESCENT = 12,
+ SENSOR_ILLUMINANT_DAY_WHITE_FLUORESCENT = 13,
+ SENSOR_ILLUMINANT_COOL_WHITE_FLUORESCENT = 14,
+ SENSOR_ILLUMINANT_WHITE_FLUORESCENT = 15,
+ SENSOR_ILLUMINANT_STANDARD_A = 17,
+ SENSOR_ILLUMINANT_STANDARD_B = 18,
+ SENSOR_ILLUMINANT_STANDARD_C = 19,
+ SENSOR_ILLUMINANT_D55 = 20,
+ SENSOR_ILLUMINANT_D65 = 21,
+ SENSOR_ILLUMINANT_D75 = 22,
+ SENSOR_ILLUMINANT_D50 = 23,
+ SENSOR_ILLUMINANT_ISO_STUDIO_TUNGSTEN = 24
+};
+
+struct camera2_sensor_ctl {
+ /* unit : nano */
+ uint64_t exposureTime;
+ /* unit : nano(It's min frame duration */
+ uint64_t frameDuration;
+ /* unit : percent(need to change ISO value?) */
+ uint32_t sensitivity;
+};
+
+struct camera2_sensor_dm {
+ uint64_t exposureTime;
+ uint64_t frameDuration;
+ uint32_t sensitivity;
+ uint64_t timeStamp;
+ uint32_t analogGain;
+ uint32_t digitalGain;
+};
+
+struct camera2_sensor_sm {
+ uint32_t exposureTimeRange[2];
+ uint32_t maxFrameDuration;
+ /* list of available sensitivities. */
+ uint32_t availableSensitivities[10];
+ enum sensor_colorfilterarrangement colorFilterArrangement;
+ float physicalSize[2];
+ uint32_t pixelArraySize[2];
+ uint32_t activeArraySize[4];
+ uint32_t whiteLevel;
+ uint32_t blackLevelPattern[4];
+ struct rational colorTransform1[9];
+ struct rational colorTransform2[9];
+ enum sensor_ref_illuminant referenceIlluminant1;
+ enum sensor_ref_illuminant referenceIlluminant2;
+ struct rational forwardMatrix1[9];
+ struct rational forwardMatrix2[9];
+ struct rational calibrationTransform1[9];
+ struct rational calibrationTransform2[9];
+ struct rational baseGainFactor;
+ uint32_t maxAnalogSensitivity;
+ float noiseModelCoefficients[2];
+ uint32_t orientation;
+};
+
+
+
+/* android.flash */
+
+enum flash_mode {
+ CAM2_FLASH_MODE_OFF = 1,
+ CAM2_FLASH_MODE_SINGLE,
+ CAM2_FLASH_MODE_TORCH,
+ CAM2_FLASH_MODE_BEST
+};
+
+enum capture_state {
+ CAPTURE_STATE_NONE = 0,
+ CAPTURE_STATE_FLASH = 1,
+ CAPTURE_STATE_HDR_DARK = 12,
+ CAPTURE_STATE_HDR_NORMAL = 13,
+ CAPTURE_STATE_HDR_BRIGHT = 14,
+ CAPTURE_STATE_ZSL_LIKE = 20,
+};
+
+struct camera2_flash_ctl {
+ enum flash_mode flashMode;
+ uint32_t firingPower;
+ uint64_t firingTime;
+};
+
+struct camera2_flash_dm {
+ enum flash_mode flashMode;
+ /*10 is max power*/
+ uint32_t firingPower;
+ /*unit : microseconds*/
+ uint64_t firingTime;
+ /*1 : stable, 0 : unstable*/
+ uint32_t firingStable;
+ /*1 : success, 0 : fail*/
+ uint32_t decision;
+ /*0: None, 1 : pre, 2 : main flash ready*/
+ uint32_t flashReady;
+ /*0: None, 1 : pre, 2 : main flash off ready*/
+ uint32_t flashOffReady;
+};
+
+struct camera2_flash_sm {
+ uint32_t available;
+ uint64_t chargeDuration;
+};
+
+
+/* android.hotpixel */
+
+enum processing_mode {
+ PROCESSING_MODE_OFF = 1,
+ PROCESSING_MODE_FAST,
+ PROCESSING_MODE_HIGH_QUALITY
+};
+
+
+struct camera2_hotpixel_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_hotpixel_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.demosaic */
+
+struct camera2_demosaic_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_demosaic_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.noiseReduction */
+
+struct camera2_noisereduction_ctl {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+struct camera2_noisereduction_dm {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+
+
+/* android.shading */
+
+struct camera2_shading_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_shading_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.geometric */
+
+struct camera2_geometric_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_geometric_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.colorCorrection */
+
+enum colorcorrection_mode {
+ COLORCORRECTION_MODE_FAST = 1,
+ COLORCORRECTION_MODE_HIGH_QUALITY,
+ COLORCORRECTION_MODE_TRANSFORM_MATRIX,
+ COLORCORRECTION_MODE_EFFECT_MONO,
+ COLORCORRECTION_MODE_EFFECT_NEGATIVE,
+ COLORCORRECTION_MODE_EFFECT_SOLARIZE,
+ COLORCORRECTION_MODE_EFFECT_SEPIA,
+ COLORCORRECTION_MODE_EFFECT_POSTERIZE,
+ COLORCORRECTION_MODE_EFFECT_WHITEBOARD,
+ COLORCORRECTION_MODE_EFFECT_BLACKBOARD,
+ COLORCORRECTION_MODE_EFFECT_AQUA,
+ COLORCORRECTION_MODE_EFFECT_EMBOSS,
+ COLORCORRECTION_MODE_EFFECT_EMBOSS_MONO,
+ COLORCORRECTION_MODE_EFFECT_SKETCH,
+ COLORCORRECTION_MODE_EFFECT_RED_YELLOW_POINT,
+ COLORCORRECTION_MODE_EFFECT_GREEN_POINT,
+ COLORCORRECTION_MODE_EFFECT_BLUE_POINT,
+ COLORCORRECTION_MODE_EFFECT_MAGENTA_POINT,
+ COLORCORRECTION_MODE_EFFECT_WARM_VINTAGE,
+ COLORCORRECTION_MODE_EFFECT_COLD_VINTAGE,
+ COLORCORRECTION_MODE_EFFECT_WASHED,
+ COLORCORRECTION_MODE_EFFECT_BEAUTY_FACE,
+ TOTAOCOUNT_COLORCORRECTION_MODE_EFFECT
+};
+
+
+struct camera2_colorcorrection_ctl {
+ enum colorcorrection_mode mode;
+ float transform[9];
+ uint32_t hue;
+ uint32_t saturation;
+ uint32_t brightness;
+ uint32_t contrast;
+};
+
+struct camera2_colorcorrection_dm {
+ enum colorcorrection_mode mode;
+ float transform[9];
+ uint32_t hue;
+ uint32_t saturation;
+ uint32_t brightness;
+ uint32_t contrast;
+};
+
+struct camera2_colorcorrection_sm {
+ /*assuming 10 supported modes*/
+ uint8_t availableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ uint32_t hueRange[2];
+ uint32_t saturationRange[2];
+ uint32_t brightnessRange[2];
+ uint32_t contrastRange[2];
+};
+
+
+/* android.tonemap */
+
+enum tonemap_mode {
+ TONEMAP_MODE_FAST = 1,
+ TONEMAP_MODE_HIGH_QUALITY,
+ TONEMAP_MODE_CONTRAST_CURVE
+};
+
+struct camera2_tonemap_ctl {
+ enum tonemap_mode mode;
+ /* assuming maxCurvePoints = 64 */
+ float curveRed[64];
+ float curveGreen[64];
+ float curveBlue[64];
+};
+
+struct camera2_tonemap_dm {
+ enum tonemap_mode mode;
+ /* assuming maxCurvePoints = 64 */
+ float curveRed[64];
+ float curveGreen[64];
+ float curveBlue[64];
+};
+
+struct camera2_tonemap_sm {
+ uint32_t maxCurvePoints;
+};
+
+/* android.edge */
+
+struct camera2_edge_ctl {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+struct camera2_edge_dm {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+
+
+/* android.scaler */
+
+enum scaler_availableformats {
+ SCALER_FORMAT_BAYER_RAW,
+ SCALER_FORMAT_YV12,
+ SCALER_FORMAT_NV21,
+ SCALER_FORMAT_JPEG,
+ SCALER_FORMAT_UNKNOWN
+};
+
+struct camera2_scaler_ctl {
+ uint32_t cropRegion[4];
+ uint32_t orientation;
+};
+
+struct camera2_scaler_dm {
+ uint32_t cropRegion[4];
+ uint32_t orientation;
+};
+
+struct camera2_scaler_sm {
+ enum scaler_availableformats availableFormats[4];
+ /*assuming # of availableFormats = 4*/
+ uint32_t availableRawSizes;
+ uint64_t availableRawMinDurations;
+ /* needs check */
+ uint32_t availableProcessedSizes[8];
+ uint64_t availableProcessedMinDurations[8];
+ uint32_t availableJpegSizes[8][2];
+ uint64_t availableJpegMinDurations[8];
+ uint32_t availableMaxDigitalZoom[8];
+};
+
+/* android.jpeg */
+struct camera2_jpeg_ctl {
+ uint32_t quality;
+ uint32_t thumbnailSize[2];
+ uint32_t thumbnailQuality;
+ double gpsCoordinates[3];
+ uint32_t gpsProcessingMethod;
+ uint64_t gpsTimestamp;
+ uint32_t orientation;
+};
+
+struct camera2_jpeg_dm {
+ uint32_t quality;
+ uint32_t thumbnailSize[2];
+ uint32_t thumbnailQuality;
+ double gpsCoordinates[3];
+ uint32_t gpsProcessingMethod;
+ uint64_t gpsTimestamp;
+ uint32_t orientation;
+};
+
+struct camera2_jpeg_sm {
+ uint32_t availableThumbnailSizes[8][2];
+ uint32_t maxSize;
+ /*assuming supported size=8*/
+};
+
+
+
+/* android.statistics */
+
+enum facedetect_mode {
+ FACEDETECT_MODE_OFF = 1,
+ FACEDETECT_MODE_SIMPLE,
+ FACEDETECT_MODE_FULL
+};
+
+enum stats_mode {
+ STATS_MODE_OFF = 1,
+ STATS_MODE_ON
+};
+
+enum stats_lowlightmode {
+ STATE_LLS_LEVEL_ZSL = 0,
+ STATE_LLS_LEVEL_LOW = 1,
+ STATE_LLS_LEVEL_HIGH = 2,
+ STATE_LLS_LEVEL_SIS = 3,
+ STATE_LLS_LEVEL_ZSL_LIKE = 4,
+ STATE_LLS_LEVEL_ZSL_FLASH = 16,
+};
+
+struct camera2_stats_ctl {
+ enum facedetect_mode faceDetectMode;
+ enum stats_mode histogramMode;
+ enum stats_mode sharpnessMapMode;
+};
+
+
+struct camera2_stats_dm {
+ enum facedetect_mode faceDetectMode;
+ uint32_t faceRectangles[CAMERA2_MAX_FACES][4];
+ uint8_t faceScores[CAMERA2_MAX_FACES];
+ uint32_t faceLandmarks[CAMERA2_MAX_FACES][6];
+ uint32_t faceIds[CAMERA2_MAX_FACES];
+/* PAYTON_CHECK_20120712 : histogram_mode -> stats_mode */
+ enum stats_mode histogramMode;
+/* [hj529.kim, 2012/07/19] androd.statistics.histogram */
+ uint32_t histogram[3 * 256];
+/* PAYTON_CHECK_20120712 : sharpnessmap_mode -> stats_mode */
+ enum stats_mode sharpnessMapMode;
+ /*sharpnessMap*/
+ enum stats_lowlightmode LowLightMode;
+ uint32_t lls_tuning_set_index;
+ uint32_t lls_brightness_index;
+};
+
+
+struct camera2_stats_sm {
+ uint8_t availableFaceDetectModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming supported modes = 3;*/
+ uint32_t maxFaceCount;
+ uint32_t histogramBucketCount;
+ uint32_t maxHistogramCount;
+ uint32_t sharpnessMapSize[2];
+ uint32_t maxSharpnessMapValue;
+};
+
+/* android.control */
+
+enum aa_capture_intent {
+ AA_CAPTURE_INTENT_CUSTOM = 0,
+ AA_CAPTURE_INTENT_PREVIEW,
+ AA_CAPTURE_INTENT_STILL_CAPTURE,
+ AA_CAPTURE_INTENT_VIDEO_RECORD,
+ AA_CAPTURE_INTENT_VIDEO_SNAPSHOT,
+ AA_CAPTURE_INTENT_ZERO_SHUTTER_LAG,
+ AA_CAPTURE_INTENT_STILL_CAPTURE_OIS_SINGLE,
+ AA_CAPTURE_INTENT_STILL_CAPTURE_OIS_MULTI
+};
+
+enum aa_mode {
+ AA_CONTROL_OFF = 1,
+ AA_CONTROL_AUTO,
+ AA_CONTROL_USE_SCENE_MODE
+};
+
+enum aa_scene_mode {
+ AA_SCENE_MODE_UNSUPPORTED = 1,
+ AA_SCENE_MODE_FACE_PRIORITY,
+ AA_SCENE_MODE_ACTION,
+ AA_SCENE_MODE_PORTRAIT,
+ AA_SCENE_MODE_LANDSCAPE,
+ AA_SCENE_MODE_NIGHT,
+ AA_SCENE_MODE_NIGHT_PORTRAIT,
+ AA_SCENE_MODE_THEATRE,
+ AA_SCENE_MODE_BEACH,
+ AA_SCENE_MODE_SNOW,
+ AA_SCENE_MODE_SUNSET,
+ AA_SCENE_MODE_STEADYPHOTO,
+ AA_SCENE_MODE_FIREWORKS,
+ AA_SCENE_MODE_SPORTS,
+ AA_SCENE_MODE_PARTY,
+ AA_SCENE_MODE_CANDLELIGHT,
+ AA_SCENE_MODE_BARCODE,
+ AA_SCENE_MODE_NIGHT_CAPTURE,
+ AA_SCENE_MODE_ANTISHAKE,
+ AA_SCENE_MODE_HDR,
+ AA_SCENE_MODE_LLS,
+ AA_SCENE_MODE_FDAE,
+ AA_SCENE_MODE_DUAL,
+ AA_SCENE_MODE_DRAMA,
+ AA_SCENE_MODE_ANIMATED,
+ AA_SCENE_MODE_PANORAMA,
+ AA_SCENE_MODE_GOLF,
+ AA_SCENE_MODE_PREVIEW,
+ AA_SCENE_MODE_VIDEO,
+ AA_SCENE_MODE_SLOWMOTION_2,
+ AA_SCENE_MODE_SLOWMOTION_4_8,
+ AA_SCENE_MODE_DUAL_PREVIEW,
+ AA_SCENE_MODE_DUAL_VIDEO,
+ AA_SCENE_MODE_120_PREVIEW,
+ AA_SCENE_MODE_LIGHT_TRACE
+};
+
+enum aa_effect_mode {
+ AA_EFFECT_OFF = 1,
+ AA_EFFECT_MONO,
+ AA_EFFECT_NEGATIVE,
+ AA_EFFECT_SOLARIZE,
+ AA_EFFECT_SEPIA,
+ AA_EFFECT_POSTERIZE,
+ AA_EFFECT_WHITEBOARD,
+ AA_EFFECT_BLACKBOARD,
+ AA_EFFECT_AQUA
+};
+
+enum aa_aemode {
+ AA_AEMODE_OFF = 1,
+ AA_AEMODE_LOCKED,
+ AA_AEMODE_CENTER,
+ AA_AEMODE_AVERAGE,
+ AA_AEMODE_MATRIX,
+ AA_AEMODE_SPOT,
+ AA_AEMODE_CENTER_TOUCH,
+ AA_AEMODE_AVERAGE_TOUCH,
+ AA_AEMODE_MATRIX_TOUCH,
+ AA_AEMODE_SPOT_TOUCH
+};
+
+enum aa_ae_flashmode {
+ /*all flash control stop*/
+ AA_FLASHMODE_OFF = 1,
+ /*flash start*/
+ AA_FLASHMODE_START,
+ /*flash cancle*/
+ AA_FLASHMODE_CANCLE,
+ /*internal 3A can control flash*/
+ AA_FLASHMODE_ON,
+ /*internal 3A can do auto flash algorithm*/
+ AA_FLASHMODE_AUTO,
+ /*internal 3A can fire flash by auto result*/
+ AA_FLASHMODE_CAPTURE,
+ /*internal 3A can control flash forced*/
+ AA_FLASHMODE_ON_ALWAYS
+};
+
+enum aa_ae_antibanding_mode {
+ AA_AE_ANTIBANDING_OFF = 1,
+ AA_AE_ANTIBANDING_50HZ,
+ AA_AE_ANTIBANDING_60HZ,
+ AA_AE_ANTIBANDING_AUTO,
+ AA_AE_ANTIBANDING_AUTO_50HZ, /*50Hz + Auto*/
+ AA_AE_ANTIBANDING_AUTO_60HZ /*60Hz + Auto*/
+};
+
+enum aa_awbmode {
+ AA_AWBMODE_OFF = 1,
+ AA_AWBMODE_LOCKED,
+ AA_AWBMODE_WB_AUTO,
+ AA_AWBMODE_WB_INCANDESCENT,
+ AA_AWBMODE_WB_FLUORESCENT,
+ AA_AWBMODE_WB_WARM_FLUORESCENT,
+ AA_AWBMODE_WB_DAYLIGHT,
+ AA_AWBMODE_WB_CLOUDY_DAYLIGHT,
+ AA_AWBMODE_WB_TWILIGHT,
+ AA_AWBMODE_WB_SHADE
+};
+
+enum aa_afmode {
+ /* These modes are adjusted immediatly */
+ AA_AFMODE_OFF = 1,
+ AA_AFMODE_SLEEP,
+ AA_AFMODE_INFINITY,
+ AA_AFMODE_MACRO,
+ AA_AFMODE_DELAYED_OFF,
+
+ /* Single AF. These modes are adjusted when afTrigger is changed from 0 to 1 */
+ AA_AFMODE_AUTO = 11,
+ AA_AFMODE_AUTO_MACRO,
+ AA_AFMODE_AUTO_VIDEO,
+ AA_AFMODE_AUTO_FACE,
+
+ /* Continuous AF. These modes are adjusted when afTrigger is changed from 0 to 1 */
+ AA_AFMODE_CONTINUOUS_PICTURE = 21,
+ AA_AFMODE_CONTINUOUS_VIDEO,
+ AA_AFMODE_CONTINUOUS_PICTURE_FACE,
+
+ /* Special modes for PDAF */
+ AA_AFMODE_PDAF_OUTFOCUSING = 31,
+ AA_AFMODE_PDAF_OUTFOCUSING_FACE,
+ AA_AFMODE_PDAF_OUTFOCUSING_CONTINUOUS_PICTURE,
+ AA_AFMODE_PDAF_OUTFOCUSING_CONTINUOUS_PICTURE_FACE,
+
+ /* Not supported yet */
+ AA_AFMODE_EDOF = 41,
+};
+
+/* camera2_aa_ctl.afRegions[4] */
+enum aa_afmode_ext {
+ AA_AFMODE_EXT_OFF = 1000,
+ /* Increase macro range for special app */
+ AA_AFMODE_EXT_ADVANCED_MACRO_FOCUS = 1001,
+ /* Set AF region for OCR */
+ AA_AFMODE_EXT_FOCUS_LOCATION = 1002,
+};
+
+enum aa_afstate {
+ AA_AFSTATE_INACTIVE = 1,
+ AA_AFSTATE_PASSIVE_SCAN,
+ AA_AFSTATE_ACTIVE_SCAN,
+ AA_AFSTATE_AF_ACQUIRED_FOCUS,
+ AA_AFSTATE_AF_FAILED_FOCUS
+};
+
+enum ae_state {
+ AE_STATE_INACTIVE = 1,
+ AE_STATE_SEARCHING,
+ AE_STATE_CONVERGED,
+ AE_STATE_LOCKED,
+ AE_STATE_FLASH_REQUIRED,
+ AE_STATE_PRECAPTURE
+};
+
+enum awb_state {
+ AWB_STATE_INACTIVE = 1,
+ AWB_STATE_SEARCHING,
+ AWB_STATE_CONVERGED,
+ AWB_STATE_LOCKED
+};
+
+enum aa_isomode {
+ AA_ISOMODE_AUTO = 1,
+ AA_ISOMODE_MANUAL,
+};
+
+struct camera2_aa_ctl {
+ enum aa_capture_intent captureIntent;
+ enum aa_mode mode;
+ /*enum aa_effect_mode effectMode;*/
+ enum aa_scene_mode sceneMode;
+ uint32_t videoStabilizationMode;
+ enum aa_aemode aeMode;
+ uint32_t aeRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ int32_t aeExpCompensation;
+ uint32_t aeTargetFpsRange[2];
+ enum aa_ae_antibanding_mode aeAntibandingMode;
+ enum aa_ae_flashmode aeflashMode;
+ enum aa_awbmode awbMode;
+ uint32_t awbRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ enum aa_afmode afMode;
+ uint32_t afRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ uint32_t afTrigger;
+ enum aa_isomode isoMode;
+ uint32_t isoValue;
+ int32_t awbValue;
+ uint32_t reserved[10];
+};
+
+struct camera2_aa_dm {
+ enum aa_mode mode;
+ enum aa_effect_mode effectMode;
+ enum aa_scene_mode sceneMode;
+ uint32_t videoStabilizationMode;
+ enum aa_aemode aeMode;
+ /*needs check*/
+ uint32_t aeRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ enum ae_state aeState;
+ enum aa_ae_flashmode aeflashMode;
+ /*needs check*/
+ enum aa_awbmode awbMode;
+ uint32_t awbRegions[5];
+ enum awb_state awbState;
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ enum aa_afmode afMode;
+ uint32_t afRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region*/
+ enum aa_afstate afState;
+ enum aa_isomode isoMode;
+ uint32_t isoValue;
+ uint32_t reserved[10];
+};
+
+struct camera2_aa_sm {
+ uint8_t availableSceneModes[CAMERA2_MAX_AVAILABLE_MODE];
+ uint8_t availableEffects[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of available scene modes = 10*/
+ uint32_t maxRegions;
+ uint8_t aeAvailableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of available ae modes = 8*/
+ struct rational aeCompensationStep;
+ int32_t aeCompensationRange[2];
+ uint32_t aeAvailableTargetFpsRanges[CAMERA2_MAX_AVAILABLE_MODE][2];
+ uint8_t aeAvailableAntibandingModes[CAMERA2_MAX_AVAILABLE_MODE];
+ uint8_t awbAvailableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of awbAvailableModes = 10*/
+ uint8_t afAvailableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of afAvailableModes = 4*/
+ uint8_t availableVideoStabilizationModes[4];
+ /*assuming # of availableVideoStabilizationModes = 4*/
+ uint32_t isoRange[2];
+};
+
+struct camera2_lens_usm {
+ /** Frame delay between sending command and applying frame data */
+ uint32_t focusDistanceFrameDelay;
+};
+
+struct camera2_sensor_usm {
+ /** Frame delay between sending command and applying frame data */
+ uint32_t exposureTimeFrameDelay;
+ uint32_t frameDurationFrameDelay;
+ uint32_t sensitivityFrameDelay;
+};
+
+struct camera2_flash_usm {
+ /** Frame delay between sending command and applying frame data */
+ uint32_t flashModeFrameDelay;
+ uint32_t firingPowerFrameDelay;
+ uint64_t firingTimeFrameDelay;
+};
+
+struct camera2_ctl {
+ struct camera2_request_ctl request;
+ struct camera2_lens_ctl lens;
+ struct camera2_sensor_ctl sensor;
+ struct camera2_flash_ctl flash;
+ struct camera2_hotpixel_ctl hotpixel;
+ struct camera2_demosaic_ctl demosaic;
+ struct camera2_noisereduction_ctl noise;
+ struct camera2_shading_ctl shading;
+ struct camera2_geometric_ctl geometric;
+ struct camera2_colorcorrection_ctl color;
+ struct camera2_tonemap_ctl tonemap;
+ struct camera2_edge_ctl edge;
+ struct camera2_scaler_ctl scaler;
+ struct camera2_jpeg_ctl jpeg;
+ struct camera2_stats_ctl stats;
+ struct camera2_aa_ctl aa;
+ struct camera2_entry_ctl entry;
+};
+
+struct camera2_dm {
+ struct camera2_request_dm request;
+ struct camera2_lens_dm lens;
+ struct camera2_sensor_dm sensor;
+ struct camera2_flash_dm flash;
+ struct camera2_hotpixel_dm hotpixel;
+ struct camera2_demosaic_dm demosaic;
+ struct camera2_noisereduction_dm noise;
+ struct camera2_shading_dm shading;
+ struct camera2_geometric_dm geometric;
+ struct camera2_colorcorrection_dm color;
+ struct camera2_tonemap_dm tonemap;
+ struct camera2_edge_dm edge;
+ struct camera2_scaler_dm scaler;
+ struct camera2_jpeg_dm jpeg;
+ struct camera2_stats_dm stats;
+ struct camera2_aa_dm aa;
+ struct camera2_entry_dm entry;
+};
+
+struct camera2_sm {
+ struct camera2_lens_sm lens;
+ struct camera2_sensor_sm sensor;
+ struct camera2_flash_sm flash;
+ struct camera2_colorcorrection_sm color;
+ struct camera2_tonemap_sm tonemap;
+ struct camera2_scaler_sm scaler;
+ struct camera2_jpeg_sm jpeg;
+ struct camera2_stats_sm stats;
+ struct camera2_aa_sm aa;
+
+ /** User-defined(ispfw specific) static metadata. */
+ struct camera2_lens_usm lensUd;
+ struct camera2_sensor_usm sensorUd;
+ struct camera2_flash_usm flashUd;
+};
+
+/** \brief
+ User-defined control for lens.
+*/
+struct camera2_lens_uctl {
+ struct camera2_lens_ctl ctl;
+
+ /** It depends by posSize */
+ uint32_t pos;
+ /** It depends by af algorithm(AF pos bit. normally 8 or 9 or 10) */
+ uint32_t posSize;
+ /** It depends by af algorithm */
+ uint32_t direction;
+ /** Some actuator support slew rate control. */
+ uint32_t slewRate;
+};
+
+/** \brief
+ User-defined metadata for lens.
+*/
+struct camera2_lens_udm {
+ /** It depends by posSize */
+ uint32_t pos;
+ /** It depends by af algorithm(AF pos bit. normally 8 or 9 or 10) */
+ uint32_t posSize;
+ /** It depends by af algorithm */
+ uint32_t direction;
+ /** Some actuator support slew rate control. */
+ uint32_t slewRate;
+};
+
+/** \brief
+ User-defined metadata for ae.
+*/
+struct camera2_ae_udm {
+ /** vendor specific length */
+ uint32_t vsLength;
+ /** vendor specific data array */
+ uint32_t vendorSpecific[CAMERA2_MAX_VENDER_LENGTH];
+};
+
+/** \brief
+ User-defined metadata for awb.
+*/
+struct camera2_awb_udm {
+ /** vendor specific length */
+ uint32_t vsLength;
+ /** vendor specific data array */
+ uint32_t vendorSpecific[CAMERA2_MAX_VENDER_LENGTH];
+};
+
+/** \brief
+ User-defined metadata for af.
+*/
+struct camera2_af_udm {
+ /** vendor specific length */
+ uint32_t vsLength;
+ /** vendor specific data array */
+ uint32_t vendorSpecific[CAMERA2_MAX_VENDER_LENGTH];
+ int32_t lensPositionInfinity;
+ int32_t lensPositionMacro;
+ int32_t lensPositionCurrent;
+};
+
+/** \brief
+ User-defined metadata for anti-shading.
+*/
+struct camera2_as_udm {
+ /** vendor specific length */
+ uint32_t vsLength;
+ /** vendor specific data array */
+ uint32_t vendorSpecific[CAMERA2_MAX_VENDER_LENGTH];
+};
+
+/** \brief
+ User-defined metadata for anti-shading.
+*/
+struct camera2_ipc_udm {
+ /** vendor specific length */
+ uint32_t vsLength;
+ /** vendor specific data array */
+ uint32_t vendorSpecific[CAMERA2_MAX_VENDER_LENGTH];
+};
+
+/** \brief
+ User-defined metadata for aa.
+*/
+struct camera2_internal_udm {
+ /** vendor specific data array */
+ uint32_t vendorSpecific1[CAMERA2_MAX_VENDER_LENGTH];
+ uint32_t vendorSpecific2[CAMERA2_MAX_VENDER_LENGTH];
+ /*
+ * vendorSpecific2[0] : info
+ * vendorSpecific2[100] : 0:sirc 1:cml
+ * vendorSpecific2[101] : cml exposure
+ * vendorSpecific2[102] : cml iso(gain)
+ * vendorSpecific2[103] : cml Bv
+ */
+};
+
+/** \brief
+ User-defined control for sensor.
+*/
+struct camera2_sensor_uctl {
+ struct camera2_sensor_ctl ctl;
+ /** Dynamic frame duration.
+ This feature is decided to max. value between
+ 'sensor.exposureTime'+alpha and 'sensor.frameDuration'.
+ */
+ uint64_t dynamicFrameDuration;
+ uint32_t analogGain;
+ uint32_t digitalGain;
+ uint64_t longExposureTime; /* For supporting WDR */
+ uint64_t shortExposureTime;
+ uint32_t longAnalogGain;
+ uint32_t shortAnalogGain;
+ uint32_t longDigitalGain;
+ uint32_t shortDigitalGain;
+};
+
+struct camera2_scaler_uctl {
+ /** \brief
+ target address for next frame.
+ \remarks
+ [0] invalid address, stop
+ [others] valid address
+ */
+ uint32_t sccTargetAddress[4];
+ uint32_t scpTargetAddress[4];
+ uint32_t disTargetAddress[4];
+ uint32_t taapTargetAddress[4]; /* 3AA preview DMA */
+ uint32_t taacTargetAddress[4]; /* 3AA capture DMA */
+ uint32_t orientation;
+};
+
+struct camera2_flash_uctl {
+ struct camera2_flash_ctl ctl;
+};
+
+struct camera2_bayer_uctl {
+ struct camera2_scaler_ctl ctl;
+};
+
+enum companion_drc_mode {
+ COMPANION_DRC_OFF = 1,
+ COMPANION_DRC_ON,
+};
+
+enum companion_wdr_mode {
+ COMPANION_WDR_OFF = 1,
+ COMPANION_WDR_ON,
+};
+
+enum companion_paf_mode {
+ COMPANION_PAF_OFF = 1,
+ COMPANION_PAF_ON,
+};
+
+enum companion_bypass_mode {
+ COMPANION_FULL_BYPASS_OFF = 1,
+ COMPANION_FULL_BYPASS_ON,
+};
+
+enum companion_lsc_mode {
+ COMPANION_LSC_OFF = 1,
+ COMPANION_LSC_ON,
+};
+
+struct camera2_companion_uctl {
+ enum companion_drc_mode drc_mode;
+ enum companion_wdr_mode wdr_mode;
+ enum companion_paf_mode paf_mode;
+};
+
+struct camera2_bayer_udm {
+ uint32_t width;
+ uint32_t height;
+};
+
+struct camera2_pdaf_single_result {
+ uint16_t mode;
+ uint16_t goalPos;
+ uint16_t reliability;
+ uint16_t currentPos;
+};
+
+struct camera2_pdaf_multi_result {
+ uint16_t mode;
+ uint16_t goalPos;
+ uint16_t reliability;
+};
+
+struct camera2_pdaf_udm {
+ uint16_t numCol; /* width of PDAF map, 0 means no multi PDAF data */
+ uint16_t numRow; /* height of PDAF map, 0 means no multi PDAF data */
+ struct camera2_pdaf_multi_result multiResult[CAMERA2_MAX_PDAF_MULTIROI_COLUMN][CAMERA2_MAX_PDAF_MULTIROI_ROW];
+ struct camera2_pdaf_single_result singleResult;
+ uint16_t lensPosResolution; /* 1023(unsigned 10bit) */
+};
+
+struct camera2_companion_udm {
+ enum companion_drc_mode drc_mode;
+ enum companion_wdr_mode wdr_mode;
+ enum companion_paf_mode paf_mode;
+ struct camera2_pdaf_udm pdaf;
+};
+
+/** \brief
+ User-defined control area.
+ \remarks
+ sensor, lens, flash category is empty value.
+ It should be filled by a5 for SET_CAM_CONTROL command.
+ Other category is filled already from host.
+*/
+struct camera2_uctl {
+ /** \brief
+ Set sensor, lens, flash control for next frame.
+ \remarks
+ This flag can be combined.
+ [0 bit] lens
+ [1 bit] sensor
+ [2 bit] flash
+ */
+ uint32_t uUpdateBitMap;
+
+ /** For debugging */
+ uint32_t uFrameNumber;
+
+ /** ispfw specific control(user-defined) of lens. */
+ struct camera2_lens_uctl lensUd;
+ /** ispfw specific control(user-defined) of sensor. */
+ struct camera2_sensor_uctl sensorUd;
+ /** ispfw specific control(user-defined) of flash. */
+ struct camera2_flash_uctl flashUd;
+
+ struct camera2_scaler_uctl scalerUd;
+ /** ispfw specific control(user-defined) of Bcrop1. */
+ struct camera2_bayer_uctl bayerUd;
+ struct camera2_companion_uctl companionUd;
+ uint32_t reserved[10];
+};
+
+struct camera2_udm {
+ struct camera2_lens_udm lens;
+ struct camera2_ae_udm ae;
+ struct camera2_awb_udm awb;
+ struct camera2_af_udm af;
+ struct camera2_as_udm as;
+ struct camera2_ipc_udm ipc;
+ /* KJ_121129 : Add udm for sirc sdk. */
+ struct camera2_internal_udm internal;
+ /* Add udm for bayer down size. */
+ struct camera2_bayer_udm bayer;
+ struct camera2_companion_udm companion;
+ uint32_t reserved[10];
+};
+
+struct camera2_shot {
+ /*google standard area*/
+ struct camera2_ctl ctl;
+ struct camera2_dm dm;
+ /*user defined area*/
+ struct camera2_uctl uctl;
+ struct camera2_udm udm;
+ /*magic : 23456789*/
+ uint32_t magicNumber;
+};
+
+struct camera2_node_input {
+ /** \brief
+ intput crop region
+ \remarks
+ [0] x axis
+ [1] y axie
+ [2] width
+ [3] height
+ */
+ uint32_t cropRegion[4];
+};
+
+struct camera2_node_output {
+ /** \brief
+ output crop region
+ \remarks
+ [0] x axis
+ [1] y axie
+ [2] width
+ [3] height
+ */
+ uint32_t cropRegion[4];
+};
+
+struct camera2_node {
+ /** \brief
+ video node id
+ \remarks
+ [x] video node id
+ */
+ uint32_t vid;
+
+ /** \brief
+ stream control
+ \remarks
+ [0] disable stream out
+ [1] enable stream out
+ */
+ uint32_t request;
+
+ struct camera2_node_input input;
+ struct camera2_node_output output;
+};
+
+struct camera2_node_group {
+ /** \brief
+ output device node
+ \remarks
+ this node can pull in image
+ */
+ struct camera2_node leader;
+
+ /** \brief
+ capture node list
+ \remarks
+ this node can get out image
+ 3AAC, 3AAP, SCC, SCP, VDISC
+ */
+ struct camera2_node capture[CAPTURE_NODE_MAX];
+};
+
+/** \brief
+ Structure for interfacing between HAL and driver.
+*/
+struct camera2_shot_ext {
+ /*
+ * ---------------------------------------------------------------------
+ * HAL Control Part
+ * ---------------------------------------------------------------------
+ */
+
+ /** \brief
+ setfile change
+ \remarks
+ [x] mode for setfile
+ */
+ uint32_t setfile;
+
+ /** \brief
+ node group control
+ \remarks
+ per frame control
+ */
+ struct camera2_node_group node_group;
+
+ /** \brief
+ post processing control(DRC)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t drc_bypass;
+
+ /** \brief
+ post processing control(DIS)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t dis_bypass;
+
+ /** \brief
+ post processing control(3DNR)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t dnr_bypass;
+
+ /** \brief
+ post processing control(FD)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t fd_bypass;
+
+ /*
+ * ---------------------------------------------------------------------
+ * DRV Control Part
+ * ---------------------------------------------------------------------
+ */
+
+ /** \brief
+ requested frames state.
+ driver return the information everytime
+ when dequeue is requested.
+ \remarks
+ [X] count
+ */
+ uint32_t free_cnt;
+ uint32_t request_cnt;
+ uint32_t process_cnt;
+ uint32_t complete_cnt;
+
+ /* reserved for future */
+ uint32_t reserved[15];
+
+ /** \brief
+ processing time debugging
+ \remarks
+ taken time(unit : struct timeval)
+ [0][x] flite start
+ [1][x] flite end
+ [2][x] DRV Shot
+ [3][x] DRV Shot done
+ [4][x] DRV Meta done
+ */
+ uint32_t timeZone[10][2];
+
+ /*
+ * ---------------------------------------------------------------------
+ * Camera API
+ * ---------------------------------------------------------------------
+ */
+
+ struct camera2_shot shot;
+};
+
+/** \brief
+ stream structure for scaler.
+*/
+struct camera2_stream {
+ /** \brief
+ this address for verifying conincidence of index and address
+ \remarks
+ [X] kernel virtual address for this buffer
+ */
+ uint32_t address;
+
+ /** \brief
+ this frame count is from FLITE through dm.request.fcount,
+ this count increases every frame end. initial value is 1.
+ \remarks
+ [X] frame count
+ */
+ uint32_t fcount;
+
+ /** \brief
+ this request count is from HAL through ctl.request.fcount,
+ this count is the unique.
+ \remarks
+ [X] request count
+ */
+ uint32_t rcount;
+
+ /** \brief
+ frame index of isp framemgr.
+ this value is for driver internal debugging
+ \remarks
+ [X] frame index
+ */
+ uint32_t findex;
+
+ /** \brief
+ frame validation of isp framemgr.
+ this value is for driver and HAL internal debugging
+ \remarks
+ [X] frame valid
+ */
+ uint32_t fvalid;
+
+ /** \brief
+ output crop region
+ this value mean the output image places the axis of memory space
+ \remarks
+ [0] crop x axis
+ [1] crop y axis
+ [2] width
+ [3] height
+ */
+ uint32_t input_crop_region[4];
+ uint32_t output_crop_region[4];
+};
+
+#define CAM_LENS_CMD (0x1 << 0x0)
+#define CAM_SENSOR_CMD (0x1 << 0x1)
+#define CAM_FLASH_CMD (0x1 << 0x2)
+
+/* typedefs below are for firmware sources */
+
+typedef enum metadata_mode metadata_mode_t;
+typedef struct camera2_request_ctl camera2_request_ctl_t;
+typedef struct camera2_request_dm camera2_request_dm_t;
+typedef enum optical_stabilization_mode optical_stabilization_mode_t;
+typedef enum lens_facing lens_facing_t;
+typedef struct camera2_entry_ctl camera2_entry_ctl_t;
+typedef struct camera2_entry_dm camera2_entry_dm_t;
+typedef struct camera2_lens_ctl camera2_lens_ctl_t;
+typedef struct camera2_lens_dm camera2_lens_dm_t;
+typedef struct camera2_lens_sm camera2_lens_sm_t;
+typedef enum sensor_colorfilterarrangement sensor_colorfilterarrangement_t;
+typedef enum sensor_ref_illuminant sensor_ref_illuminant_t;
+typedef struct camera2_sensor_ctl camera2_sensor_ctl_t;
+typedef struct camera2_sensor_dm camera2_sensor_dm_t;
+typedef struct camera2_sensor_sm camera2_sensor_sm_t;
+typedef enum flash_mode flash_mode_t;
+typedef struct camera2_flash_ctl camera2_flash_ctl_t;
+typedef struct camera2_flash_dm camera2_flash_dm_t;
+typedef struct camera2_flash_sm camera2_flash_sm_t;
+typedef enum processing_mode processing_mode_t;
+typedef struct camera2_hotpixel_ctl camera2_hotpixel_ctl_t;
+typedef struct camera2_hotpixel_dm camera2_hotpixel_dm_t;
+
+typedef struct camera2_demosaic_ctl camera2_demosaic_ctl_t;
+typedef struct camera2_demosaic_dm camera2_demosaic_dm_t;
+typedef struct camera2_noisereduction_ctl camera2_noisereduction_ctl_t;
+typedef struct camera2_noisereduction_dm camera2_noisereduction_dm_t;
+typedef struct camera2_shading_ctl camera2_shading_ctl_t;
+typedef struct camera2_shading_dm camera2_shading_dm_t;
+typedef struct camera2_geometric_ctl camera2_geometric_ctl_t;
+typedef struct camera2_geometric_dm camera2_geometric_dm_t;
+typedef enum colorcorrection_mode colorcorrection_mode_t;
+typedef struct camera2_colorcorrection_ctl camera2_colorcorrection_ctl_t;
+typedef struct camera2_colorcorrection_dm camera2_colorcorrection_dm_t;
+typedef struct camera2_colorcorrection_sm camera2_colorcorrection_sm_t;
+typedef enum tonemap_mode tonemap_mode_t;
+typedef struct camera2_tonemap_ctl camera2_tonemap_ctl_t;
+typedef struct camera2_tonemap_dm camera2_tonemap_dm_t;
+typedef struct camera2_tonemap_sm camera2_tonemap_sm_t;
+
+typedef struct camera2_edge_ctl camera2_edge_ctl_t;
+typedef struct camera2_edge_dm camera2_edge_dm_t;
+typedef enum scaler_availableformats scaler_availableformats_t;
+typedef struct camera2_scaler_ctl camera2_scaler_ctl_t;
+typedef struct camera2_scaler_dm camera2_scaler_dm_t;
+typedef struct camera2_jpeg_ctl camera2_jpeg_ctl_t;
+typedef struct camera2_jpeg_dm camera2_jpeg_dm_t;
+typedef struct camera2_jpeg_sm camera2_jpeg_sm_t;
+typedef enum facedetect_mode facedetect_mode_t;
+typedef enum stats_mode stats_mode_t;
+typedef struct camera2_stats_ctl camera2_stats_ctl_t;
+typedef struct camera2_stats_dm camera2_stats_dm_t;
+typedef struct camera2_stats_sm camera2_stats_sm_t;
+typedef enum aa_capture_intent aa_capture_intent_t;
+typedef enum aa_mode aa_mode_t;
+typedef enum aa_scene_mode aa_scene_mode_t;
+typedef enum aa_effect_mode aa_effect_mode_t;
+typedef enum aa_aemode aa_aemode_t;
+typedef enum aa_ae_antibanding_mode aa_ae_antibanding_mode_t;
+typedef enum aa_awbmode aa_awbmode_t;
+typedef enum aa_afmode aa_afmode_t;
+typedef enum aa_afstate aa_afstate_t;
+typedef struct camera2_aa_ctl camera2_aa_ctl_t;
+typedef struct camera2_aa_dm camera2_aa_dm_t;
+typedef struct camera2_aa_sm camera2_aa_sm_t;
+typedef struct camera2_lens_usm camera2_lens_usm_t;
+typedef struct camera2_sensor_usm camera2_sensor_usm_t;
+typedef struct camera2_flash_usm camera2_flash_usm_t;
+typedef struct camera2_ctl camera2_ctl_t;
+typedef struct camera2_uctl camera2_uctl_t;
+typedef struct camera2_dm camera2_dm_t;
+typedef struct camera2_sm camera2_sm_t;
+
+typedef struct camera2_scaler_sm camera2_scaler_sm_t;
+typedef struct camera2_scaler_uctl camera2_scaler_uctl_t;
+
+typedef struct camera2_sensor_uctl camera2_sensor_uctl_t;
+typedef struct camera2_lens_uctl camera2_lens_uctl_t;
+typedef struct camera2_lens_udm camera2_lens_udm_t;
+
+typedef struct camera2_ae_udm camera2_ae_udm_t;
+typedef struct camera2_awb_udm camera2_awb_udm_t;
+typedef struct camera2_af_udm camera2_af_udm_t;
+typedef struct camera2_as_udm camera2_as_udm_t;
+typedef struct camera2_ipc_udm camera2_ipc_udm_t;
+typedef struct camera2_internal_udm camera2_internal_udm_t;
+
+typedef struct camera2_flash_uctl camera2_flash_uctl_t;
+
+typedef struct camera2_shot camera2_shot_t;
+
+#endif
--- /dev/null
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include "fimc-is-ncp6335b.h"
+
+/**
+ * NCP6335B Vout Tables
+ */
+static const struct ncp6335b_vout vout_tables[] = {
+ {0, NCP6335B_VOUT_1P000, "1.000"}, /* defualt voltage */
+ {1, NCP6335B_VOUT_0P875, "0.875"},
+ {2, NCP6335B_VOUT_0P900, "0.900"},
+ {3, NCP6335B_VOUT_0P925, "0.925"},
+ {4, NCP6335B_VOUT_0P950, "0.950"},
+ {5, NCP6335B_VOUT_0P975, "0.975"},
+ {6, NCP6335B_VOUT_1P000, "1.000"},
+};
+
+/**
+ * ncp6335b_get_vout_val: get i2c register value to set vout of dcdc regulator.
+ */
+int ncp6335b_get_vout_val(int sel)
+{
+ int i, vout = vout_tables[0].val;
+
+ if (sel < 0)
+ pr_err("%s: error, invalid sel %d\n", __func__, sel);
+
+ for (i = 0; ARRAY_SIZE(vout_tables); i++) {
+ if (vout_tables[i].sel == sel) {
+ return vout_tables[i].val;
+ }
+ }
+
+ pr_err("%s: warning, default voltage selected. sel %d\n", __func__, sel);
+
+ return vout;
+}
+
+/**
+ * ncp6335b_get_vout_name: get voltage name of vout as string.
+ */
+const char *ncp6335b_get_vout_str(int sel)
+{
+ const char *vout = vout_tables[0].vout;
+ int i;
+
+ if (sel < 0)
+ pr_err("%s: error, invalid sel %d\n", __func__, sel);
+
+ for (i = 0; ARRAY_SIZE(vout_tables); i++) {
+ if (vout_tables[i].sel == sel) {
+ return vout_tables[i].vout;
+ }
+ }
+
+ pr_err("%s: warning, default voltage selected. sel %d\n", __func__, sel);
+
+ return vout;
+}
+
+/**
+ * ncp6335b_set_voltage: set dcdc vout with i2c register value.
+ */
+int ncp6335b_set_voltage(struct i2c_client *client, int vout)
+{
+ int ret = i2c_smbus_write_byte_data(client, 0x14, 0x00);
+ if (ret < 0)
+ pr_err("[%s::%d] Write Error [%d]\n", __func__, __LINE__, ret);
+
+ ret = i2c_smbus_write_byte_data(client, 0x10, vout); /* 1.05V -> 1V (0xC0) */
+ if (ret < 0)
+ pr_err("[%s::%d] Write Error [%d]. vout 0x%X\n", __func__, __LINE__, ret, vout);
+
+ ret = i2c_smbus_write_byte_data(client, 0x11, vout); /* 1.05V -> 1V (0xC0) */
+ if (ret < 0)
+ pr_err("[%s::%d] Write Error [%d]. vout 0x%X\n", __func__, __LINE__, ret, vout);
+
+ /*pr_info("%s: vout 0x%X\n", __func__, vout);*/
+
+ return ret;
+}
+
+int ncp6335b_read_voltage(struct i2c_client *client)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, 0x3);
+ if (ret < 0)
+ pr_err("[%s::%d]Read Error [%d]\n", __func__, __LINE__, ret);
+ pr_err("[%s::%d]NCP6335B PID[%x]\n", __func__, __LINE__, ret);
+
+ ret = i2c_smbus_read_byte_data(client, 0x10);
+ if (ret < 0)
+ pr_err("[%s::%d]Read Error [%d]\n", __func__, __LINE__, ret);
+ pr_err("[%s::%d]NCP6335B [0x10 Read :: %x]\n", __func__, __LINE__, ret);
+
+ ret = i2c_smbus_read_byte_data(client, 0x11);
+ if (ret < 0)
+ pr_err("[%s::%d]Read Error [%d]\n", __func__, __LINE__, ret);
+ pr_err("[%s::%d]NCP6335B [0x11 Read :: %x]\n", __func__, __LINE__, ret);
+
+ ret = i2c_smbus_read_byte_data(client, 0x14);
+ if (ret < 0)
+ pr_err("[%s::%d]Read Error [%d]\n", __func__, __LINE__, ret);
+ pr_err("[%s::%d]NCP6335B [0x14 Read :: %x]\n", __func__, __LINE__, ret);
+
+ return ret;
+}
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include "fimc-is-core.h"
+
+enum{
+ NCP6335B_VOUT_0P875 = 0xAC,
+ NCP6335B_VOUT_0P900 = 0xB0,
+ NCP6335B_VOUT_0P925 = 0xB4,
+ NCP6335B_VOUT_0P950 = 0xB8,
+ NCP6335B_VOUT_0P975 = 0xBC,
+ NCP6335B_VOUT_1P000 = 0xC0,
+};
+
+struct ncp6335b_vout {
+ int sel; /* selector, unique value for vout entry and indepedant to dcdc vendor */
+ int val; /* dcdc-specific value for vout register */
+ char vout[7]; /* voltage level string */
+};
+
+int ncp6335b_get_vout_val(int sel);
+const char *ncp6335b_get_vout_str(int sel);
+int ncp6335b_set_voltage(struct i2c_client *client, int vout);
+int ncp6335b_read_voltage(struct i2c_client *client);
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_PARAMS_H
+#define FIMC_IS_PARAMS_H
+
+#define IS_REGION_VER 150 /* IS REGION VERSION 1.50 */
+
+/* MACROs */
+#define IS_SET_PARAM_BIT(dev, num) \
+ (num >= 32 ? set_bit((num-32), &dev->p_region_index2) \
+ : set_bit(num, &dev->p_region_index1))
+#define IS_INC_PARAM_NUM(dev) atomic_inc(&dev->p_region_num)
+
+#define IS_PARAM_GLOBAL(dev) (dev->is_p_region->parameter.global)
+#define IS_PARAM_ISP(dev) (dev->is_p_region->parameter.isp)
+#define IS_PARAM_DRC(dev) (dev->is_p_region->parameter.drc)
+#define IS_PARAM_FD(dev) (dev->is_p_region->parameter.fd)
+#define IS_HEADER(dev) (dev->is_p_region->header)
+#define IS_FACE(dev) (dev->is_p_region->face)
+#define IS_SHARED(dev) (dev->is_shared_region)
+#define IS_PARAM_SIZE (FIMC_IS_REGION_SIZE + 1)
+
+#ifndef BIT0
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#define BIT32 0x0000000100000000ULL
+#define BIT33 0x0000000200000000ULL
+#define BIT34 0x0000000400000000ULL
+#define BIT35 0x0000000800000000ULL
+#define BIT36 0x0000001000000000ULL
+#define BIT37 0x0000002000000000ULL
+#define BIT38 0x0000004000000000ULL
+#define BIT39 0x0000008000000000ULL
+#define BIT40 0x0000010000000000ULL
+#define BIT41 0x0000020000000000ULL
+#define BIT42 0x0000040000000000ULL
+#define BIT43 0x0000080000000000ULL
+#define BIT44 0x0000100000000000ULL
+#define BIT45 0x0000200000000000ULL
+#define BIT46 0x0000400000000000ULL
+#define BIT47 0x0000800000000000ULL
+#define BIT48 0x0001000000000000ULL
+#define BIT49 0x0002000000000000ULL
+#define BIT50 0x0004000000000000ULL
+#define BIT51 0x0008000000000000ULL
+#define BIT52 0x0010000000000000ULL
+#define BIT53 0x0020000000000000ULL
+#define BIT54 0x0040000000000000ULL
+#define BIT55 0x0080000000000000ULL
+#define BIT56 0x0100000000000000ULL
+#define BIT57 0x0200000000000000ULL
+#define BIT58 0x0400000000000000ULL
+#define BIT59 0x0800000000000000ULL
+#define BIT60 0x1000000000000000ULL
+#define BIT61 0x2000000000000000ULL
+#define BIT62 0x4000000000000000ULL
+#define BIT63 0x8000000000000000ULL
+#define INC_BIT(bit) (bit<<1)
+#define INC_NUM(bit) (bit + 1)
+#endif
+
+#define MAGIC_NUMBER 0x01020304
+
+#define PARAMETER_MAX_SIZE 128 /* in byte */
+#define PARAMETER_MAX_MEMBER (PARAMETER_MAX_SIZE/4)
+
+enum is_entry {
+ ENTRY_GLOBAL,
+ ENTRY_BUFFER,
+ ENTRY_SENSOR,
+ ENTRY_3AA,
+ ENTRY_ISP,
+ ENTRY_DRC,
+ ENTRY_SCALERC,
+ ENTRY_DIS,
+ ENTRY_TDNR,
+ ENTRY_SCALERP,
+ ENTRY_LHFD,
+ ENTRY_3AAC,
+ ENTRY_3AAP,
+ ENTRY_END
+};
+
+#define ADDRESS_TO_OFFSET(start, end) ((uint32)end - (uint32)start)
+#define OFFSET_TO_NUM(offset) ((offset)>>6)
+#define IS_OFFSET_LOWBIT(offset) (OFFSET_TO_NUM(offset) >= \
+ 32 ? false : true)
+#define OFFSET_TO_BIT(offset) \
+ {(IS_OFFSET_LOWBIT(offset) ? (1<<OFFSET_TO_NUM(offset)) \
+ : (1<<(OFFSET_TO_NUM(offset)-32))}
+#define LOWBIT_OF_NUM(num) (num >= 32 ? 0 : BIT0<<num)
+#define HIGHBIT_OF_NUM(num) (num >= 32 ? BIT0<<(num-32) : 0)
+
+/* 0~31 */
+#define PARAM_GLOBAL_SHOTMODE 0
+#define PARAM_SENSOR_CONTROL INC_NUM(PARAM_GLOBAL_SHOTMODE)
+#define PARAM_SENSOR_OTF_INPUT INC_NUM(PARAM_SENSOR_CONTROL)
+#define PARAM_SENSOR_OTF_OUTPUT INC_NUM(PARAM_SENSOR_OTF_INPUT)
+#define PARAM_SENSOR_CONFIG INC_NUM(PARAM_SENSOR_OTF_OUTPUT)
+#define PARAM_SENSOR_DMA_OUTPUT INC_NUM(PARAM_SENSOR_CONFIG)
+#define PARAM_BUFFER_CONTROL INC_NUM(PARAM_SENSOR_DMA_OUTPUT)
+#define PARAM_BUFFER_OTF_INPUT INC_NUM(PARAM_BUFFER_CONTROL)
+#define PARAM_BUFFER_OTF_OUTPUT INC_NUM(PARAM_BUFFER_OTF_INPUT)
+#define PARAM_3AA_CONTROL INC_NUM(PARAM_BUFFER_OTF_OUTPUT)
+#define PARAM_3AA_OTF_INPUT INC_NUM(PARAM_3AA_CONTROL)
+#define PARAM_3AA_VDMA1_INPUT INC_NUM(PARAM_3AA_OTF_INPUT)
+#define PARAM_3AA_DDMA_INPUT INC_NUM(PARAM_3AA_VDMA1_INPUT)
+#define PARAM_3AA_OTF_OUTPUT INC_NUM(PARAM_3AA_DDMA_INPUT)
+#define PARAM_3AA_VDMA4_OUTPUT INC_NUM(PARAM_3AA_OTF_OUTPUT)
+#define PARAM_3AA_VDMA2_OUTPUT INC_NUM(PARAM_3AA_VDMA4_OUTPUT)
+#define PARAM_3AA_DDMA_OUTPUT INC_NUM(PARAM_3AA_VDMA2_OUTPUT)
+#define PARAM_ISP_CONTROL INC_NUM(PARAM_3AA_DDMA_OUTPUT)
+#define PARAM_ISP_OTF_INPUT INC_NUM(PARAM_ISP_CONTROL)
+#define PARAM_ISP_VDMA1_INPUT INC_NUM(PARAM_ISP_OTF_INPUT)
+#define PARAM_ISP_VDMA3_INPUT INC_NUM(PARAM_ISP_VDMA1_INPUT)
+#define PARAM_ISP_OTF_OUTPUT INC_NUM(PARAM_ISP_VDMA3_INPUT)
+#define PARAM_ISP_VDMA4_OUTPUT INC_NUM(PARAM_ISP_OTF_OUTPUT)
+#define PARAM_ISP_VDMA5_OUTPUT INC_NUM(PARAM_ISP_VDMA4_OUTPUT)
+#define PARAM_DRC_CONTROL INC_NUM(PARAM_ISP_VDMA5_OUTPUT)
+#define PARAM_DRC_OTF_INPUT INC_NUM(PARAM_DRC_CONTROL)
+#define PARAM_DRC_DMA_INPUT INC_NUM(PARAM_DRC_OTF_INPUT)
+#define PARAM_DRC_OTF_OUTPUT INC_NUM(PARAM_DRC_DMA_INPUT)
+#define PARAM_SCALERC_CONTROL INC_NUM(PARAM_DRC_OTF_OUTPUT)
+#define PARAM_SCALERC_OTF_INPUT INC_NUM(PARAM_SCALERC_CONTROL)
+#define PARAM_SCALERC_IMAGE_EFFECT INC_NUM(PARAM_SCALERC_OTF_INPUT)
+#define PARAM_SCALERC_INPUT_CROP INC_NUM(PARAM_SCALERC_IMAGE_EFFECT)
+/* 32~63 */
+#define PARAM_SCALERC_OUTPUT_CROP INC_NUM(PARAM_SCALERC_INPUT_CROP)
+#define PARAM_SCALERC_OTF_OUTPUT INC_NUM(PARAM_SCALERC_OUTPUT_CROP)
+#define PARAM_SCALERC_DMA_OUTPUT INC_NUM(PARAM_SCALERC_OTF_OUTPUT)
+#define PARAM_ODC_CONTROL INC_NUM(PARAM_SCALERC_DMA_OUTPUT)
+#define PARAM_ODC_OTF_INPUT INC_NUM(PARAM_ODC_CONTROL)
+#define PARAM_ODC_OTF_OUTPUT INC_NUM(PARAM_ODC_OTF_INPUT)
+#define PARAM_DIS_CONTROL INC_NUM(PARAM_ODC_OTF_OUTPUT)
+#define PARAM_DIS_OTF_INPUT INC_NUM(PARAM_DIS_CONTROL)
+#define PARAM_DIS_OTF_OUTPUT INC_NUM(PARAM_DIS_OTF_INPUT)
+#define PARAM_TDNR_CONTROL INC_NUM(PARAM_DIS_OTF_OUTPUT)
+#define PARAM_TDNR_OTF_INPUT INC_NUM(PARAM_TDNR_CONTROL)
+#define PARAM_TDNR_1ST_FRAME INC_NUM(PARAM_TDNR_OTF_INPUT)
+#define PARAM_TDNR_OTF_OUTPUT INC_NUM(PARAM_TDNR_1ST_FRAME)
+#define PARAM_TDNR_DMA_OUTPUT INC_NUM(PARAM_TDNR_OTF_OUTPUT)
+#define PARAM_SCALERP_CONTROL INC_NUM(PARAM_TDNR_DMA_OUTPUT)
+#define PARAM_SCALERP_OTF_INPUT INC_NUM(PARAM_SCALERP_CONTROL)
+#define PARAM_SCALERP_IMAGE_EFFECT INC_NUM(PARAM_SCALERP_OTF_INPUT)
+#define PARAM_SCALERP_INPUT_CROP INC_NUM(PARAM_SCALERP_IMAGE_EFFECT)
+#define PARAM_SCALERP_OUTPUT_CROP INC_NUM(PARAM_SCALERP_INPUT_CROP)
+#define PARAM_SCALERP_ROTATION INC_NUM(PARAM_SCALERP_OUTPUT_CROP)
+#define PARAM_SCALERP_FLIP INC_NUM(PARAM_SCALERP_ROTATION)
+#define PARAM_SCALERP_OTF_OUTPUT INC_NUM(PARAM_SCALERP_FLIP)
+#define PARAM_SCALERP_DMA_OUTPUT INC_NUM(PARAM_SCALERP_OTF_OUTPUT)
+#define PARAM_FD_CONTROL INC_NUM(PARAM_SCALERP_DMA_OUTPUT)
+#define PARAM_FD_OTF_INPUT INC_NUM(PARAM_FD_CONTROL)
+#define PARAM_FD_DMA_INPUT INC_NUM(PARAM_FD_OTF_INPUT)
+#define PARAM_FD_CONFIG INC_NUM(PARAM_FD_DMA_INPUT)
+#define PARAM_END INC_NUM(PARAM_FD_CONFIG)
+
+#define PARAM_STRNUM_GLOBAL (PARAM_GLOBAL_SHOTMODE)
+#define PARAM_RANGE_GLOBAL 1
+#define PARAM_STRNUM_SENSOR (PARAM_SENSOR_CONTROL)
+#define PARAM_RANGE_SENSOR 5
+#define PARAM_STRNUM_BUFFER (PARAM_BUFFER_CONTROL)
+#define PARAM_RANGE_BUFFER 3
+#define PARAM_STRNUM_3AA (PARAM_3AA_CONTROL)
+#define PARAM_RANGE_3AA 8
+#define PARAM_STRNUM_ISP (PARAM_ISP_CONTROL)
+#define PARAM_RANGE_ISP 7
+#define PARAM_STRNUM_DRC (PARAM_DRC_CONTROL)
+#define PARAM_RANGE_DRC 4
+#define PARAM_STRNUM_SCALERC (PARAM_SCALERC_CONTROL)
+#define PARAM_RANGE_SCALERC 7
+#define PARAM_STRNUM_ODC (PARAM_ODC_CONTROL)
+#define PARAM_RANGE_ODC 3
+#define PARAM_STRNUM_DIS (PARAM_DIS_CONTROL)
+#define PARAM_RANGE_DIS 3
+#define PARAM_STRNUM_TDNR (PARAM_TDNR_CONTROL)
+#define PARAM_RANGE_TDNR 5
+#define PARAM_STRNUM_SCALERP (PARAM_SCALERP_CONTROL)
+#define PARAM_RANGE_SCALERP 9
+#define PARAM_STRNUM_LHFD (PARAM_FD_CONTROL)
+#define PARAM_RANGE_LHFD 4
+
+#define PARAM_LOW_MASK (0xFFFFFFFF)
+#define PARAM_HIGH_MASK (0x07FFFFFF)
+
+/* Enumerations
+*
+*/
+
+/* ---------------------- Input ----------------------------------- */
+enum control_command {
+ CONTROL_COMMAND_STOP = 0,
+ CONTROL_COMMAND_START = 1,
+ CONTROL_COMMAND_TEST = 2
+};
+
+enum bypass_command {
+ CONTROL_BYPASS_DISABLE = 0,
+ CONTROL_BYPASS_ENABLE = 1
+};
+
+enum control_error {
+ CONTROL_ERROR_NO = 0
+};
+
+enum otf_input_command {
+ OTF_INPUT_COMMAND_DISABLE = 0,
+ OTF_INPUT_COMMAND_ENABLE = 1
+};
+
+enum otf_input_format {
+ OTF_INPUT_FORMAT_BAYER = 0, /* 1 Channel */
+ OTF_INPUT_FORMAT_YUV444 = 1, /* 3 Channel */
+ OTF_INPUT_FORMAT_YUV422 = 2, /* 3 Channel */
+ OTF_INPUT_FORMAT_YUV420 = 3, /* 3 Channel */
+ OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER = 10,
+ OTF_INPUT_FORMAT_BAYER_DMA = 11,
+};
+
+enum otf_input_bitwidth {
+ OTF_INPUT_BIT_WIDTH_14BIT = 14,
+ OTF_INPUT_BIT_WIDTH_12BIT = 12,
+ OTF_INPUT_BIT_WIDTH_11BIT = 11,
+ OTF_INPUT_BIT_WIDTH_10BIT = 10,
+ OTF_INPUT_BIT_WIDTH_9BIT = 9,
+ OTF_INPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum otf_input_order {
+ OTF_INPUT_ORDER_BAYER_GR_BG = 0,
+ OTF_INPUT_ORDER_BAYER_RG_GB = 1,
+ OTF_INPUT_ORDER_BAYER_BG_GR = 2,
+ OTF_INPUT_ORDER_BAYER_GB_RG = 3
+};
+
+enum otf_input_path {
+ OTF_INPUT_SERIAL_PATH = 0,
+ OTF_INPUT_PARAL_PATH = 1
+};
+
+enum otf_intput_error {
+ OTF_INPUT_ERROR_NO = 0 /* Input setting is done */
+};
+
+enum dma_input_command {
+ DMA_INPUT_COMMAND_DISABLE = 0,
+ DMA_INPUT_COMMAND_ENABLE = 1,
+ DMA_INPUT_COMMAND_BUF_MNGR = 2,
+ DMA_INPUT_COMMAND_RUN_SINGLE = 3,
+};
+
+enum dma_inut_format {
+ DMA_INPUT_FORMAT_BAYER = 0,
+ DMA_INPUT_FORMAT_YUV444 = 1,
+ DMA_INPUT_FORMAT_YUV422 = 2,
+ DMA_INPUT_FORMAT_YUV420 = 3,
+ DMA_INPUT_FORMAT_RGB = 4,
+ DMA_INPUT_FORMAT_BAYER_PACKED12 = 5,
+};
+
+enum dma_input_bitwidth {
+ DMA_INPUT_BIT_WIDTH_14BIT = 14,
+ DMA_INPUT_BIT_WIDTH_12BIT = 12,
+ DMA_INPUT_BIT_WIDTH_11BIT = 11,
+ DMA_INPUT_BIT_WIDTH_10BIT = 10,
+ DMA_INPUT_BIT_WIDTH_9BIT = 9,
+ DMA_INPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum dma_input_plane {
+ DMA_INPUT_PLANE_3 = 3,
+ DMA_INPUT_PLANE_2 = 2,
+ DMA_INPUT_PLANE_1 = 1
+};
+
+enum dma_input_order {
+ /* (for DMA_INPUT_PLANE_3) */
+ DMA_INPUT_ORDER_NO = 0,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CbCr = 1,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CrCb = 2,
+ /* (only valid at DMA_INPUT_PLANE_1 & DMA_INPUT_FORMAT_YUV444) */
+ DMA_INPUT_ORDER_YCbCr = 3,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YYCbCr = 4,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCbYCr = 5,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCrYCb = 6,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CbYCrY = 7,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CrYCbY = 8,
+ /* (only valid at DMA_INPUT_FORMAT_BAYER) */
+ DMA_INPUT_ORDER_GR_BG = 9
+};
+
+enum dma_input_MemoryWidthBits {
+ DMA_INPUT_MEMORY_WIDTH_16BIT = 16,
+ DMA_INPUT_MEMORY_WIDTH_12BIT = 12,
+};
+
+enum dma_input_error {
+ DMA_INPUT_ERROR_NO = 0 /* DMA input setting is done */
+};
+
+/* ---------------------- Output ----------------------------------- */
+enum otf_output_crop {
+ OTF_OUTPUT_CROP_DISABLE = 0,
+ OTF_OUTPUT_CROP_ENABLE = 1
+};
+
+enum otf_output_command {
+ OTF_OUTPUT_COMMAND_DISABLE = 0,
+ OTF_OUTPUT_COMMAND_ENABLE = 1
+};
+
+enum orf_output_format {
+ OTF_OUTPUT_FORMAT_YUV444 = 1,
+ OTF_OUTPUT_FORMAT_YUV422 = 2,
+ OTF_OUTPUT_FORMAT_YUV420 = 3,
+ OTF_OUTPUT_FORMAT_RGB = 4,
+ OTF_OUTPUT_FORMAT_YUV444_TRUNCATED = 5,
+ OTF_OUTPUT_FORMAT_YUV422_TRUNCATED = 6
+};
+
+enum otf_output_bitwidth {
+ OTF_OUTPUT_BIT_WIDTH_14BIT = 14,
+ OTF_OUTPUT_BIT_WIDTH_12BIT = 12,
+ OTF_OUTPUT_BIT_WIDTH_11BIT = 11,
+ OTF_OUTPUT_BIT_WIDTH_10BIT = 10,
+ OTF_OUTPUT_BIT_WIDTH_9BIT = 9,
+ OTF_OUTPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum otf_output_order {
+ OTF_OUTPUT_ORDER_BAYER_GR_BG = 0,
+};
+
+enum otf_output_error {
+ OTF_OUTPUT_ERROR_NO = 0 /* Output Setting is done */
+};
+
+enum dma_output_command {
+ DMA_OUTPUT_COMMAND_DISABLE = 0,
+ DMA_OUTPUT_COMMAND_ENABLE = 1,
+ DMA_OUTPUT_COMMAND_BUF_MNGR = 2,
+ DMA_OUTPUT_UPDATE_MASK_BITS = 3
+};
+
+enum dma_output_format {
+ DMA_OUTPUT_FORMAT_BAYER = 0,
+ DMA_OUTPUT_FORMAT_YUV444 = 1,
+ DMA_OUTPUT_FORMAT_YUV422 = 2,
+ DMA_OUTPUT_FORMAT_YUV420 = 3,
+ DMA_OUTPUT_FORMAT_RGB = 4,
+ DMA_OUTPUT_FORMAT_BAYER_PACKED12= 5,
+};
+
+enum dma_output_bitwidth {
+ DMA_OUTPUT_BIT_WIDTH_14BIT = 14,
+ DMA_OUTPUT_BIT_WIDTH_12BIT = 12,
+ DMA_OUTPUT_BIT_WIDTH_11BIT = 11,
+ DMA_OUTPUT_BIT_WIDTH_10BIT = 10,
+ DMA_OUTPUT_BIT_WIDTH_9BIT = 9,
+ DMA_OUTPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum dma_output_plane {
+ DMA_OUTPUT_PLANE_3 = 3,
+ DMA_OUTPUT_PLANE_2 = 2,
+ DMA_OUTPUT_PLANE_1 = 1
+};
+
+enum dma_output_order {
+ DMA_OUTPUT_ORDER_NO = 0,
+ /* (for DMA_OUTPUT_PLANE_3) */
+ DMA_OUTPUT_ORDER_CbCr = 1,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_CrCb = 2,
+ /* (only valid at DMA_OUTPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_YYCbCr = 3,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCbYCr = 4,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCrYCb = 5,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbYCrY = 6,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrYCbY = 7,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCbCr = 8,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrYCb = 9,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrCbY = 10,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbYCr = 11,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCrCb = 12,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbCrY = 13,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_BGR = 14,
+ /* (only valid at DMA_OUTPUT_FORMAT_RGB) */
+ DMA_OUTPUT_ORDER_GB_BG = 15
+ /* (only valid at DMA_OUTPUT_FORMAT_BAYER) */
+};
+
+enum dma_output_notify_dma_done {
+ DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE = 0,
+ DMA_OUTPUT_NOTIFY_DMA_DONE_ENBABLE = 1,
+};
+
+enum dma_output_error {
+ DMA_OUTPUT_ERROR_NO = 0 /* DMA output setting is done */
+};
+
+/* ---------------------- Global ----------------------------------- */
+enum global_shotmode_error {
+ GLOBAL_SHOTMODE_ERROR_NO = 0 /* shot-mode setting is done */
+};
+
+/* ------------------------- AA ------------------------------------ */
+enum isp_lock_command {
+ ISP_AA_COMMAND_START = 0,
+ ISP_AA_COMMAND_STOP = 1
+};
+
+enum isp_lock_target {
+ ISP_AA_TARGET_AF = 1,
+ ISP_AA_TARGET_AE = 2,
+ ISP_AA_TARGET_AWB = 4
+};
+
+enum isp_af_mode {
+ ISP_AF_MANUAL = 0,
+ ISP_AF_SINGLE,
+ ISP_AF_CONTINUOUS,
+ ISP_AF_REGION,
+ ISP_AF_SLEEP,
+ ISP_AF_INIT,
+ ISP_AF_SET_CENTER_WINDOW,
+ ISP_AF_SET_TOUCH_WINDOW,
+ ISP_AF_SET_FACE_WINDOW
+};
+
+enum isp_af_scene {
+ ISP_AF_SCENE_NORMAL = 0,
+ ISP_AF_SCENE_MACRO = 1
+};
+
+enum isp_af_touch {
+ ISP_AF_TOUCH_DISABLE = 0,
+ ISP_AF_TOUCH_ENABLE
+};
+
+enum isp_af_face {
+ ISP_AF_FACE_DISABLE = 0,
+ ISP_AF_FACE_ENABLE
+};
+
+enum isp_af_reponse {
+ ISP_AF_RESPONSE_PREVIEW = 0,
+ ISP_AF_RESPONSE_MOVIE
+};
+
+enum isp_af_sleep {
+ ISP_AF_SLEEP_OFF = 0,
+ ISP_AF_SLEEP_ON = 1
+};
+
+enum isp_af_continuous {
+ ISP_AF_CONTINUOUS_DISABLE = 0,
+ ISP_AF_CONTINUOUS_ENABLE = 1
+};
+
+enum isp_af_error {
+ ISP_AF_ERROR_NO = 0, /* AF mode change is done */
+ ISP_AF_EROOR_NO_LOCK_DONE = 1 /* AF lock is done */
+};
+
+/* ------------------------- Flash ------------------------------------- */
+enum isp_flash_command {
+ ISP_FLASH_COMMAND_DISABLE = 0,
+ ISP_FLASH_COMMAND_MANUALON = 1, /* (forced flash) */
+ ISP_FLASH_COMMAND_AUTO = 2,
+ ISP_FLASH_COMMAND_TORCH = 3, /* 3 sec */
+ ISP_FLASH_COMMAND_FLASH_ON = 4,
+ ISP_FLASH_COMMAND_CAPTURE = 5,
+ ISP_FLASH_COMMAND_TRIGGER = 6,
+ ISP_FLASH_COMMAND_CALIBRATION = 7,
+ ISP_FLASH_COMMAND_START = 8,
+ ISP_FLASH_COMMAND_CANCLE = 9
+};
+
+enum isp_flash_redeye {
+ ISP_FLASH_REDEYE_DISABLE = 0,
+ ISP_FLASH_REDEYE_ENABLE = 1
+};
+
+enum isp_flash_error {
+ ISP_FLASH_ERROR_NO = 0 /* Flash setting is done */
+};
+
+/* -------------------------- AWB ------------------------------------ */
+enum isp_awb_command {
+ ISP_AWB_COMMAND_AUTO = 0,
+ ISP_AWB_COMMAND_ILLUMINATION = 1,
+ ISP_AWB_COMMAND_MANUAL = 2
+};
+
+enum isp_awb_illumination {
+ ISP_AWB_ILLUMINATION_DAYLIGHT = 0,
+ ISP_AWB_ILLUMINATION_CLOUDY = 1,
+ ISP_AWB_ILLUMINATION_TUNGSTEN = 2,
+ ISP_AWB_ILLUMINATION_FLUORESCENT = 3
+};
+
+enum isp_awb_error {
+ ISP_AWB_ERROR_NO = 0 /* AWB setting is done */
+};
+
+/* -------------------------- Effect ----------------------------------- */
+enum isp_imageeffect_command {
+ ISP_IMAGE_EFFECT_DISABLE = 0,
+ ISP_IMAGE_EFFECT_MONOCHROME = 1,
+ ISP_IMAGE_EFFECT_NEGATIVE_MONO = 2,
+ ISP_IMAGE_EFFECT_NEGATIVE_COLOR = 3,
+ ISP_IMAGE_EFFECT_SEPIA = 4,
+ ISP_IMAGE_EFFECT_AQUA = 5,
+ ISP_IMAGE_EFFECT_EMBOSS = 6,
+ ISP_IMAGE_EFFECT_EMBOSS_MONO = 7,
+ ISP_IMAGE_EFFECT_SKETCH = 8,
+ ISP_IMAGE_EFFECT_RED_YELLOW_POINT = 9,
+ ISP_IMAGE_EFFECT_GREEN_POINT = 10,
+ ISP_IMAGE_EFFECT_BLUE_POINT = 11,
+ ISP_IMAGE_EFFECT_MAGENTA_POINT = 12,
+ ISP_IMAGE_EFFECT_WARM_VINTAGE = 13,
+ ISP_IMAGE_EFFECT_COLD_VINTAGE = 14,
+ ISP_IMAGE_EFFECT_POSTERIZE = 15,
+ ISP_IMAGE_EFFECT_SOLARIZE = 16,
+ ISP_IMAGE_EFFECT_WASHED = 17,
+ ISP_IMAGE_EFFECT_CCM = 18,
+};
+
+enum isp_imageeffect_error {
+ ISP_IMAGE_EFFECT_ERROR_NO = 0 /* Image effect setting is done */
+};
+
+/* --------------------------- ISO ------------------------------------ */
+enum isp_iso_command {
+ ISP_ISO_COMMAND_AUTO = 0,
+ ISP_ISO_COMMAND_MANUAL = 1
+};
+
+enum iso_error {
+ ISP_ISO_ERROR_NO = 0 /* ISO setting is done */
+};
+
+/* -------------------------- Adjust ----------------------------------- */
+enum iso_adjust_command {
+ ISP_ADJUST_COMMAND_AUTO = 0,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST = (1 << 0),
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION = (1 << 1),
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS = (1 << 2),
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE = (1 << 3),
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS = (1 << 4),
+ ISP_ADJUST_COMMAND_MANUAL_HUE = (1 << 5),
+ ISP_ADJUST_COMMAND_MANUAL_HOTPIXEL = (1 << 6),
+ ISP_ADJUST_COMMAND_MANUAL_NOISEREDUCTION = (1 << 7),
+ ISP_ADJUST_COMMAND_MANUAL_SHADING = (1 << 8),
+ ISP_ADJUST_COMMAND_MANUAL_GAMMA = (1 << 9),
+ ISP_ADJUST_COMMAND_MANUAL_EDGEENHANCEMENT = (1 << 10),
+ ISP_ADJUST_COMMAND_MANUAL_SCENE = (1 << 11),
+ ISP_ADJUST_COMMAND_MANUAL_FRAMETIME = (1 << 12),
+ ISP_ADJUST_COMMAND_MANUAL_ALL = 0x1FFF
+};
+
+enum isp_adjust_scene_index {
+ ISP_ADJUST_SCENE_NORMAL = 0,
+ ISP_ADJUST_SCENE_NIGHT_PREVIEW = 1,
+ ISP_ADJUST_SCENE_NIGHT_CAPTURE = 2
+};
+
+
+enum isp_adjust_error {
+ ISP_ADJUST_ERROR_NO = 0 /* Adjust setting is done */
+};
+
+/* ------------------------- Metering ---------------------------------- */
+enum isp_metering_command {
+ ISP_METERING_COMMAND_AVERAGE = 0,
+ ISP_METERING_COMMAND_SPOT = 1,
+ ISP_METERING_COMMAND_MATRIX = 2,
+ ISP_METERING_COMMAND_CENTER = 3,
+ ISP_METERING_COMMAND_EXPOSURE_MODE = (1 << 8)
+};
+
+enum isp_exposure_mode {
+ ISP_EXPOSUREMODE_OFF = 1,
+ ISP_EXPOSUREMODE_AUTO = 2
+};
+
+enum isp_metering_error {
+ ISP_METERING_ERROR_NO = 0 /* Metering setting is done */
+};
+
+/* -------------------------- AFC ----------------------------------- */
+enum isp_afc_command {
+ ISP_AFC_COMMAND_DISABLE = 0,
+ ISP_AFC_COMMAND_AUTO = 1,
+ ISP_AFC_COMMAND_MANUAL = 2
+};
+
+enum isp_afc_manual {
+ ISP_AFC_MANUAL_50HZ = 50,
+ ISP_AFC_MANUAL_60HZ = 60
+};
+
+enum isp_afc_error {
+ ISP_AFC_ERROR_NO = 0 /* AFC setting is done */
+};
+
+enum isp_scene_command {
+ ISP_SCENE_NONE = 0,
+ ISP_SCENE_PORTRAIT = 1,
+ ISP_SCENE_LANDSCAPE = 2,
+ ISP_SCENE_SPORTS = 3,
+ ISP_SCENE_PARTYINDOOR = 4,
+ ISP_SCENE_BEACHSNOW = 5,
+ ISP_SCENE_SUNSET = 6,
+ ISP_SCENE_DAWN = 7,
+ ISP_SCENE_FALL = 8,
+ ISP_SCENE_NIGHT = 9,
+ ISP_SCENE_AGAINSTLIGHTWLIGHT = 10,
+ ISP_SCENE_AGAINSTLIGHTWOLIGHT = 11,
+ ISP_SCENE_FIRE = 12,
+ ISP_SCENE_TEXT = 13,
+ ISP_SCENE_CANDLE = 14
+};
+
+enum ISP_BDSCommandEnum {
+ ISP_BDS_COMMAND_DISABLE = 0,
+ ISP_BDS_COMMAND_ENABLE = 1
+};
+
+/* -------------------------- Scaler --------------------------------- */
+enum scaler_imageeffect_command {
+ SCALER_IMAGE_EFFECT_COMMNAD_DISABLE = 0,
+ SCALER_IMAGE_EFFECT_COMMNAD_SEPIA_CB = 1,
+ SCALER_IMAGE_EFFECT_COMMAND_SEPIA_CR = 2,
+ SCALER_IMAGE_EFFECT_COMMAND_NEGATIVE = 3,
+ SCALER_IMAGE_EFFECT_COMMAND_ARTFREEZE = 4,
+ SCALER_IMAGE_EFFECT_COMMAND_EMBOSSING = 5,
+ SCALER_IMAGE_EFFECT_COMMAND_SILHOUETTE = 6
+};
+
+enum scaler_imageeffect_error {
+ SCALER_IMAGE_EFFECT_ERROR_NO = 0
+};
+
+enum scaler_crop_command {
+ SCALER_CROP_COMMAND_DISABLE = 0,
+ SCALER_CROP_COMMAND_ENABLE = 1
+};
+
+enum scaler_crop_error {
+ SCALER_CROP_ERROR_NO = 0 /* crop setting is done */
+};
+
+enum scaler_scaling_command {
+ SCALER_SCALING_COMMNAD_DISABLE = 0,
+ SCALER_SCALING_COMMAND_UP = 1,
+ SCALER_SCALING_COMMAND_DOWN = 2
+};
+
+enum scaler_scaling_error {
+ SCALER_SCALING_ERROR_NO = 0
+};
+
+enum scaler_rotation_command {
+ SCALER_ROTATION_COMMAND_DISABLE = 0,
+ SCALER_ROTATION_COMMAND_CLOCKWISE90 = 1
+};
+
+enum scaler_rotation_error {
+ SCALER_ROTATION_ERROR_NO = 0
+};
+
+enum scaler_flip_command {
+ SCALER_FLIP_COMMAND_NORMAL = 0,
+ SCALER_FLIP_COMMAND_X_MIRROR = 1,
+ SCALER_FLIP_COMMAND_Y_MIRROR = 2,
+ SCALER_FLIP_COMMAND_XY_MIRROR = 3 /* (180 rotation) */
+};
+
+enum scaler_flip_error {
+ SCALER_FLIP_ERROR_NO = 0 /* flip setting is done */
+};
+
+enum scaler_dma_out_sel {
+ SCALER_DMA_OUT_IMAGE_EFFECT = 0,
+ SCALER_DMA_OUT_SCALED = 1,
+ SCALER_DMA_OUT_UNSCALED = 2
+};
+
+enum scaler_output_yuv_range {
+ SCALER_OUTPUT_YUV_RANGE_FULL = 0,
+ SCALER_OUTPUT_YUV_RANGE_NARROW = 1,
+};
+
+/* -------------------------- 3DNR ----------------------------------- */
+enum tdnr_1st_frame_command {
+ TDNR_1ST_FRAME_COMMAND_NOPROCESSING = 0,
+ TDNR_1ST_FRAME_COMMAND_2DNR = 1
+};
+
+enum tdnr_1st_frame_error {
+ TDNR_1ST_FRAME_ERROR_NO = 0
+ /*1st frame setting is done*/
+};
+
+/* ---------------------------- FD ------------------------------------- */
+enum fd_config_command {
+ FD_CONFIG_COMMAND_MAXIMUM_NUMBER = 0x1,
+ FD_CONFIG_COMMAND_ROLL_ANGLE = 0x2,
+ FD_CONFIG_COMMAND_YAW_ANGLE = 0x4,
+ FD_CONFIG_COMMAND_SMILE_MODE = 0x8,
+ FD_CONFIG_COMMAND_BLINK_MODE = 0x10,
+ FD_CONFIG_COMMAND_EYES_DETECT = 0x20,
+ FD_CONFIG_COMMAND_MOUTH_DETECT = 0x40,
+ FD_CONFIG_COMMAND_ORIENTATION = 0x80,
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE = 0x100
+};
+
+enum fd_config_roll_angle {
+ FD_CONFIG_ROLL_ANGLE_BASIC = 0,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_BASIC = 1,
+ FD_CONFIG_ROLL_ANGLE_SIDES = 2,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_SIDES = 3,
+ FD_CONFIG_ROLL_ANGLE_FULL = 4,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_FULL = 5,
+};
+
+enum fd_config_yaw_angle {
+ FD_CONFIG_YAW_ANGLE_0 = 0,
+ FD_CONFIG_YAW_ANGLE_45 = 1,
+ FD_CONFIG_YAW_ANGLE_90 = 2,
+ FD_CONFIG_YAW_ANGLE_45_90 = 3,
+};
+
+enum fd_config_smile_mode {
+ FD_CONFIG_SMILE_MODE_DISABLE = 0,
+ FD_CONFIG_SMILE_MODE_ENABLE = 1
+};
+
+enum fd_config_blink_mode {
+ FD_CONFIG_BLINK_MODE_DISABLE = 0,
+ FD_CONFIG_BLINK_MODE_ENABLE = 1
+};
+
+enum fd_config_eye_result {
+ FD_CONFIG_EYES_DETECT_DISABLE = 0,
+ FD_CONFIG_EYES_DETECT_ENABLE = 1
+};
+
+enum fd_config_mouth_result {
+ FD_CONFIG_MOUTH_DETECT_DISABLE = 0,
+ FD_CONFIG_MOUTH_DETECT_ENABLE = 1
+};
+
+enum fd_config_orientation {
+ FD_CONFIG_ORIENTATION_DISABLE = 0,
+ FD_CONFIG_ORIENTATION_ENABLE = 1
+};
+
+struct param_control {
+ u32 cmd;
+ u32 bypass;
+ u32 buffer_address;
+ u32 buffer_number;
+ /* 0: continuous, 1: single */
+ u32 run_mode;
+ u32 reserved[PARAMETER_MAX_MEMBER-6];
+ u32 err;
+};
+
+struct param_otf_input {
+ u32 cmd;
+ u32 width; /* with margin */
+ u32 height; /* with margine */
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 sensor_binning_ratio_x; /* ex(x1: 1000, x0.5: 2000) */
+ u32 sensor_binning_ratio_y; /* ex(x1: 1000, x0.5: 2000) */
+ u32 bns_binning_enable;
+ u32 bns_binning_ratio_x; /* ex(x1: 1000, x0.5: 2000) */
+ u32 bns_binning_ratio_y; /* ex(x1: 1000, x0.5: 2000) */
+ u32 bns_margin_left;
+ u32 bns_margin_top;
+ u32 bns_output_width; /* with margin */
+ u32 bns_output_height; /* with margin */
+ u32 bayer_crop_enable;
+ u32 bayer_crop_offset_x;
+ u32 bayer_crop_offset_y;
+ u32 bayer_crop_width; /* without margin */
+ u32 bayer_crop_height; /* without margin */
+ u32 bds_out_enable;
+ u32 bds_out_width; /* without margin */
+ u32 bds_out_height; /* without margin */
+ u32 frametime_min;
+ u32 frametime_max;
+ u32 scaler_path_sel; /* parallel or serial for SCC*/
+ u32 reserved[PARAMETER_MAX_MEMBER-27];
+ u32 err;
+};
+
+struct param_dma_input {
+ u32 cmd;
+ u32 width; /* with margin */
+ u32 height; /* with margin */
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 sensor_binning_ratio_x; /* ex(x1: 1000, x0.5: 2000) */
+ u32 sensor_binning_ratio_y; /* ex(x1: 1000, x0.5: 2000) */
+ u32 dma_crop_enable; /* should be 0 */
+ u32 dma_crop_offset_x; /* not supported yet */
+ u32 dma_crop_offset_y; /* not supported yet */
+ u32 dma_crop_width; /* not supported yet */
+ u32 dma_crop_height; /* not supported yet */
+ u32 bayer_crop_enable;
+ u32 bayer_crop_offset_x;
+ u32 bayer_crop_offset_y;
+ u32 bayer_crop_width; /* without margine */
+ u32 bayer_crop_height; /* without margine */
+ u32 bds_out_enable;
+ u32 bds_out_width; /* without margine */
+ u32 bds_out_height; /* without margine */
+ u32 user_min_frame_time;
+ u32 user_max_frame_time;
+ u32 reserved[PARAMETER_MAX_MEMBER-27];
+ u32 err;
+};
+
+struct param_otf_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 crop_offset_x;
+ u32 crop_offset_y;
+ u32 reserved[PARAMETER_MAX_MEMBER-9];
+ u32 err;
+};
+
+struct param_dma_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 notify_dma_done;
+ u32 dma_out_mask;
+ u32 reserved[PARAMETER_MAX_MEMBER-12];
+ u32 err;
+};
+
+struct param_global_shotmode {
+ u32 cmd;
+ u32 skip_frames;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_sensor_config {
+ u32 framerate;
+ u32 width;
+ u32 height;
+ u32 mode;
+ u32 binning_ratio_x;
+ u32 binning_ratio_y;
+ u32 min_target_fps;
+ u32 max_target_fps;
+ u32 scene_mode;
+ u32 reserved[PARAMETER_MAX_MEMBER-10];
+ u32 err;
+};
+
+struct param_isp_aa {
+ u32 cmd;
+ u32 target;
+ u32 mode;
+ u32 scene;
+ u32 af_touch;
+ u32 af_face;
+ u32 af_response;
+ u32 sleep;
+ u32 touch_x;
+ u32 touch_y;
+ u32 manual_af_setting;
+ /*0: Legacy, 1: Camera 2.0*/
+ u32 cam_api_2p0;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 af_region_left;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 af_region_top;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 af_region_right;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 af_region_bottom;
+ u32 reserved[PARAMETER_MAX_MEMBER-17];
+ u32 err;
+};
+
+struct param_isp_flash {
+ u32 cmd;
+ u32 redeye;
+ u32 flashintensity;
+ u32 reserved[PARAMETER_MAX_MEMBER-4];
+ u32 err;
+};
+
+struct param_isp_awb {
+ u32 cmd;
+ u32 illumination;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_isp_imageeffect {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_isp_iso {
+ u32 cmd;
+ u32 value;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_isp_adjust {
+ u32 cmd;
+ s32 contrast;
+ s32 saturation;
+ s32 sharpness;
+ s32 exposure;
+ s32 brightness;
+ s32 hue;
+ /* 0 or 1 */
+ u32 hot_pixel_enable;
+ /* -127 ~ 127 */
+ s32 noise_reduction_strength;
+ /* 0 or 1 */
+ u32 shading_correction_enable;
+ /* 0 or 1 */
+ u32 user_gamma_enable;
+ /* -127 ~ 127 */
+ s32 edge_enhancement_strength;
+ /* ISP_AdjustSceneIndexEnum */
+ u32 user_scene_mode;
+ u32 min_frame_time;
+ u32 max_frame_time;
+ u32 reserved[PARAMETER_MAX_MEMBER-16];
+ u32 err;
+};
+
+struct param_isp_metering {
+ u32 cmd;
+ u32 win_pos_x;
+ u32 win_pos_y;
+ u32 win_width;
+ u32 win_height;
+ u32 exposure_mode;
+ /* 0: Legacy, 1: Camera 2.0 */
+ u32 cam_api_2p0;
+ u32 reserved[PARAMETER_MAX_MEMBER-8];
+ u32 err;
+};
+
+struct param_isp_afc {
+ u32 cmd;
+ u32 manual;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_scaler_imageeffect {
+ u32 cmd;
+ u32 arbitrary_cb;
+ u32 arbitrary_cr;
+ u32 yuv_range;
+ u32 reserved[PARAMETER_MAX_MEMBER-5];
+ u32 err;
+};
+
+struct param_scaler_input_crop {
+ u32 cmd;
+ u32 pos_x;
+ u32 pos_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 in_width;
+ u32 in_height;
+ u32 out_width;
+ u32 out_height;
+ u32 reserved[PARAMETER_MAX_MEMBER-10];
+ u32 err;
+};
+
+struct param_scaler_output_crop {
+ u32 cmd;
+ u32 pos_x;
+ u32 pos_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 format;
+ u32 reserved[PARAMETER_MAX_MEMBER-7];
+ u32 err;
+};
+
+struct param_scaler_rotation {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_scaler_flip {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_3dnr_1stframe {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_fd_config {
+ u32 cmd;
+ u32 max_number;
+ u32 roll_angle;
+ u32 yaw_angle;
+ s32 smile_mode;
+ s32 blink_mode;
+ u32 eye_detect;
+ u32 mouth_detect;
+ u32 orientation;
+ u32 orientation_value;
+ u32 reserved[PARAMETER_MAX_MEMBER-11];
+ u32 err;
+};
+
+struct global_param {
+ struct param_global_shotmode shotmode; /* 0 */
+};
+
+/* To be added */
+struct sensor_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+ struct param_sensor_config config;
+ struct param_dma_output dma_output;
+};
+
+struct buffer_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct taa_param {
+ struct param_control control;
+ struct param_otf_input otf_input; /* otf_input */
+ struct param_dma_input vdma1_input; /* dma1_input */
+ struct param_dma_input ddma_input; /* not use */
+ struct param_otf_output otf_output; /* not use */
+ struct param_dma_output vdma4_output; /* Before BDS */
+ struct param_dma_output vdma2_output; /* After BDS */
+ struct param_dma_output ddma_output; /* not use */
+};
+
+struct isp_param {
+ struct param_control control;
+ struct param_otf_input otf_input; /* not use */
+ struct param_dma_input vdma1_input; /* dma1_input */
+ struct param_dma_input vdma3_input; /* not use */
+ struct param_otf_output otf_output; /* otf_out */
+ struct param_dma_output vdma4_output; /* not use */
+ struct param_dma_output vdma5_output; /* not use */
+};
+
+struct drc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_otf_output otf_output;
+};
+
+struct scalerc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct odc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct dis_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct tdnr_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_3dnr_1stframe frame;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct scalerp_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_scaler_rotation rotation;
+ struct param_scaler_flip flip;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct fd_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_fd_config config;
+};
+
+struct is_param_region {
+ struct global_param global;
+ struct sensor_param sensor;
+ struct buffer_param buf;
+ struct taa_param taa;
+ struct isp_param isp;
+ struct drc_param drc;
+ struct scalerc_param scalerc;
+ struct odc_param odc;
+ struct dis_param dis;
+ struct tdnr_param tdnr;
+ struct scalerp_param scalerp;
+ struct fd_param fd;
+};
+
+#define NUMBER_OF_GAMMA_CURVE_POINTS 32
+
+struct is_sensor_tune {
+ u32 exposure;
+ u32 analog_gain;
+ u32 frame_rate;
+ u32 actuator_pos;
+};
+
+struct is_tune_gammacurve {
+ u32 num_pts_x[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_r[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_g[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_b[NUMBER_OF_GAMMA_CURVE_POINTS];
+};
+
+struct is_isp_tune {
+ /* Brightness level : range 0~100, default : 7 */
+ u32 brightness_level;
+ /* Contrast level : range -127~127, default : 0 */
+ s32 contrast_level;
+ /* Saturation level : range -127~127, default : 0 */
+ s32 saturation_level;
+ s32 gamma_level;
+ struct is_tune_gammacurve gamma_curve[4];
+ /* Hue : range -127~127, default : 0 */
+ s32 hue;
+ /* Sharpness blur : range -127~127, default : 0 */
+ s32 sharpness_blur;
+ /* Despeckle : range -127~127, default : 0 */
+ s32 despeckle;
+ /* Edge color supression : range -127~127, default : 0 */
+ s32 edge_color_supression;
+ /* Noise reduction : range -127~127, default : 0 */
+ s32 noise_reduction;
+ /* (32*4 + 9)*4 = 548 bytes */
+};
+
+struct is_tune_region {
+ struct is_sensor_tune sensor_tune;
+ struct is_isp_tune isp_tune;
+};
+
+struct rational_t {
+ u32 num;
+ u32 den;
+};
+
+struct srational_t {
+ s32 num;
+ s32 den;
+};
+
+#define FLASH_FIRED_SHIFT 0
+#define FLASH_NOT_FIRED 0
+#define FLASH_FIRED 1
+
+#define FLASH_STROBE_SHIFT 1
+#define FLASH_STROBE_NO_DETECTION 0
+#define FLASH_STROBE_RESERVED 1
+#define FLASH_STROBE_RETURN_LIGHT_NOT_DETECTED 2
+#define FLASH_STROBE_RETURN_LIGHT_DETECTED 3
+
+#define FLASH_MODE_SHIFT 3
+#define FLASH_MODE_UNKNOWN 0
+#define FLASH_MODE_COMPULSORY_FLASH_FIRING 1
+#define FLASH_MODE_COMPULSORY_FLASH_SUPPRESSION 2
+#define FLASH_MODE_AUTO_MODE 3
+
+#define FLASH_FUNCTION_SHIFT 5
+#define FLASH_FUNCTION_PRESENT 0
+#define FLASH_FUNCTION_NONE 1
+
+#define FLASH_RED_EYE_SHIFT 6
+#define FLASH_RED_EYE_DISABLED 0
+#define FLASH_RED_EYE_SUPPORTED 1
+
+enum apex_aperture_value {
+ F1_0 = 0,
+ F1_4 = 1,
+ F2_0 = 2,
+ F2_8 = 3,
+ F4_0 = 4,
+ F5_6 = 5,
+ F8_9 = 6,
+ F11_0 = 7,
+ F16_0 = 8,
+ F22_0 = 9,
+ F32_0 = 10,
+};
+
+struct exif_attribute {
+ struct rational_t exposure_time;
+ struct srational_t shutter_speed;
+ u32 iso_speed_rating;
+ u32 flash;
+ struct srational_t brightness;
+};
+
+struct is_frame_header {
+ u32 valid;
+ u32 bad_mark;
+ u32 captured;
+ u32 frame_number;
+ struct exif_attribute exif;
+};
+
+struct is_fd_rect {
+ u32 offset_x;
+ u32 offset_y;
+ u32 width;
+ u32 height;
+};
+
+struct is_face_marker {
+ u32 frame_number;
+ struct is_fd_rect face;
+ struct is_fd_rect left_eye;
+ struct is_fd_rect right_eye;
+ struct is_fd_rect mouth;
+ u32 roll_angle;
+ u32 yaw_angle;
+ u32 confidence;
+ u32 is_tracked;
+ u32 tracked_face_id;
+ u32 smile_level;
+ u32 blink_level;
+};
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433) || defined(CONFIG_SOC_EXYNOS5422) || defined(CONFIG_SOC_EXYNOS4415)
+struct is_debug_region {
+ u32 frame_count;
+ u32 reserved[PARAMETER_MAX_MEMBER-1];
+};
+#endif
+
+#define MAX_FRAME_COUNT 8
+#define MAX_FRAME_COUNT_PREVIEW 4
+#define MAX_FRAME_COUNT_CAPTURE 1
+#define MAX_FACE_COUNT 16
+
+#define MAX_SHARED_COUNT 500
+
+struct is_region {
+ struct is_param_region parameter;
+ struct is_tune_region tune;
+ struct is_frame_header header[MAX_FRAME_COUNT];
+ struct is_face_marker face[MAX_FACE_COUNT];
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433) || defined(CONFIG_SOC_EXYNOS5422) || defined(CONFIG_SOC_EXYNOS4415)
+ struct is_debug_region debug;
+#endif
+ u32 shared[MAX_SHARED_COUNT];
+};
+
+struct is_time_measure_us {
+ u32 min_time_us;
+ u32 max_time_us;
+ u32 avrg_time_us;
+ u32 current_time_us;
+};
+
+struct is_debug_frame_descriptor {
+ u32 sensor_frame_time;
+ u32 sensor_exposure_time;
+ u32 sensor_analog_gain;
+ u32 req_lei;
+};
+
+#define MAX_FRAMEDESCRIPTOR_CONTEXT_NUM (30 * 20) /* 600 frame */
+#define MAX_VERSION_DISPLAY_BUF (32)
+
+struct is_share_region {
+ u32 frame_time;
+ u32 exposure_time;
+ u32 analog_gain;
+
+ u32 r_gain;
+ u32 g_gain;
+ u32 b_gain;
+
+ u32 af_position;
+ u32 af_status;
+ u32 af_scene_type;
+
+ u32 frame_descp_onoff_control;
+ u32 frame_descp_update_done;
+ u32 frame_descp_idx;
+ u32 frame_descp_max_idx;
+
+ struct is_debug_frame_descriptor
+ dbg_frame_descp_ctx[MAX_FRAMEDESCRIPTOR_CONTEXT_NUM];
+
+ u32 chip_id;
+ u32 chip_rev_no;
+ u8 ispfw_version_no[MAX_VERSION_DISPLAY_BUF];
+ u8 ispfw_version_date[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_version_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_revsion_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_version_date[MAX_VERSION_DISPLAY_BUF];
+
+ /*measure timing*/
+ struct is_time_measure_us isp_sdk_Time;
+};
+
+struct is_debug_control {
+ u32 write_point; /* 0~500KB boundary*/
+ u32 assert_flag; /* 0:Not Inovked, 1:Invoked*/
+ u32 pabort_flag; /* 0:Not Inovked, 1:Invoked*/
+ u32 dabort_flag; /* 0:Not Inovked, 1:Invoked*/
+ u32 pd_Ready_flag; /* 0:Normal, 1:EnterIdle(Ready to power down)*/
+ u32 isp_frameErr; /* Frame Error Count.*/
+ u32 drc_frame_err; /* Frame Error Count.*/
+ u32 scc_frame_err; /* Frame Error Count.*/
+ u32 odc_frame_err; /* Frame Error Count.*/
+ u32 dis_frame_err; /* Frame Error Count.*/
+ u32 tdnr_frame_err; /* Frame Error Count.*/
+ u32 scp_frame_err; /* Frame Error Count.*/
+ u32 fd_frame_err; /* Frame Error Count.*/
+ u32 isp_frame_drop; /* Frame Drop Count.*/
+ u32 drc_frame_drop; /* Frame Drop Count.*/
+ u32 dis_frame_drop; /* Frame Drop Count.*/
+ u32 fd_frame_drop;
+};
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_REGS_H
+#define FIMC_IS_REGS_H
+
+#include <mach/map.h>
+
+/* MCUCTL register */
+#define MCUCTL 0x0
+/* MCU Controller Register */
+#define MCUCTLR (MCUCTL+0x00)
+#define MCUCTLR_AXI_ISPX_AWCACHE(x) ((x) << 16)
+#define MCUCTLR_AXI_ISPX_ARCACHE(x) ((x) << 12)
+#define MCUCTLR_MSWRST (1 << 0)
+/* Boot Base OFfset Address Register */
+#define BBOAR (MCUCTL+0x04)
+#define BBOAR_BBOA(x) ((x) << 0)
+/* Interrupt Generation Register 0 from Host CPU to VIC */
+#define INTGR0 (MCUCTL+0x08)
+#define INTGR0_INTGC9 (1 << 25)
+#define INTGR0_INTGC8 (1 << 24)
+#define INTGR0_INTGC7 (1 << 23)
+#define INTGR0_INTGC6 (1 << 22)
+#define INTGR0_INTGC5 (1 << 21)
+#define INTGR0_INTGC4 (1 << 20)
+#define INTGR0_INTGC3 (1 << 19)
+#define INTGR0_INTGC2 (1 << 18)
+#define INTGR0_INTGC1 (1 << 17)
+#define INTGR0_INTGC0 (1 << 16)
+#define INTGR0_INTGD5 (1 << 5)
+#define INTGR0_INTGD4 (1 << 4)
+#define INTGR0_INTGD3 (1 << 3)
+#define INTGR0_INTGD2 (1 << 2)
+#define INTGR0_INTGD1 (1 << 1)
+#define INTGR0_INTGD0 (1 << 0)
+/* Interrupt Clear Register 0 from Host CPU to VIC */
+#define INTCR0 (MCUCTL+0x0c)
+#define INTCR0_INTCC9 (1 << 25)
+#define INTCR0_INTCC8 (1 << 24)
+#define INTCR0_INTCC7 (1 << 23)
+#define INTCR0_INTCC6 (1 << 22)
+#define INTCR0_INTCC5 (1 << 21)
+#define INTCR0_INTCC4 (1 << 20)
+#define INTCR0_INTCC3 (1 << 19)
+#define INTCR0_INTCC2 (1 << 18)
+#define INTCR0_INTCC1 (1 << 17)
+#define INTCR0_INTCC0 (1 << 16)
+#define INTCR0_INTCD5 (1 << 5)
+#define INTCR0_INTCD4 (1 << 4)
+#define INTCR0_INTCD3 (1 << 3)
+#define INTCR0_INTCD2 (1 << 2)
+#define INTCR0_INTCD1 (1 << 1)
+#define INTCR0_INTCD0 (1 << 0)
+/* Interrupt Mask Register 0 from Host CPU to VIC */
+#define INTMR0 (MCUCTL+0x10)
+#define INTMR0_INTMC9 (1 << 25)
+#define INTMR0_INTMC8 (1 << 24)
+#define INTMR0_INTMC7 (1 << 23)
+#define INTMR0_INTMC6 (1 << 22)
+#define INTMR0_INTMC5 (1 << 21)
+#define INTMR0_INTMC4 (1 << 20)
+#define INTMR0_INTMC3 (1 << 19)
+#define INTMR0_INTMC2 (1 << 18)
+#define INTMR0_INTMC1 (1 << 17)
+#define INTMR0_INTMC0 (1 << 16)
+#define INTMR0_INTMD5 (1 << 5)
+#define INTMR0_INTMD4 (1 << 4)
+#define INTMR0_INTMD3 (1 << 3)
+#define INTMR0_INTMD2 (1 << 2)
+#define INTMR0_INTMD1 (1 << 1)
+#define INTMR0_INTMD0 (1 << 0)
+/* Interrupt Status Register 0 from Host CPU to VIC */
+#define INTSR0 (MCUCTL+0x14)
+#define INTSR0_GET_INTSD0(x) (((x) >> 0) & 0x1)
+#define INTSR0_GET_INTSD1(x) (((x) >> 1) & 0x1)
+#define INTSR0_GET_INTSD2(x) (((x) >> 2) & 0x1)
+#define INTSR0_GET_INTSD3(x) (((x) >> 3) & 0x1)
+#define INTSR0_GET_INTSD4(x) (((x) >> 4) & 0x1)
+#define INTSR0_GET_INTSC0(x) (((x) >> 16) & 0x1)
+#define INTSR0_GET_INTSC1(x) (((x) >> 17) & 0x1)
+#define INTSR0_GET_INTSC2(x) (((x) >> 18) & 0x1)
+#define INTSR0_GET_INTSC3(x) (((x) >> 19) & 0x1)
+#define INTSR0_GET_INTSC4(x) (((x) >> 20) & 0x1)
+#define INTSR0_GET_INTSC5(x) (((x) >> 21) & 0x1)
+#define INTSR0_GET_INTSC6(x) (((x) >> 22) & 0x1)
+#define INTSR0_GET_INTSC7(x) (((x) >> 23) & 0x1)
+#define INTSR0_GET_INTSC8(x) (((x) >> 24) & 0x1)
+#define INTSR0_GET_INTSC9(x) (((x) >> 25) & 0x1)
+/* Interrupt Mask Status Register 0 from Host CPU to VIC */
+#define INTMSR0 (MCUCTL+0x18)
+#define INTMSR0_GET_INTMSD0(x) (((x) >> 0) & 0x1)
+#define INTMSR0_GET_INTMSD1(x) (((x) >> 1) & 0x1)
+#define INTMSR0_GET_INTMSD2(x) (((x) >> 2) & 0x1)
+#define INTMSR0_GET_INTMSD3(x) (((x) >> 3) & 0x1)
+#define INTMSR0_GET_INTMSD4(x) (((x) >> 4) & 0x1)
+#define INTMSR0_GET_INTMSC0(x) (((x) >> 16) & 0x1)
+#define INTMSR0_GET_INTMSC1(x) (((x) >> 17) & 0x1)
+#define INTMSR0_GET_INTMSC2(x) (((x) >> 18) & 0x1)
+#define INTMSR0_GET_INTMSC3(x) (((x) >> 19) & 0x1)
+#define INTMSR0_GET_INTMSC4(x) (((x) >> 20) & 0x1)
+#define INTMSR0_GET_INTMSC5(x) (((x) >> 21) & 0x1)
+#define INTMSR0_GET_INTMSC6(x) (((x) >> 22) & 0x1)
+#define INTMSR0_GET_INTMSC7(x) (((x) >> 23) & 0x1)
+#define INTMSR0_GET_INTMSC8(x) (((x) >> 24) & 0x1)
+#define INTMSR0_GET_INTMSC9(x) (((x) >> 25) & 0x1)
+/* Interrupt Generation Register 1 from ISP CPU to Host IC */
+#define INTGR1 (MCUCTL+0x1c)
+#define INTGR1_INTGC9 (1 << 9)
+#define INTGR1_INTGC8 (1 << 8)
+#define INTGR1_INTGC7 (1 << 7)
+#define INTGR1_INTGC6 (1 << 6)
+#define INTGR1_INTGC5 (1 << 5)
+#define INTGR1_INTGC4 (1 << 4)
+#define INTGR1_INTGC3 (1 << 3)
+#define INTGR1_INTGC2 (1 << 2)
+#define INTGR1_INTGC1 (1 << 1)
+#define INTGR1_INTGC0 (1 << 0)
+/* Interrupt Clear Register 1 from ISP CPU to Host IC */
+#define INTCR1 (MCUCTL+0x20)
+#define INTCR1_INTCC9 (1 << 9)
+#define INTCR1_INTCC8 (1 << 8)
+#define INTCR1_INTCC7 (1 << 7)
+#define INTCR1_INTCC6 (1 << 6)
+#define INTCR1_INTCC5 (1 << 5)
+#define INTCR1_INTCC4 (1 << 4)
+#define INTCR1_INTCC3 (1 << 3)
+#define INTCR1_INTCC2 (1 << 2)
+#define INTCR1_INTCC1 (1 << 1)
+#define INTCR1_INTCC0 (1 << 0)
+/* Interrupt Mask Register 1 from ISP CPU to Host IC */
+#define INTMR1 (MCUCTL+0x24)
+#define INTMR1_INTMC9 (1 << 9)
+#define INTMR1_INTMC8 (1 << 8)
+#define INTMR1_INTMC7 (1 << 7)
+#define INTMR1_INTMC6 (1 << 6)
+#define INTMR1_INTMC5 (1 << 5)
+#define INTMR1_INTMC4 (1 << 4)
+#define INTMR1_INTMC3 (1 << 3)
+#define INTMR1_INTMC2 (1 << 2)
+#define INTMR1_INTMC1 (1 << 1)
+#define INTMR1_INTMC0 (1 << 0)
+/* Interrupt Status Register 1 from ISP CPU to Host IC */
+#define INTSR1 (MCUCTL+0x28)
+/* Interrupt Mask Status Register 1 from ISP CPU to Host IC */
+#define INTMSR1 (MCUCTL+0x2c)
+/* Interrupt Clear Register 2 from ISP BLK's interrupts to Host IC */
+#define INTCR2 (MCUCTL+0x30)
+#define INTCR2_INTCC21 (1 << 21)
+#define INTCR2_INTCC20 (1 << 20)
+#define INTCR2_INTCC19 (1 << 19)
+#define INTCR2_INTCC18 (1 << 18)
+#define INTCR2_INTCC17 (1 << 17)
+#define INTCR2_INTCC16 (1 << 16)
+/* Interrupt Mask Register 2 from ISP BLK's interrupts to Host IC */
+#define INTMR2 (MCUCTL+0x34)
+#define INTMR2_INTMCIS25 (1 << 25)
+#define INTMR2_INTMCIS24 (1 << 24)
+#define INTMR2_INTMCIS23 (1 << 23)
+#define INTMR2_INTMCIS22 (1 << 22)
+#define INTMR2_INTMCIS21 (1 << 21)
+#define INTMR2_INTMCIS20 (1 << 20)
+#define INTMR2_INTMCIS19 (1 << 19)
+#define INTMR2_INTMCIS18 (1 << 18)
+#define INTMR2_INTMCIS17 (1 << 17)
+#define INTMR2_INTMCIS16 (1 << 16)
+#define INTMR2_INTMCIS15 (1 << 15)
+#define INTMR2_INTMCIS14 (1 << 14)
+#define INTMR2_INTMCIS13 (1 << 13)
+#define INTMR2_INTMCIS12 (1 << 12)
+#define INTMR2_INTMCIS11 (1 << 11)
+#define INTMR2_INTMCIS10 (1 << 10)
+#define INTMR2_INTMCIS9 (1 << 9)
+#define INTMR2_INTMCIS8 (1 << 8)
+#define INTMR2_INTMCIS7 (1 << 7)
+#define INTMR2_INTMCIS6 (1 << 6)
+#define INTMR2_INTMCIS5 (1 << 5)
+#define INTMR2_INTMCIS4 (1 << 4)
+#define INTMR2_INTMCIS3 (1 << 3)
+#define INTMR2_INTMCIS2 (1 << 2)
+#define INTMR2_INTMCIS1 (1 << 1)
+#define INTMR2_INTMCIS0 (1 << 0)
+/* Interrupt Status Register 2 from ISP BLK's interrupts to Host IC */
+#define INTSR2 (MCUCTL+0x38)
+/* Interrupt Mask Status Register 2 from ISP BLK's interrupts to Host IC */
+#define INTMSR2 (MCUCTL+0x3c)
+/* General Purpose Output Control Register (0~17) */
+#define GPOCTLR (MCUCTL+0x40)
+#define GPOCTLR_GPOG17(x) ((x) << 17)
+#define GPOCTLR_GPOG16(x) ((x) << 16)
+#define GPOCTLR_GPOG15(x) ((x) << 15)
+#define GPOCTLR_GPOG14(x) ((x) << 14)
+#define GPOCTLR_GPOG13(x) ((x) << 13)
+#define GPOCTLR_GPOG12(x) ((x) << 12)
+#define GPOCTLR_GPOG11(x) ((x) << 11)
+#define GPOCTLR_GPOG10(x) ((x) << 10)
+#define GPOCTLR_GPOG9(x) ((x) << 9)
+#define GPOCTLR_GPOG8(x) ((x) << 8)
+#define GPOCTLR_GPOG7(x) ((x) << 7)
+#define GPOCTLR_GPOG6(x) ((x) << 6)
+#define GPOCTLR_GPOG5(x) ((x) << 5)
+#define GPOCTLR_GPOG4(x) ((x) << 4)
+#define GPOCTLR_GPOG3(x) ((x) << 3)
+#define GPOCTLR_GPOG2(x) ((x) << 2)
+#define GPOCTLR_GPOG1(x) ((x) << 1)
+#define GPOCTLR_GPOG0(x) ((x) << 0)
+/* General Purpose Pad Output Enable Register (0~17) */
+#define GPOENCTLR (MCUCTL+0x44)
+#define GPOENCTLR_GPOEN17(x) ((x) << 17)
+#define GPOENCTLR_GPOEN16(x) ((x) << 16)
+#define GPOENCTLR_GPOEN15(x) ((x) << 15)
+#define GPOENCTLR_GPOEN14(x) ((x) << 14)
+#define GPOENCTLR_GPOEN13(x) ((x) << 13)
+#define GPOENCTLR_GPOEN12(x) ((x) << 12)
+#define GPOENCTLR_GPOEN11(x) ((x) << 11)
+#define GPOENCTLR_GPOEN10(x) ((x) << 10)
+#define GPOENCTLR_GPOEN9(x) ((x) << 9)
+#define GPOENCTLR_GPOEN8(x) ((x) << 8)
+#define GPOENCTLR_GPOEN7(x) ((x) << 7)
+#define GPOENCTLR_GPOEN6(x) ((x) << 6)
+#define GPOENCTLR_GPOEN5(x) ((x) << 5)
+#define GPOENCTLR_GPOEN4(x) ((x) << 4)
+#define GPOENCTLR_GPOEN3(x) ((x) << 3)
+#define GPOENCTLR_GPOEN2(x) ((x) << 2)
+#define GPOENCTLR_GPOEN1(x) ((x) << 1)
+#define GPOENCTLR_GPOEN0(x) ((x) << 0)
+/* General Purpose Input Control Register (0~17) */
+#define GPICTLR (MCUCTL+0x48)
+/* IS Shared Register 0 between ISP CPU and HOST CPU */
+#define ISSR0 (MCUCTL+0x80)
+/* Command Host -> IS */
+/* IS Shared Register 1 between ISP CPU and HOST CPU */
+/* Sensor ID for Command */
+#define ISSR1 (MCUCTL+0x84)
+/* IS Shared Register 2 between ISP CPU and HOST CPU */
+/* Parameter 1 */
+#define ISSR2 (MCUCTL+0x88)
+/* IS Shared Register 3 between ISP CPU and HOST CPU */
+/* Parameter 2 */
+#define ISSR3 (MCUCTL+0x8c)
+/* IS Shared Register 4 between ISP CPU and HOST CPU */
+/* Parameter 3 */
+#define ISSR4 (MCUCTL+0x90)
+/* IS Shared Register 5 between ISP CPU and HOST CPU */
+/* Parameter 4 */
+#define ISSR5 (MCUCTL+0x94)
+#define ISSR6 (MCUCTL+0x98)
+#define ISSR7 (MCUCTL+0x9c)
+#define ISSR8 (MCUCTL+0xa0)
+#define ISSR9 (MCUCTL+0xa4)
+/* IS Shared Register 10 between ISP CPU and HOST CPU */
+/* Command IS -> Host */
+#define ISSR10 (MCUCTL+0xa8)
+/* IS Shared Register 11 between ISP CPU and HOST CPU */
+/* Sensor ID for Command */
+#define ISSR11 (MCUCTL+0xac)
+/* IS Shared Register 12 between ISP CPU and HOST CPU */
+/* Parameter 1 */
+#define ISSR12 (MCUCTL+0xb0)
+/* IS Shared Register 13 between ISP CPU and HOST CPU */
+/* Parameter 2 */
+#define ISSR13 (MCUCTL+0xb4)
+/* IS Shared Register 14 between ISP CPU and HOST CPU */
+/* Parameter 3 */
+#define ISSR14 (MCUCTL+0xb8)
+/* IS Shared Register 15 between ISP CPU and HOST CPU */
+/* Parameter 4 */
+#define ISSR15 (MCUCTL+0xbc)
+#define ISSR16 (MCUCTL+0xc0)
+#define ISSR17 (MCUCTL+0xc4)
+#define ISSR18 (MCUCTL+0xc8)
+#define ISSR19 (MCUCTL+0xcc)
+/* IS Shared Register 20 between ISP CPU and HOST CPU */
+/* ISP_FRAME_DONE : SENSOR ID */
+#define ISSR20 (MCUCTL+0xd0)
+/* IS Shared Register 21 between ISP CPU and HOST CPU */
+/* ISP_FRAME_DONE : PARAMETER 1 */
+#define ISSR21 (MCUCTL+0xd4)
+#define ISSR22 (MCUCTL+0xd8)
+#define ISSR23 (MCUCTL+0xdc)
+/* IS Shared Register 24 between ISP CPU and HOST CPU */
+/* SCALERC_FRAME_DONE : SENSOR ID */
+#define ISSR24 (MCUCTL+0xe0)
+/* IS Shared Register 25 between ISP CPU and HOST CPU */
+/* SCALERC_FRAME_DONE : PARAMETER 1 */
+#define ISSR25 (MCUCTL+0xe4)
+#define ISSR26 (MCUCTL+0xe8)
+#define ISSR27 (MCUCTL+0xec)
+/* IS Shared Register 28 between ISP CPU and HOST CPU */
+/* 3DNR_FRAME_DONE : SENSOR ID */
+#define ISSR28 (MCUCTL+0xf0)
+/* IS Shared Register 29 between ISP CPU and HOST CPU */
+/* 3DNR_FRAME_DONE : PARAMETER 1 */
+#define ISSR29 (MCUCTL+0xf4)
+#define ISSR30 (MCUCTL+0xf8)
+#define ISSR31 (MCUCTL+0xfc)
+/* IS Shared Register 32 between ISP CPU and HOST CPU */
+/* SCALERP_FRAME_DONE : SENSOR ID */
+#define ISSR32 (MCUCTL+0x100)
+/* IS Shared Register 33 between ISP CPU and HOST CPU */
+/* SCALERP_FRAME_DONE : PARAMETER 1 */
+#define ISSR33 (MCUCTL+0x104)
+#define ISSR34 (MCUCTL+0x108)
+#define ISSR35 (MCUCTL+0x10c)
+#define ISSR36 (MCUCTL+0x110)
+#define ISSR37 (MCUCTL+0x114)
+#define ISSR38 (MCUCTL+0x118)
+#define ISSR39 (MCUCTL+0x11c)
+#define ISSR40 (MCUCTL+0x120)
+#define ISSR41 (MCUCTL+0x124)
+#define ISSR42 (MCUCTL+0x128)
+#define ISSR43 (MCUCTL+0x12c)
+#define ISSR44 (MCUCTL+0x130)
+#define ISSR45 (MCUCTL+0x134)
+#define ISSR46 (MCUCTL+0x138)
+#define ISSR47 (MCUCTL+0x13c)
+#define ISSR48 (MCUCTL+0x140)
+#define ISSR49 (MCUCTL+0x144)
+#define ISSR50 (MCUCTL+0x148)
+#define ISSR51 (MCUCTL+0x14c)
+#define ISSR52 (MCUCTL+0x150)
+#define ISSR53 (MCUCTL+0x154)
+#define ISSR54 (MCUCTL+0x158)
+#define ISSR55 (MCUCTL+0x15c)
+#define ISSR56 (MCUCTL+0x160)
+#define ISSR57 (MCUCTL+0x164)
+#define ISSR58 (MCUCTL+0x168)
+#define ISSR59 (MCUCTL+0x16c)
+#define ISSR60 (MCUCTL+0x170)
+#define ISSR61 (MCUCTL+0x174)
+#define ISSR62 (MCUCTL+0x178)
+#define ISSR63 (MCUCTL+0x17c)
+
+/* PMU for FIMC-IS*/
+#if defined(CONFIG_SOC_EXYNOS4415)
+#define PMUREG_CMU_RESET_ISP0_SYS_PWR (S5P_VA_PMU + 0x1594)
+#define PMUREG_ISP0_CONFIGURATION (S5P_VA_PMU + 0x40A0)
+#define PMUREG_ISP0_STATUS (S5P_VA_PMU + 0x40A4)
+#define PMUREG_ISP0_OPTION (S5P_VA_PMU + 0x40A8)
+
+#define PMUREG_CMU_RESET_ISP1_SYS_PWR (S5P_VA_PMU + 0x159C)
+#define PMUREG_ISP1_CONFIGURATION (S5P_VA_PMU + 0x40E0)
+#define PMUREG_ISP1_STATUS (S5P_VA_PMU + 0x40E4)
+#define PMUREG_ISP1_OPTION (S5P_VA_PMU + 0x40E8)
+
+#define PMUREG_CENTRAL_SEQ_OPTION (S5P_VA_PMU + 0x0208)
+#define PMUREG_ISP_ARM_SYS_PWR_REG (S5P_VA_PMU + 0x1050)
+#define PMUREG_ISP_ARM_CONFIGURATION (S5P_VA_PMU + 0x2280)
+#define PMUREG_ISP_ARM_STATUS (S5P_VA_PMU + 0x2284)
+#define PMUREG_ISP_ARM_OPTION (S5P_VA_PMU + 0x2288)
+
+#define PMUREG_ISP_LOW_POWER_OFF (S5P_VA_PMU + 0x0004)
+
+#define PMUREG_ISP0_STATUS (S5P_VA_PMU + 0x40A4)
+#define PMUREG_ISP1_STATUS (S5P_VA_PMU + 0x40E4)
+
+#define MIPICSI0_REG_BASE (S5P_VA_MIPICSI0) /* phy : 0x120C_0000 */
+#define MIPICSI1_REG_BASE (S5P_VA_MIPICSI1) /* phy : 0x120D_0000 */
+#define MIPICSI2_REG_BASE 0
+
+#define FIMCLITE0_REG_BASE (S5P_VA_FIMCLITE0) /* phy : 0x120A0000 */
+#define FIMCLITE1_REG_BASE (S5P_VA_FIMCLITE1) /* phy : 0x120B0000 */
+#define FIMCLITE2_REG_BASE (S5P_VA_FIMCLITE2) /* phy : 0x122A0000 */
+
+#define PA_FIMC_IS_GIC_C (0x121E0000)
+#define PA_FIMC_IS_GIC_D (0x121F0000)
+#else
+#define MIPICSI0_REG_BASE (S5P_VA_MIPICSI0)
+#define MIPICSI1_REG_BASE (S5P_VA_MIPICSI1)
+#define MIPICSI2_REG_BASE (S5P_VA_MIPICSI2)
+
+#define FIMCLITE0_REG_BASE (S5P_VA_FIMCLITE0)
+#define FIMCLITE1_REG_BASE (S5P_VA_FIMCLITE1)
+#define FIMCLITE2_REG_BASE (S5P_VA_FIMCLITE2)
+
+#if defined(CONFIG_SOC_EXYNOS3470)
+#define PMUREG_ISP_ARM_CONFIGURATION (S5P_VA_PMU + 0x2280)
+#define PMUREG_ISP_ARM_STATUS (S5P_VA_PMU + 0x2284)
+#define PMUREG_ISP_ARM_OPTION (S5P_VA_PMU + 0x2288)
+#define PMUREG_ISP_LOW_POWER_OFF (S5P_VA_PMU + 0x0004)
+#define PMUREG_ISP_CONFIGURATION (S5P_VA_PMU + 0x3CA0)
+#define PMUREG_ISP_STATUS (S5P_VA_PMU + 0x3CA4)
+#define PMUREG_ISP_ARM_SYS_PWR_REG (S5P_VA_PMU + 0x1050)
+#elif defined(CONFIG_SOC_EXYNOS5422)
+#define PMUREG_ISP_ARM_CONFIGURATION (S5P_VA_PMU + 0x2480)
+#define PMUREG_ISP_ARM_STATUS (S5P_VA_PMU + 0x2484)
+#define PMUREG_ISP_ARM_OPTION (S5P_VA_PMU + 0x2488)
+#define PMUREG_ISP_LOW_POWER_OFF (S5P_VA_PMU + 0x0004)
+#define PMUREG_ISP_CONFIGURATION (S5P_VA_PMU + 0x4020)
+#define PMUREG_ISP_STATUS (S5P_VA_PMU + 0x4024)
+#define PMUREG_CMU_RESET_ISP_SYS_PWR_REG (S5P_VA_PMU + 0x1584)
+#define PMUREG_CMU_SYSCLK_ISP_SYS_PWR_REG (S5P_VA_PMU + 0x14C4)
+#define PMUREG_ISP_ARM_SYS_PWR_REG (S5P_VA_PMU + 0x1090)
+#define PMUREG_CAM_CONFIGURATION (S5P_VA_PMU + 0x5100)
+#define PMUREG_CAM_STATUS (S5P_VA_PMU + 0x5104)
+#else
+#define PMUREG_ISP_ARM_CONFIGURATION (S5P_VA_PMU + 0x2580)
+#define PMUREG_ISP_ARM_STATUS (S5P_VA_PMU + 0x2584)
+#define PMUREG_ISP_ARM_OPTION (S5P_VA_PMU + 0x2588)
+#define PMUREG_ISP_LOW_POWER_OFF (S5P_VA_PMU + 0x0004)
+#define PMUREG_ISP_CONFIGURATION (S5P_VA_PMU + 0x4140)
+#define PMUREG_ISP_STATUS (S5P_VA_PMU + 0x4144)
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+#define PMUREG_CAM0_STATUS (S5P_VA_PMU + 0x4024)
+#define PMUREG_CAM1_STATUS (S5P_VA_PMU + 0x40A4)
+#endif
+
+#define SYSREG_GSCBLK_CFG1 (S3C_VA_SYS + 0x0224)
+#define SYSREG_ISPBLK_CFG (S3C_VA_SYS + 0x022C)
+
+/* GIC for FIMC-IS*/
+#if defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+#define PA_FIMC_IS_GIC_C (0x141E0000)
+#define PA_FIMC_IS_GIC_D (0x141F0000)
+#elif defined(CONFIG_SOC_EXYNOS3470)
+#define PA_FIMC_IS_GIC_C (0x121E0000)
+#define PA_FIMC_IS_GIC_D (0x121F0000)
+#else
+#define PA_FIMC_IS_GIC_C (0x131E0000)
+#define PA_FIMC_IS_GIC_D (0x131F0000)
+#endif
+#endif
+
+/* PWM for FIMC-IS*/
+#define FIMC_IS_PWM_TCNTB0 (0xC)
+
+#endif
--- /dev/null
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "fimc-is-resourcemgr.h"
+#include "fimc-is-core.h"
+#include "fimc-is-dvfs.h"
+#include "fimc-is-clk-gate.h"
+#include "fimc-is-hw.h"
+
+struct pm_qos_request exynos_isp_qos_cpu_min;
+struct pm_qos_request exynos_isp_qos_cpu_max;
+struct pm_qos_request exynos_isp_qos_int;
+struct pm_qos_request exynos_isp_qos_mem;
+struct pm_qos_request exynos_isp_qos_cam;
+struct pm_qos_request exynos_isp_qos_disp;
+#if defined(CONFIG_SOC_EXYNOS5422) || defined(CONFIG_SOC_EXYNOS5430) || defined(CONFIG_SOC_EXYNOS5433)
+struct pm_qos_request max_cpu_qos;
+#endif
+
+extern struct fimc_is_sysfs_debug sysfs_debug;
+
+int fimc_is_resource_probe(struct fimc_is_resourcemgr *resourcemgr,
+ void *private_data)
+{
+ int ret = 0;
+
+ BUG_ON(!resourcemgr);
+ BUG_ON(!private_data);
+
+ resourcemgr->private_data = private_data;
+
+ atomic_set(&resourcemgr->rsccount, 0);
+ atomic_set(&resourcemgr->resource_sensor0.rsccount, 0);
+ atomic_set(&resourcemgr->resource_sensor1.rsccount, 0);
+ atomic_set(&resourcemgr->resource_ischain.rsccount, 0);
+
+#ifdef ENABLE_DVFS
+ /* dvfs controller init */
+ ret = fimc_is_dvfs_init(resourcemgr);
+ if (ret)
+ err("%s: fimc_is_dvfs_init failed!\n", __func__);
+#endif
+
+ info("%s\n", __func__);
+ return ret;
+}
+
+int fimc_is_resource_get(struct fimc_is_resourcemgr *resourcemgr, u32 rsc_type)
+{
+ int ret = 0;
+ u32 rsccount;
+ struct fimc_is_resource *resource;
+ struct fimc_is_core *core;
+
+ BUG_ON(!resourcemgr);
+ BUG_ON(!resourcemgr->private_data);
+ BUG_ON(rsc_type >= RESOURCE_TYPE_MAX);
+
+ resource = GET_RESOURCE(resourcemgr, rsc_type);
+ core = (struct fimc_is_core *)resourcemgr->private_data;
+ rsccount = atomic_read(&core->rsccount);
+
+ if (rsccount >= 5) {
+ err("[RSC] Invalid rsccount(%d)", rsccount);
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+ if (rsccount == 0) {
+#ifdef ENABLE_DVFS
+ /* dvfs controller init */
+ ret = fimc_is_dvfs_init(resourcemgr);
+ if (ret) {
+ err("%s: fimc_is_dvfs_init failed!\n", __func__);
+ goto p_err;
+ }
+#endif
+ }
+
+ if (atomic_read(&resource->rsccount) == 0) {
+ switch (rsc_type) {
+ case RESOURCE_TYPE_SENSOR0:
+ break;
+ case RESOURCE_TYPE_SENSOR1:
+ break;
+ case RESOURCE_TYPE_ISCHAIN:
+ core->debug_cnt = 0;
+
+ ret = fimc_is_interface_open(&core->interface);
+ if (ret) {
+ err("fimc_is_interface_open is fail(%d)", ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_power(&core->ischain[0], 1);
+ if (ret) {
+ err("fimc_is_ischain_power is fail (%d)", ret);
+ goto p_err;
+ }
+
+ /* W/A for a lower version MCUCTL */
+ fimc_is_interface_reset(&core->interface);
+
+#ifdef ENABLE_CLOCK_GATE
+ if (sysfs_debug.en_clk_gate &&
+ sysfs_debug.clk_gate_mode == CLOCK_GATE_MODE_HOST)
+ fimc_is_clk_gate_init(core);
+#endif
+ break;
+ default:
+ err("[RSC] resource type(%d) is invalid", rsc_type);
+ BUG();
+ break;
+ }
+ }
+
+ atomic_inc(&resource->rsccount);
+ atomic_inc(&core->rsccount);
+
+p_err:
+ info("[RSC] rsctype : %d, rsccount : %d\n", rsc_type, rsccount);
+ return ret;
+}
+
+int fimc_is_resource_put(struct fimc_is_resourcemgr *resourcemgr, u32 rsc_type)
+{
+ int ret = 0;
+ u32 rsccount;
+ struct fimc_is_resource *resource;
+ struct fimc_is_core *core;
+
+ BUG_ON(!resourcemgr);
+ BUG_ON(!resourcemgr->private_data);
+ BUG_ON(rsc_type >= RESOURCE_TYPE_MAX);
+
+ resource = GET_RESOURCE(resourcemgr, rsc_type);
+ core = (struct fimc_is_core *)resourcemgr->private_data;
+ rsccount = atomic_read(&core->rsccount);
+
+ if (rsccount == 0) {
+ err("[RSC] Invalid rsccount(%d)\n", rsccount);
+ ret = -EMFILE;
+ goto p_err;
+ }
+
+ if (atomic_read(&resource->rsccount) == 1) {
+ switch (rsc_type) {
+ case RESOURCE_TYPE_SENSOR0:
+ break;
+ case RESOURCE_TYPE_SENSOR1:
+ break;
+ case RESOURCE_TYPE_ISCHAIN:
+ ret = fimc_is_itf_power_down(&core->interface);
+ if (ret)
+ err("power down cmd is fail(%d)", ret);
+
+ ret = fimc_is_ischain_power(&core->ischain[0], 0);
+ if (ret)
+ err("fimc_is_ischain_power is fail(%d)", ret);
+
+ ret = fimc_is_interface_close(&core->interface);
+ if (ret)
+ err("fimc_is_interface_close is fail(%d)", ret);
+#ifndef RESERVED_MEM
+ /* 5. Dealloc memroy */
+ ret = fimc_is_ishcain_deinitmem(&core->ischain[0]);
+ if (ret)
+ err("fimc_is_ishcain_deinitmem is fail(%d)", ret);
+#endif
+ break;
+
+ default:
+ err("[RSC] resource type(%d) is invalid", rsc_type);
+ BUG();
+ break;
+ }
+ }
+
+ /* global update */
+ if (atomic_read(&core->rsccount) == 1) {
+ ret = fimc_is_runtime_suspend_post(NULL);
+ if (ret)
+ err("fimc_is_runtime_suspend_post is fail(%d)", ret);
+ }
+
+ atomic_dec(&resource->rsccount);
+ atomic_dec(&core->rsccount);
+
+p_err:
+ info("[RSC] rsctype : %d, rsccount : %d\n", rsc_type, rsccount);
+ return ret;
+}
+
+int fimc_is_logsync(struct fimc_is_interface *itf, u32 sync_id, u32 msg_test_id)
+{
+ int ret = 0;
+
+ /* print kernel sync log */
+ log_sync(sync_id);
+
+#ifdef ENABLE_FW_SYNC_LOG
+ ret = fimc_is_hw_msg_test(itf, sync_id, msg_test_id);
+ if (ret)
+ err("fimc_is_hw_msg_test(%d)", ret);
+#endif
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_RESOURCE_MGR_H
+#define FIMC_IS_RESOURCE_MGR_H
+
+#include "fimc-is-groupmgr.h"
+#include "fimc-is-interface.h"
+
+#define RESOURCE_TYPE_SENSOR0 0
+#define RESOURCE_TYPE_SENSOR1 1
+#define RESOURCE_TYPE_ISCHAIN 2
+#define RESOURCE_TYPE_MAX 3
+
+struct fimc_is_dvfs_ctrl {
+ struct mutex lock;
+ int cur_cpu_min_qos;
+ int cur_cpu_max_qos;
+ int cur_int_qos;
+ int cur_mif_qos;
+ int cur_cam_qos;
+ int cur_i2c_qos;
+ int cur_disp_qos;
+
+ struct fimc_is_dvfs_scenario_ctrl *static_ctrl;
+ struct fimc_is_dvfs_scenario_ctrl *dynamic_ctrl;
+};
+
+struct fimc_is_clk_gate_ctrl {
+ spinlock_t lock;
+ unsigned long msk_state;
+ int msk_cnt[GROUP_ID_MAX];
+ u32 msk_lock_by_ischain[FIMC_IS_MAX_NODES];
+ struct exynos_fimc_is_clk_gate_info *gate_info;
+ u32 msk_clk_on_off_state; /* on/off(1/0) state per ip */
+ /*
+ * For check that there's too long clock-on period.
+ * This var will increase when clock on,
+ * And will decrease when clock off.
+ */
+ unsigned long chk_on_off_cnt[GROUP_ID_MAX];
+};
+
+struct fimc_is_resource {
+ struct platform_device *pdev;
+ void __iomem *regs;
+ atomic_t rsccount;
+ u32 private_data;
+};
+
+struct fimc_is_resourcemgr {
+ atomic_t rsccount;
+ atomic_t rsccount_module; /* sensor module */
+ struct fimc_is_resource resource_sensor0;
+ struct fimc_is_resource resource_sensor1;
+ struct fimc_is_resource resource_ischain;
+
+ struct fimc_is_dvfs_ctrl dvfs_ctrl;
+ struct fimc_is_clk_gate_ctrl clk_gate_ctrl;
+
+ void *private_data;
+};
+
+int fimc_is_resource_probe(struct fimc_is_resourcemgr *resourcemgr,
+ void *private_data);
+int fimc_is_resource_get(struct fimc_is_resourcemgr *resourcemgr, u32 rsc_type);
+int fimc_is_resource_put(struct fimc_is_resourcemgr *resourcemgr, u32 rsc_type);
+int fimc_is_logsync(struct fimc_is_interface *itf, u32 sync_id, u32 msg_test_id);
+
+
+#define GET_RESOURCE(resourcemgr, type) \
+ ((type == RESOURCE_TYPE_SENSOR0) ? &resourcemgr->resource_sensor0 : \
+ ((type == RESOURCE_TYPE_SENSOR1) ? &resourcemgr->resource_sensor1 : \
+ &resourcemgr->resource_ischain))
+
+#endif
--- /dev/null
+#include "fimc-is-sec-define.h"
+#include <mach/pinctrl-samsung.h>
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+#include <linux/i2c.h>
+#endif
+
+bool crc32_fw_check = true;
+bool crc32_check = true;
+bool crc32_check_factory = true;
+bool crc32_header_check = true;
+bool crc32_check_front = true;
+bool crc32_header_check_front = true;
+bool crc32_check_factory_front = true;
+bool fw_version_crc_check = true;
+bool is_latest_cam_module = false;
+bool is_final_cam_module = false;
+#if defined(CONFIG_SOC_EXYNOS5433)
+bool is_right_prj_name = true;
+#endif
+#ifdef CONFIG_COMPANION_USE
+bool crc32_c1_fw_check = true;
+bool crc32_c1_check = true;
+bool crc32_c1_check_factory = true;
+bool companion_lsc_isvalid = false;
+bool companion_coef_isvalid = false;
+#endif
+u8 cal_map_version[4] = {0,};
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+#define FIMC_IS_MAX_CAL_SIZE (8 * 1024)
+#else
+#define FIMC_IS_MAX_CAL_SIZE (64 * 1024)
+#endif
+#define FIMC_IS_MAX_CAL_SIZE_FRONT (8 * 1024)
+
+#define FIMC_IS_DEFAULT_CAL_SIZE (20 * 1024)
+#define FIMC_IS_DUMP_CAL_SIZE (172 * 1024)
+#define FIMC_IS_LATEST_FROM_VERSION_B 'B'
+#define FIMC_IS_LATEST_FROM_VERSION_C 'C'
+#define FIMC_IS_LATEST_FROM_VERSION_D 'D'
+#define FIMC_IS_LATEST_FROM_VERSION_M 'M'
+
+
+//static bool is_caldata_read = false;
+//static bool is_c1_caldata_read = false;
+static bool force_caldata_dump = false;
+static int cam_id = CAMERA_SINGLE_REAR;
+bool is_dumped_fw_loading_needed = false;
+bool is_dumped_c1_fw_loading_needed = false;
+char fw_core_version;
+//struct class *camera_class;
+//struct device *camera_front_dev; /*sys/class/camera/front*/
+//struct device *camera_rear_dev; /*sys/class/camera/rear*/
+static struct fimc_is_from_info sysfs_finfo;
+static struct fimc_is_from_info sysfs_pinfo;
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+static struct fimc_is_from_info sysfs_finfo_front;
+static struct fimc_is_from_info sysfs_pinfo_front;
+static char cal_buf_front[FIMC_IS_MAX_CAL_SIZE_FRONT];
+#endif
+
+static char cal_buf[FIMC_IS_MAX_CAL_SIZE];
+char loaded_fw[12] = {0, };
+char loaded_companion_fw[30] = {0, };
+
+int fimc_is_sec_set_force_caldata_dump(bool fcd)
+{
+ force_caldata_dump = fcd;
+ if (fcd)
+ pr_info("forced caldata dump enabled!!\n");
+ return 0;
+}
+
+int fimc_is_sec_get_sysfs_finfo(struct fimc_is_from_info **finfo)
+{
+ *finfo = &sysfs_finfo;
+ return 0;
+}
+
+int fimc_is_sec_get_sysfs_pinfo(struct fimc_is_from_info **pinfo)
+{
+ *pinfo = &sysfs_pinfo;
+ return 0;
+}
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+int fimc_is_sec_get_sysfs_finfo_front(struct fimc_is_from_info **finfo)
+{
+ *finfo = &sysfs_finfo_front;
+ return 0;
+}
+
+int fimc_is_sec_get_sysfs_pinfo_front(struct fimc_is_from_info **pinfo)
+{
+ *pinfo = &sysfs_pinfo_front;
+ return 0;
+}
+
+int fimc_is_sec_get_front_cal_buf(char **buf)
+{
+ *buf = &cal_buf_front[0];
+ return 0;
+}
+#endif
+
+int fimc_is_sec_get_cal_buf(char **buf)
+{
+ *buf = &cal_buf[0];
+ return 0;
+}
+
+int fimc_is_sec_get_loaded_fw(char **buf)
+{
+ *buf = &loaded_fw[0];
+ return 0;
+}
+
+int fimc_is_sec_get_loaded_c1_fw(char **buf)
+{
+ *buf = &loaded_companion_fw[0];
+ return 0;
+}
+
+int fimc_is_sec_set_camid(int id)
+{
+ cam_id = id;
+ return 0;
+}
+
+int fimc_is_sec_get_camid(void)
+{
+ return cam_id;
+}
+
+int fimc_is_sec_get_camid_from_hal(char *fw_name, char *setf_name)
+{
+#if 0
+ char buf[1];
+ loff_t pos = 0;
+ int pixelSize;
+
+ read_data_from_file("/data/CameraID.txt", buf, 1, &pos);
+ if (buf[0] == '0')
+ cam_id = CAMERA_SINGLE_REAR;
+ else if (buf[0] == '1')
+ cam_id = CAMERA_SINGLE_FRONT;
+ else if (buf[0] == '2')
+ cam_id = CAMERA_DUAL_REAR;
+ else if (buf[0] == '3')
+ cam_id = CAMERA_DUAL_FRONT;
+
+ if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_3L2)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_3L2), "%s", FIMC_IS_FW_3L2);
+ snprintf(setf_name, sizeof(FIMC_IS_3L2_SETF), "%s", FIMC_IS_3L2_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_IMX135)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW), "%s", FIMC_IS_FW);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX135_SETF), "%s", FIMC_IS_IMX135_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_IMX134)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_IMX134), "%s", FIMC_IS_FW_IMX134);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX134_SETF), "%s", FIMC_IS_IMX134_SETF);
+ } else {
+ pixelSize = fimc_is_sec_get_pixel_size(sysfs_finfo.header_ver);
+ if (pixelSize == 13) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW), "%s", FIMC_IS_FW);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX135_SETF), "%s", FIMC_IS_IMX135_SETF);
+ } else if (pixelSize == 8) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_IMX134), "%s", FIMC_IS_FW_IMX134);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX134_SETF), "%s", FIMC_IS_IMX134_SETF);
+ } else {
+ snprintf(fw_name, sizeof(FIMC_IS_FW), "%s", FIMC_IS_FW);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX135_SETF), "%s", FIMC_IS_IMX135_SETF);
+ }
+ }
+
+ if (cam_id == CAMERA_SINGLE_FRONT ||
+ cam_id == CAMERA_DUAL_FRONT) {
+ snprintf(setf_name, sizeof(FIMC_IS_6B2_SETF), "%s", FIMC_IS_6B2_SETF);
+ }
+#else
+ pr_err("%s: waring, you're calling the disabled func!\n\n", __func__);
+#endif
+ return 0;
+}
+
+int fimc_is_sec_fw_revision(char *fw_ver)
+{
+ int revision = 0;
+ revision = revision + ((int)fw_ver[FW_PUB_YEAR] - 58) * 10000;
+ revision = revision + ((int)fw_ver[FW_PUB_MON] - 64) * 100;
+ revision = revision + ((int)fw_ver[FW_PUB_NUM] - 48) * 10;
+ revision = revision + (int)fw_ver[FW_PUB_NUM + 1] - 48;
+
+ return revision;
+}
+
+bool fimc_is_sec_fw_module_compare(char *fw_ver1, char *fw_ver2)
+{
+ if (fw_ver1[FW_CORE_VER] != fw_ver2[FW_CORE_VER]
+ || fw_ver1[FW_PIXEL_SIZE] != fw_ver2[FW_PIXEL_SIZE]
+ || fw_ver1[FW_PIXEL_SIZE + 1] != fw_ver2[FW_PIXEL_SIZE + 1]
+ || fw_ver1[FW_ISP_COMPANY] != fw_ver2[FW_ISP_COMPANY]
+ || fw_ver1[FW_SENSOR_MAKER] != fw_ver2[FW_SENSOR_MAKER]) {
+ return false;
+ }
+
+ return true;
+}
+
+bool fimc_is_sec_check_cal_crc32(char *buf, int id)
+{
+ u32 *buf32 = NULL;
+ u32 checksum;
+ u32 check_base;
+ u32 check_length;
+ u32 checksum_base;
+ bool crc32_temp, crc32_header_temp;
+ struct fimc_is_from_info *finfo = NULL;
+
+ buf32 = (u32 *)buf;
+
+ printk(KERN_INFO "+++ %s\n", __func__);
+
+
+ crc32_temp = true;
+#ifdef CONFIG_COMPANION_USE
+ crc32_c1_check = true;
+#endif
+
+ /* Header data */
+ check_base = 0;
+ checksum = 0;
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ finfo = &sysfs_finfo_front;
+ checksum_base = ((check_base & 0xffffff00) + 0xfc) / 4;
+ } else
+#endif
+ {
+ finfo = &sysfs_finfo;
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ checksum_base = ((check_base & 0xffffff00) + 0xfc) / 4;
+#else
+ checksum_base = ((check_base & 0xfffff000) + 0xffc) / 4;
+#endif
+ }
+
+ checksum = getCRC((u16 *)&buf32[check_base], HEADER_CRC32_LEN, NULL, NULL);
+ if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) {
+ err("Camera: CRC32 error at the header (0x%08X != 0x%08X)",
+ checksum, buf32[checksum_base]);
+ crc32_temp = false;
+ crc32_header_temp = false;
+ } else if (checksum_base > 0x80000 || checksum_base < 0) {
+ err("Camera: Header checksum address has error(0x%08X)", checksum_base * 4);
+ } else {
+ crc32_header_temp = true;
+ }
+
+ /* OEM */
+ check_base = finfo->oem_start_addr / 4;
+ checksum = 0;
+ check_length = (finfo->oem_end_addr - finfo->oem_start_addr + 1) / 2;
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ checksum_base = ((finfo->oem_end_addr & 0xffffff00) + 0xfc) / 4;
+ } else
+#endif
+ {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ checksum_base = ((finfo->oem_end_addr & 0xffffff00) + 0xfc) / 4;
+#else
+ checksum_base = ((finfo->oem_end_addr & 0xfffff000) + 0xffc) / 4;
+#endif
+ }
+
+ checksum = getCRC((u16 *)&buf32[check_base],
+ check_length, NULL, NULL);
+ if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) {
+ err("Camera: CRC32 error at the OEM (0x%08X != 0x%08X)",
+ checksum, buf32[checksum_base]);
+ crc32_temp = false;
+ } else if (checksum_base > 0x80000 || checksum_base < 0) {
+ err("Camera: OEM checksum address has error(0x%08X)", checksum_base * 4);
+ }
+
+ /* AWB */
+ check_base = finfo->awb_start_addr / 4;
+ checksum = 0;
+ check_length = (finfo->awb_end_addr - finfo->awb_start_addr + 1) / 2;
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ checksum_base = ((finfo->awb_end_addr & 0xffffff00) + 0xfc) / 4;
+ } else
+#endif
+ {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ checksum_base = ((finfo->awb_end_addr & 0xffffff00) + 0xfc) / 4;
+#else
+ checksum_base = ((finfo->awb_end_addr & 0xfffff000) + 0xffc) / 4;
+#endif
+ }
+
+ checksum = getCRC((u16 *)&buf32[check_base],
+ check_length, NULL, NULL);
+ if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) {
+ err("Camera: CRC32 error at the AWB (0x%08X != 0x%08X)",
+ checksum, buf32[checksum_base]);
+ crc32_temp = false;
+ } else if (checksum_base > 0x80000 || checksum_base < 0) {
+ err("Camera: AWB checksum address has error(0x%08X)", checksum_base * 4);
+ }
+
+ /* Shading */
+ check_base = finfo->shading_start_addr / 4;
+ checksum = 0;
+ check_length = (finfo->shading_end_addr - finfo->shading_start_addr + 1) / 2;
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ checksum_base = 0x1ffc / 4;
+ } else
+#endif
+ {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ checksum_base = 0x1ffc / 4;
+#else
+ checksum_base = ((finfo->shading_end_addr & 0xfffff000) + 0xffc) / 4;
+#endif
+ }
+
+ checksum = getCRC((u16 *)&buf32[check_base],
+ check_length, NULL, NULL);
+ if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) {
+ err("Camera: CRC32 error at the Shading (0x%08X != 0x%08X)",
+ checksum, buf32[checksum_base]);
+ crc32_temp = false;
+ } else if (checksum_base > 0x80000 || checksum_base < 0) {
+ err("Camera: Shading checksum address has error(0x%08X)", checksum_base * 4);
+ }
+
+#ifdef CONFIG_COMPANION_USE
+ /* pdaf cal */
+ check_base = finfo->pdaf_cal_start_addr / 4;
+ checksum = 0;
+ check_length = (finfo->pdaf_cal_end_addr - finfo->pdaf_cal_start_addr + 1) / 2;
+ checksum_base = ((0x8FFF & 0xfffff000) + 0xffc) / 4;
+
+ checksum = getCRC((u16 *)&buf32[check_base],
+ check_length, NULL, NULL);
+ if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) {
+ err("Camera: CRC32 error at the pdaf cal (0x%08X != 0x%08X)",
+ checksum, buf32[checksum_base]);
+ crc32_temp = false;
+ } else if (checksum_base > 0x80000 || checksum_base < 0) {
+ err("Camera: pdaf cal checksum address has error(0x%08X)", checksum_base * 4);
+ }
+
+ /* concord cal */
+ check_base = finfo->concord_cal_start_addr / 4;
+ checksum = 0;
+ check_length = (finfo->concord_cal_end_addr - finfo->concord_cal_start_addr + 1) / 2;
+ checksum_base = ((finfo->concord_cal_end_addr & 0xfffff000) + 0xffc) / 4;
+
+ checksum = getCRC((u16 *)&buf32[check_base],
+ check_length, NULL, NULL);
+ if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) {
+ err("Camera: CRC32 error at the concord cal (0x%08X != 0x%08X)",
+ checksum, buf32[checksum_base]);
+ crc32_c1_check = false;
+ } else if (checksum_base > 0x80000 || checksum_base < 0) {
+ err("Camera: concord cal checksum address has error(0x%08X)", checksum_base * 4);
+ }
+#endif
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ crc32_check_front = crc32_temp;
+ crc32_header_check_front = crc32_header_temp;
+ return crc32_check_front;
+ } else
+#endif
+ {
+ crc32_check = crc32_temp;
+ crc32_header_check = crc32_header_temp;
+#ifdef CONFIG_COMPANION_USE
+ return crc32_check && crc32_c1_check;
+#else
+ return crc32_check;
+#endif
+ }
+}
+
+bool fimc_is_sec_check_fw_crc32(char *buf)
+{
+ u32 *buf32 = NULL;
+ u32 checksum;
+
+ buf32 = (u32 *)buf;
+
+ pr_info("Camera: Start checking CRC32 FW\n\n");
+
+ crc32_fw_check = true;
+
+ checksum = 0;
+
+ checksum = getCRC((u16 *)&buf32[0],
+ (sysfs_finfo.setfile_end_addr - sysfs_finfo.bin_start_addr + 1)/2, NULL, NULL);
+ if (checksum != buf32[(0x3FFFFC - 0x80000)/4]) {
+ err("Camera: CRC32 error at the binary section (0x%08X != 0x%08X)",
+ checksum, buf32[(0x3FFFFC - 0x80000)/4]);
+ crc32_fw_check = false;
+ }
+
+ pr_info("Camera: End checking CRC32 FW\n\n");
+
+ return crc32_fw_check;
+}
+
+#ifdef CONFIG_COMPANION_USE
+bool fimc_is_sec_check_companion_fw_crc32(char *buf)
+{
+ u32 *buf32 = NULL;
+ u32 checksum;
+
+ buf32 = (u32 *)buf;
+
+ pr_info("Camera: Start checking CRC32 Companion FW\n\n");
+
+ crc32_c1_fw_check = true;
+
+ checksum = 0;
+
+ checksum = getCRC((u16 *)&buf32[0], (sysfs_finfo.concord_mode_setfile_end_addr - sysfs_finfo.concord_bin_start_addr + 1)/2, NULL, NULL);
+ if (checksum != buf32[(0x6AFFC - 0x2B000)/4]) {
+ err("Camera: CRC32 error at the binary section (0x%08X != 0x%08X)",
+ checksum, buf32[(0x6AFFC - 0x2B000)/4]);
+ crc32_c1_fw_check = false;
+ }
+
+ pr_info("Camera: End checking CRC32 Companion FW\n\n");
+
+ return crc32_c1_fw_check;
+}
+#endif
+
+ssize_t write_data_to_file(char *name, char *buf, size_t count, loff_t *pos)
+{
+ struct file *fp;
+ mm_segment_t old_fs;
+ ssize_t tx;
+ int fd, old_mask;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ old_mask = sys_umask(0);
+
+ fd = sys_open(name, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0664);
+ if (fd < 0) {
+ err("open file error!!\n");
+ sys_umask(old_mask);
+ set_fs(old_fs);
+ return -EINVAL;
+ }
+
+ fp = fget(fd);
+ if (fp) {
+ tx = vfs_write(fp, buf, count, pos);
+ vfs_fsync(fp, 0);
+ fput(fp);
+ }
+
+ sys_close(fd);
+ sys_umask(old_mask);
+ set_fs(old_fs);
+
+ return count;
+}
+
+ssize_t read_data_from_file(char *name, char *buf, size_t count, loff_t *pos)
+{
+ struct file *fp;
+ mm_segment_t old_fs;
+ ssize_t tx;
+ int fd;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ fd = sys_open(name, O_RDONLY, 0664);
+ if (fd < 0) {
+ if (-ENOENT == fd)
+ pr_info("%s: file(%s) not exist!\n", __func__, name);
+ else
+ pr_info("%s: error %d, failed to open %s\n", __func__, fd, name);
+
+ set_fs(old_fs);
+ return -EINVAL;
+ }
+ fp = fget(fd);
+ if (fp) {
+ tx = vfs_read(fp, buf, count, pos);
+ fput(fp);
+ }
+ sys_close(fd);
+ set_fs(old_fs);
+
+ return count;
+}
+
+void fimc_is_sec_make_crc32_table(u32 *table, u32 id)
+{
+ u32 i, j, k;
+
+ for (i = 0; i < 256; ++i) {
+ k = i;
+ for (j = 0; j < 8; ++j) {
+ if (k & 1)
+ k = (k >> 1) ^ id;
+ else
+ k >>= 1;
+ }
+ table[i] = k;
+ }
+}
+
+#if 0 /* unused */
+static void fimc_is_read_sensor_version(void)
+{
+ int ret;
+ char buf[0x50];
+
+ memset(buf, 0x0, 0x50);
+
+ printk(KERN_INFO "+++ %s\n", __func__);
+
+ ret = fimc_is_spi_read(buf, 0x0, 0x50);
+
+ printk(KERN_INFO "--- %s\n", __func__);
+
+ if (ret) {
+ err("fimc_is_spi_read - can't read sensor version\n");
+ }
+
+ err("Manufacturer ID(0x40): 0x%02x\n", buf[0x40]);
+ err("Pixel Number(0x41): 0x%02x\n", buf[0x41]);
+}
+
+static void fimc_is_read_sensor_version2(void)
+{
+ char *buf;
+ char *cal_data;
+ u32 cur;
+ u32 count = SETFILE_SIZE/READ_SIZE;
+ u32 extra = SETFILE_SIZE%READ_SIZE;
+
+ printk(KERN_ERR "%s\n\n\n\n", __func__);
+
+
+ buf = (char *)kmalloc(READ_SIZE, GFP_KERNEL);
+ cal_data = (char *)kmalloc(SETFILE_SIZE, GFP_KERNEL);
+
+ memset(buf, 0x0, READ_SIZE);
+ memset(cal_data, 0x0, SETFILE_SIZE);
+
+
+ for (cur = 0; cur < SETFILE_SIZE; cur += READ_SIZE) {
+ fimc_is_spi_read(buf, cur, READ_SIZE);
+ memcpy(cal_data+cur, buf, READ_SIZE);
+ memset(buf, 0x0, READ_SIZE);
+ }
+
+ if (extra != 0) {
+ fimc_is_spi_read(buf, cur, extra);
+ memcpy(cal_data+cur, buf, extra);
+ memset(buf, 0x0, extra);
+ }
+
+ pr_info("Manufacturer ID(0x40): 0x%02x\n", cal_data[0x40]);
+ pr_info("Pixel Number(0x41): 0x%02x\n", cal_data[0x41]);
+
+
+ pr_info("Manufacturer ID(0x4FE7): 0x%02x\n", cal_data[0x4FE7]);
+ pr_info("Pixel Number(0x4FE8): 0x%02x\n", cal_data[0x4FE8]);
+ pr_info("Manufacturer ID(0x4FE9): 0x%02x\n", cal_data[0x4FE9]);
+ pr_info("Pixel Number(0x4FEA): 0x%02x\n", cal_data[0x4FEA]);
+
+ kfree(buf);
+ kfree(cal_data);
+
+}
+
+static int fimc_is_get_cal_data(void)
+{
+ int err = 0;
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long ret = 0;
+ u8 mem0 = 0, mem1 = 0;
+ u32 CRC = 0;
+ u32 DataCRC = 0;
+ u32 IntOriginalCRC = 0;
+ u32 crc_index = 0;
+ int retryCnt = 2;
+ u32 header_crc32 = 0x1000;
+ u32 oem_crc32 = 0x2000;
+ u32 awb_crc32 = 0x3000;
+ u32 shading_crc32 = 0x6000;
+ u32 shading_header = 0x22C0;
+
+ char *cal_data;
+
+ crc32_check = true;
+ printk(KERN_INFO "%s\n\n\n\n", __func__);
+ printk(KERN_INFO "+++ %s\n", __func__);
+
+ fimc_is_spi_read(cal_map_version, 0x60, 0x4);
+ printk(KERN_INFO "cal_map_version = %.4s\n", cal_map_version);
+
+ if (cal_map_version[3] == '5') {
+ shading_crc32 = 0x6000;
+ shading_header = 0x22C0;
+ } else if (cal_map_version[3] == '6') {
+ shading_crc32 = 0x4000;
+ shading_header = 0x920;
+ } else {
+ shading_crc32 = 0x5000;
+ shading_header = 0x22C0;
+ }
+
+ /* Make CRC Table */
+ fimc_is_sec_make_crc32_table((u32 *)&crc_table, 0xEDB88320);
+
+
+ retry:
+ cal_data = (char *)kmalloc(SETFILE_SIZE, GFP_KERNEL);
+
+ memset(cal_data, 0x0, SETFILE_SIZE);
+
+ mem0 = 0, mem1 = 0;
+ CRC = 0;
+ DataCRC = 0;
+ IntOriginalCRC = 0;
+ crc_index = 0;
+
+ fimc_is_spi_read(cal_data, 0, SETFILE_SIZE);
+
+ CRC = ~CRC;
+ for (crc_index = 0; crc_index < (0x80)/2; crc_index++) {
+ /*low byte*/
+ mem0 = (unsigned char)(cal_data[crc_index*2] & 0x00ff);
+ /*high byte*/
+ mem1 = (unsigned char)((cal_data[crc_index*2+1]) & 0x00ff);
+ CRC = crc_table[(CRC ^ (mem0)) & 0xFF] ^ (CRC >> 8);
+ CRC = crc_table[(CRC ^ (mem1)) & 0xFF] ^ (CRC >> 8);
+ }
+ CRC = ~CRC;
+
+
+ DataCRC = (CRC&0x000000ff)<<24;
+ DataCRC += (CRC&0x0000ff00)<<8;
+ DataCRC += (CRC&0x00ff0000)>>8;
+ DataCRC += (CRC&0xff000000)>>24;
+ printk(KERN_INFO "made HEADER CSC value by S/W = 0x%x\n", DataCRC);
+
+ IntOriginalCRC = (cal_data[header_crc32-4]&0x00ff)<<24;
+ IntOriginalCRC += (cal_data[header_crc32-3]&0x00ff)<<16;
+ IntOriginalCRC += (cal_data[header_crc32-2]&0x00ff)<<8;
+ IntOriginalCRC += (cal_data[header_crc32-1]&0x00ff);
+ printk(KERN_INFO "Original HEADER CRC Int = 0x%x\n", IntOriginalCRC);
+
+ if (IntOriginalCRC != DataCRC)
+ crc32_check = false;
+
+ CRC = 0;
+ CRC = ~CRC;
+ for (crc_index = 0; crc_index < (0xC0)/2; crc_index++) {
+ /*low byte*/
+ mem0 = (unsigned char)(cal_data[0x1000 + crc_index*2] & 0x00ff);
+ /*high byte*/
+ mem1 = (unsigned char)((cal_data[0x1000 + crc_index*2+1]) & 0x00ff);
+ CRC = crc_table[(CRC ^ (mem0)) & 0xFF] ^ (CRC >> 8);
+ CRC = crc_table[(CRC ^ (mem1)) & 0xFF] ^ (CRC >> 8);
+ }
+ CRC = ~CRC;
+
+
+ DataCRC = (CRC&0x000000ff)<<24;
+ DataCRC += (CRC&0x0000ff00)<<8;
+ DataCRC += (CRC&0x00ff0000)>>8;
+ DataCRC += (CRC&0xff000000)>>24;
+ printk(KERN_INFO "made OEM CSC value by S/W = 0x%x\n", DataCRC);
+
+ IntOriginalCRC = (cal_data[oem_crc32-4]&0x00ff)<<24;
+ IntOriginalCRC += (cal_data[oem_crc32-3]&0x00ff)<<16;
+ IntOriginalCRC += (cal_data[oem_crc32-2]&0x00ff)<<8;
+ IntOriginalCRC += (cal_data[oem_crc32-1]&0x00ff);
+ printk(KERN_INFO "Original OEM CRC Int = 0x%x\n", IntOriginalCRC);
+
+ if (IntOriginalCRC != DataCRC)
+ crc32_check = false;
+
+
+ CRC = 0;
+ CRC = ~CRC;
+ for (crc_index = 0; crc_index < (0x20)/2; crc_index++) {
+ /*low byte*/
+ mem0 = (unsigned char)(cal_data[0x2000 + crc_index*2] & 0x00ff);
+ /*high byte*/
+ mem1 = (unsigned char)((cal_data[0x2000 + crc_index*2+1]) & 0x00ff);
+ CRC = crc_table[(CRC ^ (mem0)) & 0xFF] ^ (CRC >> 8);
+ CRC = crc_table[(CRC ^ (mem1)) & 0xFF] ^ (CRC >> 8);
+ }
+ CRC = ~CRC;
+
+
+ DataCRC = (CRC&0x000000ff)<<24;
+ DataCRC += (CRC&0x0000ff00)<<8;
+ DataCRC += (CRC&0x00ff0000)>>8;
+ DataCRC += (CRC&0xff000000)>>24;
+ printk(KERN_INFO "made AWB CSC value by S/W = 0x%x\n", DataCRC);
+
+ IntOriginalCRC = (cal_data[awb_crc32-4]&0x00ff)<<24;
+ IntOriginalCRC += (cal_data[awb_crc32-3]&0x00ff)<<16;
+ IntOriginalCRC += (cal_data[awb_crc32-2]&0x00ff)<<8;
+ IntOriginalCRC += (cal_data[awb_crc32-1]&0x00ff);
+ printk(KERN_INFO "Original AWB CRC Int = 0x%x\n", IntOriginalCRC);
+
+ if (IntOriginalCRC != DataCRC)
+ crc32_check = false;
+
+
+ CRC = 0;
+ CRC = ~CRC;
+ for (crc_index = 0; crc_index < (shading_header)/2; crc_index++) {
+
+ /*low byte*/
+ mem0 = (unsigned char)(cal_data[0x3000 + crc_index*2] & 0x00ff);
+ /*high byte*/
+ mem1 = (unsigned char)((cal_data[0x3000 + crc_index*2+1]) & 0x00ff);
+ CRC = crc_table[(CRC ^ (mem0)) & 0xFF] ^ (CRC >> 8);
+ CRC = crc_table[(CRC ^ (mem1)) & 0xFF] ^ (CRC >> 8);
+ }
+ CRC = ~CRC;
+
+
+ DataCRC = (CRC&0x000000ff)<<24;
+ DataCRC += (CRC&0x0000ff00)<<8;
+ DataCRC += (CRC&0x00ff0000)>>8;
+ DataCRC += (CRC&0xff000000)>>24;
+ printk(KERN_INFO "made SHADING CSC value by S/W = 0x%x\n", DataCRC);
+
+ IntOriginalCRC = (cal_data[shading_crc32-4]&0x00ff)<<24;
+ IntOriginalCRC += (cal_data[shading_crc32-3]&0x00ff)<<16;
+ IntOriginalCRC += (cal_data[shading_crc32-2]&0x00ff)<<8;
+ IntOriginalCRC += (cal_data[shading_crc32-1]&0x00ff);
+ printk(KERN_INFO "Original SHADING CRC Int = 0x%x\n", IntOriginalCRC);
+
+ if (IntOriginalCRC != DataCRC)
+ crc32_check = false;
+
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ if (crc32_check == true) {
+ printk(KERN_INFO "make cal_data.bin~~~~ \n");
+ fp = filp_open(FIMC_IS_CAL_SDCARD, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (IS_ERR(fp) || fp == NULL) {
+ printk(KERN_INFO "failed to open %s, err %ld\n",
+ FIMC_IS_CAL_SDCARD, PTR_ERR(fp));
+ err = -EINVAL;
+ goto out;
+ }
+
+ ret = vfs_write(fp, (char __user *)cal_data,
+ SETFILE_SIZE, &fp->f_pos);
+
+ } else {
+ if (retryCnt > 0) {
+ set_fs(old_fs);
+ retryCnt--;
+ goto retry;
+ }
+ }
+
+/*
+ {
+ fp = filp_open(FIMC_IS_CAL_SDCARD, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (IS_ERR(fp) || fp == NULL) {
+ printk(KERN_INFO "failed to open %s, err %ld\n",
+ FIMC_IS_CAL_SDCARD, PTR_ERR(fp));
+ err = -EINVAL;
+ goto out;
+ }
+
+ ret = vfs_write(fp, (char __user *)cal_data,
+ SETFILE_SIZE, &fp->f_pos);
+
+ }
+*/
+
+ if (fp != NULL)
+ filp_close(fp, current->files);
+
+ out:
+ set_fs(old_fs);
+ kfree(cal_data);
+ return err;
+
+}
+
+#endif
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+int fimc_is_i2c_read(struct i2c_client *client, void *buf, u32 addr, size_t size)
+{
+ const u32 addr_size = 2, max_retry = 5;
+ u8 addr_buf[addr_size];
+ int retries = max_retry;
+ int ret = 0;
+
+ if (!client) {
+ pr_info("%s: client is null\n", __func__);
+ return -ENODEV;
+ }
+
+ /* pr_info("%s %s: fimc_is_i2c_read\n",
+ dev_driver_string(&client->dev), dev_name(&client->dev));*/
+
+ /* Send addr */
+ addr_buf[0] = ((u16)addr) >> 8;
+ addr_buf[1] = (u8)addr;
+
+ for (retries = max_retry; retries > 0; retries--) {
+ ret = i2c_master_send(client, addr_buf, addr_size);
+ if (likely(addr_size == ret))
+ break;
+
+ pr_info("%s: i2c_master_send failed(%d), try %d\n", __func__, ret, retries);
+ usleep_range(1000, 1000);
+ }
+
+ if (unlikely(ret <= 0)) {
+ pr_err("%s: error %d, fail to write 0x%04X\n", __func__, ret, addr);
+ return ret ? ret : -ETIMEDOUT;
+ }
+
+ /* Receive data */
+ for (retries = max_retry; retries > 0; retries--) {
+ ret = i2c_master_recv(client, buf, size);
+ if (likely(ret == size))
+ break;
+
+ pr_info("%s: i2c_master_recv failed(%d), try %d\n", __func__, ret, retries);
+ usleep_range(1000, 1000);
+ }
+
+ if (unlikely(ret <= 0)) {
+ pr_err("%s: error %d, fail to read 0x%04X\n", __func__, ret, addr);
+ return ret ? ret : -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int fimc_is_i2c_write(struct i2c_client *client, void *buf, u32 addr, size_t size)
+{
+ pr_info("%s: do nothing\n", __func__);
+ return 0;
+}
+
+int fimc_is_sec_read_eeprom_header(struct device *dev)
+{
+ int ret = 0;
+ struct fimc_is_core *core = dev_get_drvdata(dev);
+ u8 header_version[12] = {0, };
+ struct i2c_client *client;
+ client = core->eeprom_client0;
+
+ ret = fimc_is_i2c_read(client, header_version, 0x20, 0x0B);
+ if (unlikely(ret)) {
+ err("failed to fimc_is_i2c_read for header version (%d)\n", ret);
+ ret = -EINVAL;
+ }
+
+ memcpy(sysfs_finfo.header_ver, header_version, 11);
+ sysfs_finfo.header_ver[11] = '\0';
+
+ return ret;
+}
+
+int fimc_is_sec_readcal_eeprom(struct device *dev, int id)
+{
+ int ret = 0;
+ char *buf = NULL;
+ int retry = FIMC_IS_CAL_RETRY_CNT;
+ struct fimc_is_core *core = dev_get_drvdata(dev);
+ struct fimc_is_from_info *finfo = NULL;
+ int cal_size = 0;
+ struct i2c_client *client = NULL;
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ finfo = &sysfs_finfo_front;
+ fimc_is_sec_get_front_cal_buf(&buf);
+ cal_size = FIMC_IS_MAX_CAL_SIZE_FRONT;
+ client = core->eeprom_client1;
+ } else
+#endif
+ {
+ finfo = &sysfs_finfo;
+ fimc_is_sec_get_cal_buf(&buf);
+ cal_size = FIMC_IS_MAX_CAL_SIZE;
+ client = core->eeprom_client0;
+ }
+
+ ret = fimc_is_i2c_read(client, cal_map_version, 0x30, 0x4);
+ if (unlikely(ret)) {
+ err("failed to fimc_is_i2c_read (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+ printk(KERN_INFO "Camera: Cal map_version = %c%c%c%c\n", cal_map_version[0],
+ cal_map_version[1], cal_map_version[2], cal_map_version[3]);
+
+crc_retry:
+
+ /* read cal data */
+ pr_info("Camera: I2C read cal data\n\n");
+ fimc_is_i2c_read(client, buf, 0x0, cal_size);
+
+ finfo->oem_start_addr = *((u32 *)&buf[0x0]);
+ finfo->oem_end_addr = *((u32 *)&buf[0x04]);
+ pr_info("OEM start = 0x%08x, end = 0x%08x\n",
+ (finfo->oem_start_addr), (finfo->oem_end_addr));
+ finfo->awb_start_addr = *((u32 *)&buf[0x08]);
+ finfo->awb_end_addr = *((u32 *)&buf[0x0C]);
+ pr_info("AWB start = 0x%08x, end = 0x%08x\n",
+ (finfo->awb_start_addr), (finfo->awb_end_addr));
+ finfo->shading_start_addr = *((u32 *)&buf[0x10]);
+ finfo->shading_end_addr = *((u32 *)&buf[0x14]);
+ if (finfo->shading_end_addr > 0x1fff) {
+ err("Shading end_addr has error!! 0x%08x", finfo->shading_end_addr);
+ finfo->setfile_end_addr = 0x1fff;
+ }
+ pr_info("Shading start = 0x%08x, end = 0x%08x\n",
+ (finfo->shading_start_addr), (finfo->shading_end_addr));
+
+ /* HEARDER Data : Module/Manufacturer Information */
+ memcpy(finfo->header_ver, &buf[0x20], 11);
+ finfo->header_ver[11] = '\0';
+ /* HEARDER Data : Cal Map Version */
+ memcpy(finfo->cal_map_ver, &buf[0x30], 4);
+
+ memcpy(finfo->project_name, &buf[0x38], 8);
+ finfo->project_name[8] = '\0';
+
+ /* OEM Data : Module/Manufacturer Information */
+ memcpy(finfo->oem_ver, &buf[0x150], 11);
+ finfo->oem_ver[11] = '\0';
+
+ /* AWB Data : Module/Manufacturer Information */
+ memcpy(finfo->awb_ver, &buf[0x220], 11);
+ finfo->awb_ver[11] = '\0';
+
+ /* SHADING Data : Module/Manufacturer Information */
+ memcpy(finfo->shading_ver, &buf[0x1CE0], 11);
+ finfo->shading_ver[11] = '\0';
+
+ /* debug info dump */
+#if defined(EEPROM_DEBUG)
+ pr_info("++++ EEPROM data info\n");
+ pr_info("1. Header info\n");
+ pr_info("Module info : %s\n", finfo->header_ver);
+ pr_info(" ID : %c\n", finfo->header_ver[0]);
+ pr_info(" Pixel num : %c%c\n", finfo->header_ver[1],
+ finfo->header_ver[2]);
+ pr_info(" ISP ID : %c\n", finfo->header_ver[3]);
+ pr_info(" Sensor Maker : %c\n", finfo->header_ver[4]);
+ pr_info(" Module ver : %c\n", finfo->header_ver[6]);
+ pr_info(" Year : %c\n", finfo->header_ver[7]);
+ pr_info(" Month : %c\n", finfo->header_ver[8]);
+ pr_info(" Release num : %c%c\n", finfo->header_ver[9],
+ finfo->header_ver[10]);
+ pr_info("project_name : %s\n", finfo->project_name);
+ pr_info("Cal data map ver : %s\n", finfo->cal_map_ver);
+ pr_info("2. OEM info\n");
+ pr_info("Module info : %s\n", finfo->oem_ver);
+ pr_info("3. AWB info\n");
+ pr_info("Module info : %s\n", finfo->awb_ver);
+ pr_info("4. Shading info\n");
+ pr_info("Module info : %s\n", finfo->shading_ver);
+ pr_info("---- EEPROM data info\n");
+#endif
+
+ /* CRC check */
+ if (id == SENSOR_POSITION_FRONT) {
+ ret = fimc_is_sec_check_cal_crc32(buf, SENSOR_POSITION_FRONT);
+ } else {
+ ret = fimc_is_sec_check_cal_crc32(buf, SENSOR_POSITION_REAR);
+ }
+ if (!ret && (retry > 0)) {
+ retry--;
+ goto crc_retry;
+ }
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ if (finfo->header_ver[3] == 'L') {
+ crc32_check_factory_front = crc32_check_front;
+ } else {
+ crc32_check_factory_front = false;
+ }
+ } else
+#endif
+ {
+ if (finfo->header_ver[3] == 'L') {
+ crc32_check_factory = crc32_check;
+ } else {
+ crc32_check_factory = false;
+ }
+
+ if (finfo->project_name[6] == 'C' && finfo->header_ver[0] == 'E' && finfo->header_ver[1] == '0' &&
+ finfo->header_ver[2] == '8') {
+ pr_info("This camera module use IMX134+EEPROM - project_name: %c-%c\n"
+ , finfo->project_name[6], finfo->project_name[7]);
+
+ if (!core->use_module_check) {
+ is_right_prj_name = true;
+ is_latest_cam_module = true;
+ is_final_cam_module = true;
+ }
+ }
+ }
+
+exit:
+ return ret;
+}
+#endif
+
+#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+extern int fimc_is_spi_reset_by_core(struct spi_device *spi, void *buf, u32 rx_addr, size_t size);
+extern int fimc_is_spi_read_by_core(struct spi_device *spi, void *buf, u32 rx_addr, size_t size);
+extern int fimc_is_spi_read_module_id(struct spi_device *spi, void *buf, u16 rx_addr, size_t size);
+
+int fimc_is_sec_read_from_header(struct device *dev)
+{
+ int ret = 0;
+ struct fimc_is_core *core = dev_get_drvdata(dev);
+ u8 header_version[12] = {0, };
+
+ ret = fimc_is_spi_read_by_core(core->spi0, header_version, 0x40, 0x0B);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to fimc_is_spi_read for header version (%d)\n", ret);
+ ret = -EINVAL;
+ }
+
+ memcpy(sysfs_finfo.header_ver, header_version, 11);
+ sysfs_finfo.header_ver[11] = '\0';
+
+ return ret;
+}
+
+int fimc_is_sec_readcal(struct fimc_is_core *core)
+{
+ int ret = 0;
+ int retry = FIMC_IS_CAL_RETRY_CNT;
+ char spi_buf[0x50] = {0, };
+ struct file *key_fp = NULL;
+ struct file *dump_fp = NULL;
+ mm_segment_t old_fs;
+ loff_t pos = 0;
+ u16 id;
+
+ /* reset spi */
+ if (!core->spi0) {
+ pr_err("spi0 device is not available");
+ goto exit;
+ }
+
+ ret = fimc_is_spi_reset_by_core(core->spi0, spi_buf, 0x0, FIMC_IS_MAX_CAL_SIZE);
+ if (ret < 0) {
+ err("failed to fimc_is_spi_read (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_spi_read_module_id(core->spi0, &id, 0x0, 0x2);
+ pr_info("Camera: FROM Module ID = 0x%04x\n", id);
+
+ ret = fimc_is_spi_read_by_core(core->spi0, cal_map_version, 0x60, 0x4);
+ if (ret < 0) {
+ printk(KERN_ERR "failed to fimc_is_spi_read (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+ pr_info("Camera: Cal map_version = %c%c%c%c\n", cal_map_version[0],
+ cal_map_version[1], cal_map_version[2], cal_map_version[3]);
+crc_retry:
+ /* read cal data */
+ pr_info("Camera: SPI read cal data\n\n");
+ ret = fimc_is_spi_read_by_core(core->spi0, cal_buf, 0x0, FIMC_IS_MAX_CAL_SIZE);
+ if (ret < 0) {
+ err("failed to fimc_is_spi_read (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ sysfs_finfo.bin_start_addr = *((u32 *)&cal_buf[0]);
+ sysfs_finfo.bin_end_addr = *((u32 *)&cal_buf[4]);
+ pr_info("Binary start = 0x%08x, end = 0x%08x\n",
+ (sysfs_finfo.bin_start_addr), (sysfs_finfo.bin_end_addr));
+ sysfs_finfo.oem_start_addr = *((u32 *)&cal_buf[8]);
+ sysfs_finfo.oem_end_addr = 0x113F;//*((u32 *)&cal_buf[12]);
+ pr_info("OEM start = 0x%08x, end = 0x%08x\n",
+ (sysfs_finfo.oem_start_addr), (sysfs_finfo.oem_end_addr));
+ sysfs_finfo.awb_start_addr = *((u32 *)&cal_buf[16]);
+ sysfs_finfo.awb_end_addr = *((u32 *)&cal_buf[20]);
+ pr_info("AWB start = 0x%08x, end = 0x%08x\n",
+ (sysfs_finfo.awb_start_addr), (sysfs_finfo.awb_end_addr));
+ sysfs_finfo.shading_start_addr = *((u32 *)&cal_buf[24]);
+ sysfs_finfo.shading_end_addr = *((u32 *)&cal_buf[28]);
+ pr_info("Shading start = 0x%08x, end = 0x%08x\n",
+ (sysfs_finfo.shading_start_addr), (sysfs_finfo.shading_end_addr));
+ sysfs_finfo.setfile_start_addr = *((u32 *)&cal_buf[32]);
+ sysfs_finfo.setfile_end_addr = *((u32 *)&cal_buf[36]);
+ /*if (sysfs_finfo.setfile_start_addr == 0xffffffff) {
+ sysfs_finfo.setfile_start_addr = *((u32 *)&cal_buf[40]);
+ sysfs_finfo.setfile_end_addr = *((u32 *)&cal_buf[44]);
+ }*/
+#ifdef CONFIG_COMPANION_USE
+ sysfs_finfo.concord_cal_start_addr = *((u32 *)&cal_buf[40]);
+ sysfs_finfo.concord_cal_end_addr = 0xF23F;//*((u32 *)&cal_buf[44]);
+ pr_info("concord cal start = 0x%08x, end = 0x%08x\n",
+ sysfs_finfo.concord_cal_start_addr, sysfs_finfo.concord_cal_end_addr);
+ sysfs_finfo.concord_bin_start_addr = *((u32 *)&cal_buf[48]);
+ sysfs_finfo.concord_bin_end_addr = *((u32 *)&cal_buf[52]);
+ pr_info("concord bin start = 0x%08x, end = 0x%08x\n",
+ sysfs_finfo.concord_bin_start_addr, sysfs_finfo.concord_bin_end_addr);
+ sysfs_finfo.concord_master_setfile_start_addr = *((u32 *)&cal_buf[168]);
+ sysfs_finfo.concord_master_setfile_end_addr = sysfs_finfo.concord_master_setfile_start_addr + 16064;
+ sysfs_finfo.concord_mode_setfile_start_addr = sysfs_finfo.concord_master_setfile_end_addr + 1;
+ sysfs_finfo.concord_mode_setfile_end_addr = *((u32 *)&cal_buf[172]);
+ sysfs_finfo.pdaf_cal_start_addr = 0x5000;
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V005)
+ sysfs_finfo.pdaf_cal_end_addr = 0x540F;
+ else
+ sysfs_finfo.pdaf_cal_end_addr = 0x521F;
+ pr_info("pdaf start = 0x%08x, end = 0x%08x\n",
+ sysfs_finfo.pdaf_cal_start_addr, sysfs_finfo.pdaf_cal_end_addr);
+
+ sysfs_finfo.lsc_i0_gain_addr = 0x3006;
+ pr_info("Shading lsc_i0 start = 0x%08x\n", sysfs_finfo.lsc_i0_gain_addr);
+ sysfs_finfo.lsc_j0_gain_addr = sysfs_finfo.lsc_i0_gain_addr + 0x2;
+ pr_info("Shading lsc_j0 start = 0x%08x\n", sysfs_finfo.lsc_j0_gain_addr);
+ sysfs_finfo.lsc_a_gain_addr = sysfs_finfo.lsc_j0_gain_addr + 0x2;
+ pr_info("Shading lsc_a start = 0x%08x\n", sysfs_finfo.lsc_a_gain_addr);
+ sysfs_finfo.lsc_k4_gain_addr = sysfs_finfo.lsc_a_gain_addr + 0x4;
+ pr_info("Shading lsc_k4 start = 0x%08x\n", sysfs_finfo.lsc_k4_gain_addr);
+ sysfs_finfo.lsc_scale_gain_addr = sysfs_finfo.lsc_k4_gain_addr + 0x4;
+ pr_info("Shading lsc_scale start = 0x%08x\n", sysfs_finfo.lsc_scale_gain_addr);
+
+ sysfs_finfo.lsc_gain_start_addr = sysfs_finfo.shading_start_addr + 0x14;
+ sysfs_finfo.lsc_gain_end_addr = sysfs_finfo.lsc_gain_start_addr + 6600 -1;
+ pr_info("LSC start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.lsc_gain_start_addr, sysfs_finfo.lsc_gain_end_addr);
+ sysfs_finfo.pdaf_start_addr = sysfs_finfo.concord_cal_start_addr;
+ sysfs_finfo.pdaf_end_addr = sysfs_finfo.pdaf_start_addr + 512 -1;
+ pr_info("pdaf_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.pdaf_start_addr, sysfs_finfo.pdaf_end_addr);
+ /*sysfs_finfo.coefficient_cal_start_addr = sysfs_finfo.pdaf_start_addr + 512 + 16;
+ sysfs_finfo.coefficient_cal_end_addr = sysfs_finfo.coefficient_cal_start_addr + 24576 -1;
+ pr_info("coefficient_cal_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.coefficient_cal_start_addr, sysfs_finfo.coefficient_cal_end_addr);*/
+ sysfs_finfo.coef1_start = sysfs_finfo.pdaf_start_addr + 512 + 16;
+ sysfs_finfo.coef1_end = sysfs_finfo.coef1_start + 4032 -1;
+ pr_info("coefficient1_cal_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.coef1_start, sysfs_finfo.coef1_end);
+ sysfs_finfo.coef2_start = sysfs_finfo.coef1_end + 64 + 1;
+ sysfs_finfo.coef2_end = sysfs_finfo.coef2_start + 4032 -1;
+ pr_info("coefficient2_cal_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.coef2_start, sysfs_finfo.coef2_end);
+ sysfs_finfo.coef3_start = sysfs_finfo.coef2_end + 64 + 1;
+ sysfs_finfo.coef3_end = sysfs_finfo.coef3_start + 4032 -1;
+ pr_info("coefficient3_cal_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.coef3_start, sysfs_finfo.coef3_end);
+ sysfs_finfo.coef4_start = sysfs_finfo.coef3_end + 64 + 1;
+ sysfs_finfo.coef4_end = sysfs_finfo.coef4_start + 4032 -1;
+ pr_info("coefficient4_cal_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.coef4_start, sysfs_finfo.coef4_end);
+ sysfs_finfo.coef5_start = sysfs_finfo.coef4_end + 64 + 1;
+ sysfs_finfo.coef5_end = sysfs_finfo.coef5_start + 4032 -1;
+ pr_info("coefficient5_cal_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.coef5_start, sysfs_finfo.coef5_end);
+ sysfs_finfo.coef6_start = sysfs_finfo.coef5_end + 64 + 1;
+ sysfs_finfo.coef6_end = sysfs_finfo.coef6_start + 4032 -1;
+ pr_info("coefficient6_cal_addr start = 0x%04x, end = 0x%04x\n",
+ sysfs_finfo.coef6_start, sysfs_finfo.coef6_end);
+ sysfs_finfo.wcoefficient1_addr = 0xF210;
+ pr_info("Shading wcoefficient1 start = 0x%04x\n", sysfs_finfo.wcoefficient1_addr);
+ memcpy(sysfs_finfo.concord_header_ver, &cal_buf[80], 11);
+ sysfs_finfo.concord_header_ver[11] = '\0';
+ sysfs_finfo.af_inf_addr = 0x1000;
+ sysfs_finfo.af_macro_addr = 0x1008;
+ sysfs_finfo.lsc_gain_crc_addr = 0x49DC;
+ sysfs_finfo.pdaf_crc_addr= 0x9200;
+ sysfs_finfo.coef1_crc_addr= 0xF21A;
+ sysfs_finfo.coef2_crc_addr = 0xF21E;
+ sysfs_finfo.coef3_crc_addr = 0xF222;
+ sysfs_finfo.coef4_crc_addr = 0xF226;
+ sysfs_finfo.coef5_crc_addr = 0xF22A;
+ sysfs_finfo.coef6_crc_addr = 0xF22E;
+#endif
+
+ if (sysfs_finfo.setfile_end_addr < 0x8000 || sysfs_finfo.setfile_end_addr > 0x3fffff) {
+ err("setfile end_addr has error!! 0x%08x", sysfs_finfo.setfile_end_addr);
+ sysfs_finfo.setfile_end_addr = 0x1fffff;
+ }
+
+ pr_info("Setfile start = 0x%08x, end = 0x%08x\n",
+ (sysfs_finfo.setfile_start_addr), (sysfs_finfo.setfile_end_addr));
+
+ memcpy(sysfs_finfo.header_ver, &cal_buf[64], 11);
+ sysfs_finfo.header_ver[11] = '\0';
+ memcpy(sysfs_finfo.cal_map_ver, &cal_buf[96], 4);
+ memcpy(sysfs_finfo.setfile_ver, &cal_buf[100], 6);
+ sysfs_finfo.setfile_ver[6] = '\0';
+ memcpy(sysfs_finfo.oem_ver, &cal_buf[8160], 11);
+ sysfs_finfo.oem_ver[11] = '\0';
+ memcpy(sysfs_finfo.awb_ver, &cal_buf[12256], 11);
+ sysfs_finfo.awb_ver[11] = '\0';
+ memcpy(sysfs_finfo.shading_ver, &cal_buf[16352], 11);
+ sysfs_finfo.shading_ver[11] = '\0';
+ memcpy(sysfs_finfo.project_name, &cal_buf[110], 8);
+ sysfs_finfo.project_name[8] = '\0';
+
+ fw_core_version = sysfs_finfo.header_ver[0];
+ /* debug info dump */
+//#if defined(FROM_DEBUG)
+#if 1
+ pr_err("++++ FROM data info\n");
+ pr_err("1. Header info\n");
+ pr_err("Module info : %s\n", sysfs_finfo.header_ver);
+#ifdef CONFIG_COMPANION_USE
+ pr_err("Companion version info : %s\n", sysfs_finfo.concord_header_ver);
+#endif
+ pr_err(" ID : %c\n", sysfs_finfo.header_ver[0]);
+ pr_err(" Pixel num : %c%c\n", sysfs_finfo.header_ver[1],
+ sysfs_finfo.header_ver[2]);
+ pr_err(" ISP ID : %c\n", sysfs_finfo.header_ver[3]);
+ pr_err(" Sensor Maker : %c\n", sysfs_finfo.header_ver[5]);
+ pr_err(" Module ver : %c\n", sysfs_finfo.header_ver[6]);
+ pr_err(" Year : %c\n", sysfs_finfo.header_ver[7]);
+ pr_err(" Month : %c\n", sysfs_finfo.header_ver[8]);
+ pr_err(" Release num : %c%c\n", sysfs_finfo.header_ver[9],
+ sysfs_finfo.header_ver[10]);
+ pr_err("Cal data map ver : %s\n", sysfs_finfo.cal_map_ver);
+ pr_err("Setfile ver : %s\n", sysfs_finfo.setfile_ver);
+ pr_err("Project name : %s\n", sysfs_finfo.project_name);
+ pr_err("2. OEM info\n");
+ pr_err("Module info : %s\n", sysfs_finfo.oem_ver);
+ pr_err("3. AWB info\n");
+ pr_err("Module info : %s\n", sysfs_finfo.awb_ver);
+ pr_err("4. Shading info\n");
+ pr_err("Module info : %s\n", sysfs_finfo.shading_ver);
+ pr_err("---- FROM data info\n");
+#endif
+
+ /* CRC check */
+#ifdef CONFIG_COMPANION_USE
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ if (!fimc_is_sec_check_cal_crc32(cal_buf, SENSOR_POSITION_REAR) && (retry > 0)) {
+ retry--;
+ goto crc_retry;
+ }
+ } else {
+ fw_version_crc_check = false;
+ crc32_check = false;
+ crc32_c1_check = false;
+ }
+#else
+ if (!fimc_is_sec_check_cal_crc32(cal_buf, SENSOR_POSITION_REAR) && (retry > 0)) {
+ retry--;
+ goto crc_retry;
+ }
+#endif
+
+ if (sysfs_finfo.header_ver[3] == 'L') {
+ crc32_check_factory = crc32_check;
+#ifdef CONFIG_COMPANION_USE
+ crc32_c1_check_factory = crc32_c1_check;
+#endif
+ } else {
+ crc32_check_factory = false;
+#ifdef CONFIG_COMPANION_USE
+ crc32_c1_check_factory = false;
+#endif
+ }
+
+#ifdef CONFIG_COMPANION_USE
+ if (fimc_is_comp_is_compare_ver(core) >= FROM_VERSION_V004) {
+ if (crc32_check && crc32_c1_check) {
+ /* If FROM LSC value is not valid, loading default lsc data */
+ if (*((u32 *)&cal_buf[sysfs_finfo.lsc_gain_start_addr]) == 0x00000000) {
+ companion_lsc_isvalid = false;
+ } else {
+ companion_lsc_isvalid = true;
+ }
+ if (*((u32 *)&cal_buf[sysfs_finfo.coef1_start]) == 0x00000000) {
+ companion_coef_isvalid = false;
+ } else {
+ companion_coef_isvalid = true;
+ }
+ } else {
+ companion_lsc_isvalid = false;
+ companion_coef_isvalid = false;
+ }
+ } else {
+ companion_lsc_isvalid = true;
+ companion_coef_isvalid = true;
+ }
+#endif
+
+ if (!core->use_module_check) {
+ is_latest_cam_module = true;
+ } else {
+ if (sysfs_finfo.header_ver[10] >= FIMC_IS_LATEST_FROM_VERSION_B) {
+ is_latest_cam_module = true;
+ } else {
+ is_latest_cam_module = false;
+ }
+ }
+
+ if (core->use_module_check) {
+ if (sysfs_finfo.header_ver[10] == FIMC_IS_LATEST_FROM_VERSION_M) {
+ is_final_cam_module = true;
+ } else {
+ is_final_cam_module = false;
+ }
+ } else {
+ is_final_cam_module = true;
+ }
+
+#if defined(CONFIG_SOC_EXYNOS5433)
+ if (sysfs_finfo.project_name[6] != 'T' && sysfs_finfo.header_ver[0] == 'H' && sysfs_finfo.header_ver[1] == '1' &&
+ sysfs_finfo.header_ver[2] == '6') {
+ pr_info("FROM has abnormal project name : %c-%c\n", sysfs_finfo.project_name[6], sysfs_finfo.project_name[7]);
+ is_right_prj_name = false;
+ } else {
+ is_right_prj_name = true;
+ }
+#endif
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ key_fp = filp_open("/data/media/0/1q2w3e4r.key", O_RDONLY, 0);
+ if (IS_ERR(key_fp)) {
+ pr_info("KEY does not exist.\n");
+ key_fp = NULL;
+ goto key_err;
+ } else {
+ dump_fp = filp_open("/data/media/0/dump", O_RDONLY, 0);
+ if (IS_ERR(dump_fp)) {
+ pr_info("dump folder does not exist.\n");
+ dump_fp = NULL;
+ goto key_err;
+ } else {
+ pr_info("dump folder exist, Dump FROM cal data.\n");
+ if (write_data_to_file("/data/media/0/dump/from_cal.bin", cal_buf, FIMC_IS_DUMP_CAL_SIZE, &pos) < 0) {
+ pr_info("Failedl to dump cal data.\n");
+ goto dump_err;
+ }
+ }
+ }
+dump_err:
+ if (dump_fp)
+ filp_close(dump_fp, current->files);
+key_err:
+ if (key_fp)
+ filp_close(key_fp, current->files);
+ set_fs(old_fs);
+exit:
+ return ret;
+}
+
+int fimc_is_sec_readfw(struct fimc_is_core *core)
+{
+ int ret = 0;
+ char *buf = NULL;
+ loff_t pos = 0;
+ char fw_path[100];
+ char setfile_path[100];
+ char setf_name[50];
+ int retry = FIMC_IS_FW_RETRY_CNT;
+ int pixelSize;
+#ifdef USE_ION_ALLOC
+ struct ion_handle *handle = NULL;
+#endif
+
+ pr_info("Camera: FW, Setfile need to be dumped\n");
+#ifdef USE_ION_ALLOC
+ handle = ion_alloc(core->fimc_ion_client, (size_t)FIMC_IS_MAX_FW_SIZE, 0,
+ EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ err("(%s):failed to ioc_alloc\n",__func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ buf = (char *)ion_map_kernel(core->fimc_ion_client, handle);
+ if (IS_ERR_OR_NULL(buf)) {
+ err("(%s)fail to ion_map_kernle\n",__func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+#else
+ buf = vmalloc(FIMC_IS_MAX_FW_SIZE);
+ if (!buf) {
+ err("vmalloc fail");
+ ret = -ENOMEM;
+ goto exit;
+ }
+#endif
+ crc_retry:
+
+ /* read fw data */
+ pr_info("Camera: Start SPI read fw data\n\n");
+ ret = fimc_is_spi_read_by_core(core->spi0, buf, 0x80000, FIMC_IS_MAX_FW_SIZE);
+ if (ret < 0) {
+ err("failed to fimc_is_spi_read (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+ pr_info("Camera: End SPI read fw data\n\n");
+
+ /* CRC check */
+ if (!fimc_is_sec_check_fw_crc32(buf) && (retry > 0)) {
+ retry--;
+ goto crc_retry;
+ } else if (!retry) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ snprintf(fw_path, sizeof(fw_path), "%s%s", FIMC_IS_FW_DUMP_PATH, FIMC_IS_FW);
+ if (write_data_to_file(fw_path, buf,
+ sysfs_finfo.bin_end_addr - sysfs_finfo.bin_start_addr + 1, &pos) < 0) {
+ ret = -EIO;
+ goto exit;
+ }
+
+ pr_info("Camera: FW Data has dumped successfully\n");
+
+ if (sysfs_finfo.header_ver[FW_SENSOR_MAKER] == FW_SENSOR_MAKER_SLSI) {
+ snprintf(setf_name, sizeof(setf_name), "%s", FIMC_IS_2P2_SETF);
+ } else if (sysfs_finfo.header_ver[FW_SENSOR_MAKER] == FW_SENSOR_MAKER_SONY) {
+ pixelSize = fimc_is_sec_get_pixel_size(sysfs_finfo.header_ver);
+ if (pixelSize == 13) {
+ snprintf(setf_name, sizeof(setf_name), "%s", FIMC_IS_IMX135_SETF);
+ } else if (pixelSize == 8) {
+ snprintf(setf_name, sizeof(setf_name), "%s", FIMC_IS_IMX134_SETF);
+ } else {
+ snprintf(setf_name, sizeof(setf_name), "%s", FIMC_IS_IMX135_SETF);
+ }
+ } else {
+ snprintf(setf_name, sizeof(setf_name), "%s", FIMC_IS_2P2_SETF);
+ }
+
+ snprintf(setfile_path, sizeof(setfile_path), "%s%s", FIMC_IS_FW_DUMP_PATH, setf_name);
+ pos = 0;
+
+ if (write_data_to_file(setfile_path,
+ buf+(sysfs_finfo.setfile_start_addr - sysfs_finfo.bin_start_addr),
+ sysfs_finfo.setfile_end_addr - sysfs_finfo.setfile_start_addr + 1, &pos) < 0) {
+ ret = -EIO;
+ goto exit;
+ }
+
+ pr_info("Camera: Setfile has dumped successfully\n");
+ pr_info("Camera: FW, Setfile were dumped successfully\n");
+
+exit:
+#ifdef USE_ION_ALLOC
+ if (!IS_ERR_OR_NULL(buf)) {
+ ion_unmap_kernel(core->fimc_ion_client, handle);
+ }
+
+ if (!IS_ERR_OR_NULL(handle)) {
+ ion_free(core->fimc_ion_client, handle);
+ }
+#else
+ if (buf) {
+ vfree(buf);
+ }
+#endif
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_COMPANION_USE
+int fimc_is_sec_read_companion_fw(struct fimc_is_core *core)
+{
+ int ret = 0;
+ char *buf = NULL;
+ loff_t pos = 0;
+ char fw_path[100];
+ char master_setfile_path[100];
+ char mode_setfile_path[100];
+ char master_setf_name[50];
+ char mode_setf_name[50];
+ int retry = FIMC_IS_FW_RETRY_CNT;
+#ifdef USE_ION_ALLOC
+ struct ion_handle *handle = NULL;
+#endif
+
+ pr_info("Camera: Companion FW, Setfile need to be dumped\n");
+#ifdef USE_ION_ALLOC
+ handle = ion_alloc(core->fimc_ion_client, (size_t)FIMC_IS_MAX_COMPANION_FW_SIZE, 0,
+ EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ err("(%s)failed to ioc_alloc\n",__func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ buf = (char *)ion_map_kernel(core->fimc_ion_client, handle);
+ if (IS_ERR_OR_NULL(buf)) {
+ err("(%s)fail to ion_map_kernle\n",__func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+#else
+ buf = vmalloc(FIMC_IS_MAX_COMPANION_FW_SIZE);
+ if (!buf) {
+ err("vmalloc fail");
+ ret = -ENOMEM;
+ goto exit;
+ }
+#endif
+ crc_retry:
+
+ /* read companion fw data */
+ pr_info("Camera: Start SPI read companion fw data\n\n");
+ ret = fimc_is_spi_read_by_core(core->spi0, buf, 0x2B000, FIMC_IS_MAX_COMPANION_FW_SIZE);
+ if (ret < 0) {
+ err("failed to fimc_is_spi_read (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+ pr_info("Camera: End SPI read companion fw data\n\n");
+
+ /* CRC check */
+ if (!fimc_is_sec_check_companion_fw_crc32(buf) && (retry > 0)) {
+ retry--;
+ goto crc_retry;
+ } else if (!retry) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (sysfs_finfo.concord_header_ver[9] == 0) {
+ snprintf(fw_path, sizeof(fw_path), "%s%s",
+ FIMC_IS_FW_DUMP_PATH, FIMC_IS_FW_COMPANION_EVT0);
+ } else if (sysfs_finfo.concord_header_ver[9] == 10) {
+ snprintf(fw_path, sizeof(fw_path), "%s%s",
+ FIMC_IS_FW_DUMP_PATH, FIMC_IS_FW_COMPANION_EVT1);
+ }
+
+ if (write_data_to_file(fw_path, buf,
+ sysfs_finfo.concord_bin_end_addr - sysfs_finfo.concord_bin_start_addr + 1, &pos) < 0) {
+ ret = -EIO;
+ goto exit;
+ }
+
+ pr_info("Camera: Companion FW Data has dumped successfully\n");
+
+ if (sysfs_finfo.concord_header_ver[FW_SENSOR_MAKER] == FW_SENSOR_MAKER_SLSI) {
+ snprintf(master_setf_name, sizeof(master_setf_name), "%s", FIMC_IS_COMPANION_MASTER_SETF);
+ snprintf(mode_setf_name, sizeof(mode_setf_name), "%s", FIMC_IS_COMPANION_MODE_SETF);
+ } else {
+ snprintf(master_setf_name, sizeof(master_setf_name), "%s", FIMC_IS_COMPANION_MASTER_SETF);
+ snprintf(mode_setf_name, sizeof(mode_setf_name), "%s", FIMC_IS_COMPANION_MODE_SETF);
+ }
+
+ snprintf(master_setfile_path, sizeof(master_setfile_path), "%s%s", FIMC_IS_FW_DUMP_PATH, master_setf_name);
+ snprintf(mode_setfile_path, sizeof(mode_setfile_path), "%s%s", FIMC_IS_FW_DUMP_PATH, mode_setf_name);
+ pos = 0;
+
+ if (write_data_to_file(master_setfile_path,
+ buf + sysfs_finfo.concord_master_setfile_start_addr,
+ sysfs_finfo.concord_master_setfile_end_addr - sysfs_finfo.concord_master_setfile_start_addr + 1, &pos) < 0) {
+ ret = -EIO;
+ goto exit;
+ }
+ pos = 0;
+ if (write_data_to_file(mode_setfile_path,
+ buf + sysfs_finfo.concord_mode_setfile_start_addr,
+ sysfs_finfo.concord_mode_setfile_end_addr - sysfs_finfo.concord_mode_setfile_start_addr + 1, &pos) < 0) {
+ ret = -EIO;
+ goto exit;
+ }
+
+ pr_info("Camera: Companion Setfile has dumped successfully\n");
+ pr_info("Camera: Companion FW, Setfile were dumped successfully\n");
+
+exit:
+#ifdef USE_ION_ALLOC
+ if (!IS_ERR_OR_NULL(buf)) {
+ ion_unmap_kernel(core->fimc_ion_client, handle);
+ }
+
+ if (!IS_ERR_OR_NULL(handle)) {
+ ion_free(core->fimc_ion_client, handle);
+ }
+#else
+ if (buf) {
+ vfree(buf);
+ }
+#endif
+
+ return ret;
+}
+#endif
+
+#if 0
+int fimc_is_sec_gpio_enable(struct exynos_platform_fimc_is *pdata, char *name, bool on)
+{
+ struct gpio_set *gpio;
+ int ret = 0;
+ int i = 0;
+
+ for (i = 0; i < FIMC_IS_MAX_GPIO_NUM; i++) {
+ gpio = &pdata->gpio_info->cfg[i];
+ if (strcmp(gpio->name, name) == 0)
+ break;
+ else
+ continue;
+ }
+
+ if (i == FIMC_IS_MAX_GPIO_NUM) {
+ pr_err("GPIO %s is not found!!\n", name);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = gpio_request(gpio->pin, gpio->name);
+ if (ret) {
+ pr_err("Request GPIO error(%s)\n", gpio->name);
+ goto exit;
+ }
+
+ if (on) {
+ switch (gpio->act) {
+ case GPIO_PULL_NONE:
+ s3c_gpio_cfgpin(gpio->pin, gpio->value);
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_NONE);
+ break;
+ case GPIO_OUTPUT:
+ s3c_gpio_cfgpin(gpio->pin, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_NONE);
+ gpio_set_value(gpio->pin, gpio->value);
+ break;
+ case GPIO_INPUT:
+ s3c_gpio_cfgpin(gpio->pin, S3C_GPIO_INPUT);
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_NONE);
+ gpio_set_value(gpio->pin, gpio->value);
+ break;
+ case GPIO_RESET:
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_NONE);
+ gpio_direction_output(gpio->pin, 0);
+ gpio_direction_output(gpio->pin, 1);
+ break;
+ default:
+ pr_err("unknown act for gpio\n");
+ break;
+ }
+ } else {
+ s3c_gpio_cfgpin(gpio->pin, S3C_GPIO_INPUT);
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_DOWN);
+ }
+
+ gpio_free(gpio->pin);
+
+exit:
+ return ret;
+}
+#endif
+
+int fimc_is_sec_get_pixel_size(char *header_ver)
+{
+ int pixelsize = 0;
+
+ pixelsize += (int) (header_ver[FW_PIXEL_SIZE] - 0x30) * 10;
+ pixelsize += (int) (header_ver[FW_PIXEL_SIZE + 1] - 0x30);
+
+ return pixelsize;
+}
+
+int fimc_is_sec_core_voltage_select(struct device *dev, char *header_ver)
+{
+ struct regulator *regulator = NULL;
+ int ret = 0;
+ int minV, maxV;
+ int pixelSize = 0;
+
+ regulator = regulator_get(dev, "cam_sensor_core_1.2v");
+ if (IS_ERR_OR_NULL(regulator)) {
+ pr_err("%s : regulator_get fail\n",
+ __func__);
+ return -EINVAL;
+ }
+ pixelSize = fimc_is_sec_get_pixel_size(header_ver);
+
+ if (header_ver[FW_SENSOR_MAKER] == FW_SENSOR_MAKER_SONY) {
+ if (pixelSize == 13) {
+ minV = 1050000;
+ maxV = 1050000;
+ } else if (pixelSize == 8) {
+ minV = 1100000;
+ maxV = 1100000;
+ } else {
+ minV = 1050000;
+ maxV = 1050000;
+ }
+ } else if (header_ver[FW_SENSOR_MAKER] == FW_SENSOR_MAKER_SLSI) {
+ minV = 1200000;
+ maxV = 1200000;
+ } else {
+ minV = 1050000;
+ maxV = 1050000;
+ }
+
+ ret = regulator_set_voltage(regulator, minV, maxV);
+
+ if (ret >= 0)
+ pr_info("%s : set_core_voltage %d, %d successfully\n",
+ __func__, minV, maxV);
+ regulator_put(regulator);
+
+ return ret;
+}
+
+/**
+ * fimc_is_sec_ldo_enabled: check whether the ldo has already been enabled.
+ *
+ * @ return: true, false or error value
+ */
+static int fimc_is_sec_ldo_enabled(struct device *dev, char *name) {
+ struct regulator *regulator = NULL;
+ int enabled = 0;
+
+ regulator = regulator_get(dev, name);
+ if (IS_ERR_OR_NULL(regulator)) {
+ pr_err("%s : regulator_get(%s) fail\n", __func__, name);
+ return -EINVAL;
+ }
+
+ enabled = regulator_is_enabled(regulator);
+
+ regulator_put(regulator);
+
+ return enabled;
+}
+
+int fimc_is_sec_ldo_enable(struct device *dev, char *name, bool on)
+{
+ struct regulator *regulator = NULL;
+ int ret = 0;
+
+ regulator = regulator_get(dev, name);
+ if (IS_ERR_OR_NULL(regulator)) {
+ pr_err("%s : regulator_get(%s) fail\n", __func__, name);
+ return -EINVAL;
+ }
+
+ if (on) {
+ if (regulator_is_enabled(regulator)) {
+ pr_warning("%s: regulator is already enabled\n", name);
+ goto exit;
+ }
+
+ ret = regulator_enable(regulator);
+ if (ret) {
+ pr_err("%s : regulator_enable(%s) fail\n", __func__, name);
+ goto exit;
+ }
+ } else {
+ if (!regulator_is_enabled(regulator)) {
+ pr_warning("%s: regulator is already disabled\n", name);
+ goto exit;
+ }
+
+ ret = regulator_disable(regulator);
+ if (ret) {
+ pr_err("%s : regulator_disable(%s) fail\n", __func__, name);
+ goto exit;
+ }
+ }
+
+exit:
+ if (regulator)
+ regulator_put(regulator);
+
+ return ret;
+}
+
+int fimc_is_sec_fw_find(struct fimc_is_core *core, char *fw_name, char *setf_name)
+{
+ int pixelSize = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_device_sensor *sensor_device = &core->sensor[0];
+
+ BUG_ON(!sensor_device);
+ BUG_ON(!sensor_device->pdata);
+ BUG_ON(!sensor_device->pdata->sensor_id);
+
+ pdata = sensor_device->pdata;
+
+ if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_2P2_F) ||
+ fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_2P2_I)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P2), "%s", FIMC_IS_FW_2P2);
+ snprintf(setf_name, sizeof(FIMC_IS_2P2_SETF), "%s", FIMC_IS_2P2_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_2P2_12M)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P2_12M), "%s", FIMC_IS_FW_2P2_12M);
+ snprintf(setf_name, sizeof(FIMC_IS_2P2_12M_SETF), "%s", FIMC_IS_2P2_12M_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_2P3)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P3), "%s", FIMC_IS_FW_2P3);
+ snprintf(setf_name, sizeof(FIMC_IS_2P3_SETF), "%s", FIMC_IS_2P3_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_4H5)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_4H5), "%s", FIMC_IS_FW_4H5);
+ snprintf(setf_name, sizeof(FIMC_IS_4H5_SETF), "%s", FIMC_IS_4H5_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_IMX240) ||
+ fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_IMX240_Q)) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_IMX240), "%s", FIMC_IS_FW_IMX240);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX240_SETF), "%s", FIMC_IS_IMX240_SETF);
+ } else {
+ /* Use the PixelSize information */
+ pixelSize = fimc_is_sec_get_pixel_size(sysfs_finfo.header_ver);
+ if (pixelSize == 16) {
+ if (pdata->sensor_id == SENSOR_NAME_S5K2P3) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P3), "%s", FIMC_IS_FW_2P3);
+ snprintf(setf_name, sizeof(FIMC_IS_2P3_SETF), "%s", FIMC_IS_2P3_SETF);
+ } else {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P2), "%s", FIMC_IS_FW_2P2);
+ snprintf(setf_name, sizeof(FIMC_IS_2P2_SETF), "%s", FIMC_IS_2P2_SETF);
+ }
+ } else if (pixelSize == 13) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW), "%s", FIMC_IS_FW);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX135_SETF), "%s", FIMC_IS_IMX135_SETF);
+ } else if (pixelSize == 12) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P2_12M), "%s", FIMC_IS_FW_2P2_12M);
+ snprintf(setf_name, sizeof(FIMC_IS_2P2_12M_SETF), "%s", FIMC_IS_2P2_12M_SETF);
+ } else if (pixelSize == 8) {
+ snprintf(fw_name, sizeof(FIMC_IS_FW_IMX134), "%s", FIMC_IS_FW_IMX134);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX134_SETF), "%s", FIMC_IS_IMX134_SETF);
+ } else {
+ /* default firmware and setfile */
+ if ( pdata->sensor_id == SENSOR_NAME_IMX240 ) {
+ /* IMX240 */
+ snprintf(fw_name, sizeof(FIMC_IS_FW_IMX240), "%s", FIMC_IS_FW_IMX240);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX240_SETF), "%s", FIMC_IS_IMX240_SETF);
+ } else if ( pdata->sensor_id == SENSOR_NAME_IMX134 ) {
+ /* IMX134 */
+ snprintf(fw_name, sizeof(FIMC_IS_FW_IMX134), "%s", FIMC_IS_FW_IMX134);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX134_SETF), "%s", FIMC_IS_IMX134_SETF);
+ } else if ( pdata->sensor_id == SENSOR_NAME_S5K2P2_12M ) {
+ /* 2P2_12M */
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P2_12M), "%s", FIMC_IS_FW_2P2_12M);
+ snprintf(setf_name, sizeof(FIMC_IS_2P2_12M_SETF), "%s", FIMC_IS_2P2_12M_SETF);
+ } else if ( pdata->sensor_id == SENSOR_NAME_S5K2P2 ) {
+ /* 2P2 */
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P2), "%s", FIMC_IS_FW_2P2);
+ snprintf(setf_name, sizeof(FIMC_IS_2P2_SETF), "%s", FIMC_IS_2P2_SETF);
+ } else if ( pdata->sensor_id == SENSOR_NAME_S5K2P3 ) {
+ /* 2P3 */
+ snprintf(fw_name, sizeof(FIMC_IS_FW_2P3), "%s", FIMC_IS_FW_2P3);
+ snprintf(setf_name, sizeof(FIMC_IS_2P3_SETF), "%s", FIMC_IS_2P3_SETF);
+ } else if ( pdata->sensor_id == SENSOR_NAME_S5K4H5 ) {
+ /* 4H5 */
+ snprintf(fw_name, sizeof(FIMC_IS_FW_4H5), "%s", FIMC_IS_FW_4H5);
+ snprintf(setf_name, sizeof(FIMC_IS_4H5_SETF), "%s", FIMC_IS_4H5_SETF);
+ } else {
+ snprintf(fw_name, sizeof(FIMC_IS_FW), "%s", FIMC_IS_FW);
+ snprintf(setf_name, sizeof(FIMC_IS_IMX135_SETF), "%s", FIMC_IS_IMX135_SETF);
+ }
+ }
+ }
+
+ strcpy(sysfs_finfo.load_fw_name, fw_name);
+ strcpy(sysfs_finfo.load_setfile_name, setf_name);
+
+ return 0;
+}
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+int fimc_is_sec_fw_sel_eeprom(struct device *dev,
+ char *fw_name, char *setf_name, int id, bool headerOnly)
+{
+ int ret = 0;
+ char fw_path[100];
+ char phone_fw_version[12] = {0, };
+
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long fsize, nread;
+ u8 *fw_buf = NULL;
+ bool is_ldo_enabled = false;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(pdev);
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_device_sensor *sensor_device = &core->sensor[0];
+
+ BUG_ON(!sensor_device);
+ BUG_ON(!sensor_device->pdata);
+ BUG_ON(!sensor_device->pdata->sensor_id);
+
+ pdata = sensor_device->pdata;
+
+ /* Use mutex for i2c read */
+ mutex_lock(&core->spi_lock);
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ if (!sysfs_finfo_front.is_caldata_read || force_caldata_dump) {
+ if (force_caldata_dump)
+ pr_info("forced caldata dump!!\n");
+
+ if (!fimc_is_sec_ldo_enabled(dev, "VT_CAM_1.8V")) {
+ ret = fimc_is_sec_ldo_enable(dev, "VT_CAM_1.8V", true);
+ if (ret) {
+ pr_err("fimc_is_sec_fw_sel_eeprom: error, failed to cam_io(on)");
+ goto exit;
+ }
+
+ is_ldo_enabled = true;
+ }
+
+ pr_info("Camera: read cal data from Front EEPROM\n");
+ if ((fimc_is_sec_readcal_eeprom(dev, SENSOR_POSITION_FRONT) != -EIO) &&
+ crc32_header_check_front) {
+ sysfs_finfo_front.is_caldata_read = true;
+ }
+ }
+ goto exit;
+ } else
+#endif
+ {
+ if (!sysfs_finfo.is_caldata_read || force_caldata_dump) {
+ is_dumped_fw_loading_needed = false;
+ if (force_caldata_dump)
+ pr_info("forced caldata dump!!\n");
+
+ if (!fimc_is_sec_ldo_enabled(dev, "CAM_IO_1.8V_AP")) {
+ ret = fimc_is_sec_ldo_enable(dev, "CAM_IO_1.8V_AP", true);
+ if (ret) {
+ pr_err("fimc_is_sec_fw_sel_eeprom: error, failed to cam_io(on)");
+ goto exit;
+ }
+
+ is_ldo_enabled = true;
+ }
+
+ pr_info("Camera: read cal data from Rear EEPROM\n");
+ if (headerOnly) {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+ fimc_is_sec_read_eeprom_header(dev);
+#endif
+ } else {
+ if ((fimc_is_sec_readcal_eeprom(dev, SENSOR_POSITION_REAR) != -EIO) &&
+ crc32_header_check) {
+ sysfs_finfo.is_caldata_read = true;
+ }
+ }
+ }
+ }
+
+ fimc_is_sec_fw_find(core, fw_name, setf_name);
+ if (headerOnly) {
+ goto exit;
+ }
+
+ snprintf(fw_path, sizeof(fw_path), "%s%s", FIMC_IS_FW_PATH, fw_name);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ fp = filp_open(fw_path, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ pr_err("Camera: Failed open phone firmware\n");
+ ret = -EIO;
+ fp = NULL;
+ goto read_phone_fw_exit;
+ }
+
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start, file path %s, size %ld Bytes\n",
+ fw_path, fsize);
+ fw_buf = vmalloc(fsize);
+ if (!fw_buf) {
+ pr_err("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto read_phone_fw_exit;
+ }
+ nread = vfs_read(fp, (char __user *)fw_buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ pr_err("failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto read_phone_fw_exit;
+ }
+
+ strncpy(phone_fw_version, fw_buf + nread - 11, 11);
+ strncpy(sysfs_pinfo.header_ver, fw_buf + nread - 11, 11);
+ pr_info("Camera: phone fw version: %s\n", phone_fw_version);
+read_phone_fw_exit:
+ if (fw_buf) {
+ vfree(fw_buf);
+ fw_buf = NULL;
+ }
+
+ if (fp) {
+ filp_close(fp, current->files);
+ fp = NULL;
+ }
+
+ set_fs(old_fs);
+
+exit:
+ if (is_ldo_enabled) {
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+ if (id == SENSOR_POSITION_FRONT) {
+ ret = fimc_is_sec_ldo_enable(dev, "VT_CAM_1.8V", false);
+ } else
+#endif
+ {
+ ret = fimc_is_sec_ldo_enable(dev, "CAM_IO_1.8V_AP", false);
+ }
+ if (ret)
+ pr_err("fimc_is_sec_fw_sel_eeprom: error, failed to cam_io(off)");
+ }
+
+ mutex_unlock(&core->spi_lock);
+
+ return ret;
+}
+#endif
+
+#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev,
+ char *fw_name, char *setf_name, bool headerOnly)
+{
+ int ret = 0;
+#if 1
+ char fw_path[100];
+ char dump_fw_path[100];
+ char dump_fw_version[12] = {0, };
+ char phone_fw_version[12] = {0, };
+ int from_fw_revision = 0;
+ int dump_fw_revision = 0;
+ int phone_fw_revision = 0;
+
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long fsize, nread;
+ u8 *fw_buf = NULL;
+ bool is_dump_existed = false;
+ bool is_dump_needed = true;
+#endif
+#ifdef CONFIG_COMPANION_USE
+ struct fimc_is_spi_gpio *spi_gpio = &core->spi_gpio;
+#endif
+ bool is_ldo_enabled = false;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct fimc_is_device_sensor *sensor_device = &core->sensor[0];
+
+ BUG_ON(!sensor_device);
+ BUG_ON(!sensor_device->pdata);
+ BUG_ON(!sensor_device->pdata->sensor_id);
+
+ pdata = sensor_device->pdata;
+
+ /* Use mutex for spi read */
+ mutex_lock(&core->spi_lock);
+ if (!sysfs_finfo.is_caldata_read || force_caldata_dump) {
+ is_dumped_fw_loading_needed = false;
+ if (force_caldata_dump)
+ pr_info("forced caldata dump!!\n");
+ if (!fimc_is_sec_ldo_enabled(dev, "CAM_IO_1.8V_AP")) {
+ pr_info("enable %s in the %s\n", "CAM_IO_1.8V_AP", __func__);
+ ret = fimc_is_sec_ldo_enable(dev, "CAM_IO_1.8V_AP", true);
+ if (ret) {
+ pr_err("fimc_is_sec_fw_sel: error, failed to cam_io(on)");
+ goto exit;
+ }
+
+ is_ldo_enabled = true;
+ }
+ pr_info("read cal data from FROM\n");
+#ifdef CONFIG_COMPANION_USE
+ fimc_is_set_spi_config(spi_gpio, FIMC_IS_SPI_FUNC, false);
+#endif
+
+ if (headerOnly) {
+ fimc_is_sec_read_from_header(dev);
+ } else {
+ if ((fimc_is_sec_readcal(core) != -EIO) &&
+ crc32_header_check) {
+ sysfs_finfo.is_caldata_read = true;
+ }
+ }
+
+#ifdef CONFIG_COMPANION_USE
+ fimc_is_set_spi_config(spi_gpio, FIMC_IS_SPI_OUTPUT, false);
+#endif
+ /*select AF actuator*/
+ if (!crc32_header_check) {
+ pr_info("Camera : CRC32 error for all section.\n");
+ //ret = -EIO;
+ //goto exit;
+ }
+
+ /*ret = fimc_is_sec_core_voltage_select(dev, sysfs_finfo.header_ver);
+ if (ret < 0) {
+ err("failed to fimc_is_sec_core_voltage_select (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }*/
+
+ fimc_is_sec_fw_find(core, fw_name, setf_name);
+ if (headerOnly) {
+ goto exit;
+ }
+
+ snprintf(fw_path, sizeof(fw_path), "%s%s", FIMC_IS_FW_PATH, fw_name);
+
+#if 1
+ snprintf(dump_fw_path, sizeof(dump_fw_path), "%s%s",
+ FIMC_IS_FW_DUMP_PATH, fw_name);
+ pr_info("Camera: f-rom fw version: %s\n", sysfs_finfo.header_ver);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fp = filp_open(dump_fw_path, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ pr_info("Camera: There is no dumped firmware\n");
+ is_dump_existed = false;
+ goto read_phone_fw;
+ } else {
+ is_dump_existed = true;
+ }
+
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start, file path %s, size %ld Bytes\n",
+ dump_fw_path, fsize);
+ fw_buf = vmalloc(fsize);
+ if (!fw_buf) {
+ pr_err("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto read_phone_fw;
+ }
+ nread = vfs_read(fp, (char __user *)fw_buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ pr_err("failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto read_phone_fw;
+ }
+
+ strncpy(dump_fw_version, fw_buf+nread-11, 11);
+ pr_info("Camera: dumped fw version: %s\n", dump_fw_version);
+
+read_phone_fw:
+ if (fw_buf) {
+ vfree(fw_buf);
+ fw_buf = NULL;
+ }
+
+ if (fp && is_dump_existed) {
+ filp_close(fp, current->files);
+ fp = NULL;
+ }
+
+ set_fs(old_fs);
+
+ if (ret < 0)
+ goto exit;
+#endif
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ fp = filp_open(fw_path, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ pr_err("Camera: Failed open phone firmware\n");
+ ret = -EIO;
+ fp = NULL;
+ goto read_phone_fw_exit;
+ }
+
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start, file path %s, size %ld Bytes\n",
+ fw_path, fsize);
+ fw_buf = vmalloc(fsize);
+ if (!fw_buf) {
+ pr_err("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto read_phone_fw_exit;
+ }
+ nread = vfs_read(fp, (char __user *)fw_buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ pr_err("failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto read_phone_fw_exit;
+ }
+
+ strncpy(phone_fw_version, fw_buf + nread - 11, 11);
+ strncpy(sysfs_pinfo.header_ver, fw_buf + nread - 11, 11);
+ pr_info("Camera: phone fw version: %s\n", phone_fw_version);
+read_phone_fw_exit:
+ if (fw_buf) {
+ vfree(fw_buf);
+ fw_buf = NULL;
+ }
+
+ if (fp) {
+ filp_close(fp, current->files);
+ fp = NULL;
+ }
+
+ set_fs(old_fs);
+
+ if (ret < 0)
+ goto exit;
+
+ from_fw_revision = fimc_is_sec_fw_revision(sysfs_finfo.header_ver);
+ phone_fw_revision = fimc_is_sec_fw_revision(phone_fw_version);
+ if (is_dump_existed)
+ dump_fw_revision = fimc_is_sec_fw_revision(dump_fw_version);
+
+ if ((!fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, phone_fw_version)) ||
+ (from_fw_revision > phone_fw_revision)) {
+ is_dumped_fw_loading_needed = true;
+ if (is_dump_existed) {
+ if (!fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver,
+ dump_fw_version)) {
+ is_dump_needed = true;
+ } else if (from_fw_revision > dump_fw_revision) {
+ is_dump_needed = true;
+ } else {
+ is_dump_needed = false;
+ }
+ } else {
+ is_dump_needed = true;
+ }
+ } else {
+ is_dump_needed = false;
+ if (is_dump_existed) {
+ if (!fimc_is_sec_fw_module_compare(phone_fw_version,
+ dump_fw_version)) {
+ is_dumped_fw_loading_needed = false;
+ } else if (phone_fw_revision > dump_fw_revision) {
+ is_dumped_fw_loading_needed = false;
+ } else {
+ is_dumped_fw_loading_needed = true;
+ }
+ } else {
+ is_dumped_fw_loading_needed = false;
+ }
+ }
+#if 0
+ if (sysfs_finfo.header_ver[0] == 'O') {
+ /* hack: gumi module using phone fw */
+ is_dumped_fw_loading_needed = false;
+ is_dump_needed = false;
+ } else if (sysfs_finfo.header_ver[FW_ISP_COMPANY] != FW_ISP_COMPANY_LSI) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (is_dump_needed) {
+ ret = fimc_is_sec_readfw(core);
+ if (ret < 0) {
+ if (!crc32_fw_check) {
+ is_dumped_fw_loading_needed = false;
+ ret = 0;
+ } else
+ goto exit;
+ }
+ }
+#endif
+ if (is_dump_needed && is_dumped_fw_loading_needed) {
+ strncpy(loaded_fw, sysfs_finfo.header_ver, 11);
+ } else if (!is_dump_needed && is_dumped_fw_loading_needed) {
+ strncpy(loaded_fw, dump_fw_version, 11);
+ } else
+ strncpy(loaded_fw, phone_fw_version, 11);
+
+ } else {
+ pr_info("Did not read cal data from FROM, FW version = %s\n", sysfs_finfo.header_ver);
+ strcpy(fw_name, sysfs_finfo.load_fw_name);
+ strcpy(setf_name, sysfs_finfo.load_setfile_name);
+ }
+
+exit:
+ if (is_ldo_enabled && !core->running_rear_camera) {
+ pr_info("disable %s in the %s\n", "CAM_IO_1.8V_AP", __func__);
+ ret = fimc_is_sec_ldo_enable(dev, "CAM_IO_1.8V_AP", false);
+ if (ret)
+ pr_err("fimc_is_sec_fw_sel: error, failed to cam_io(off)");
+ }
+
+ mutex_unlock(&core->spi_lock);
+
+ if (core->use_module_check) {
+ if (sysfs_finfo.header_ver[3] != 'L') {
+ pr_err("Not supported module. Module ver = %s", sysfs_finfo.header_ver);
+ return -EIO;
+ }
+ }
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_COMPANION_USE
+void fimc_is_set_spi_config(struct fimc_is_spi_gpio *spi_gpio, int func, bool ssn) {
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_sclk,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, func));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_miso,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, func));
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_mois,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, func));
+ if(ssn == true) {
+ pin_config_set(FIMC_IS_SPI_PINNAME, spi_gpio->spi_ssn,
+ PINCFG_PACK(PINCFG_TYPE_FUNC, func));
+ }
+}
+
+int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev,
+ char *fw_name, char *master_setf_name, char *mode_setf_name)
+{
+ int ret = 0;
+ char c1_fw_path[100];
+ char dump_c1_fw_path[100];
+ char dump_c1_fw_version[12] = {0, };
+ char phone_c1_fw_version[12] = {0, };
+ int from_c1_fw_revision = 0;
+ int dump_c1_fw_revision = 0;
+ int phone_c1_fw_revision = 0;
+
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ long fsize, nread;
+ u8 *c1_fw_buf = NULL;
+ bool is_dump_existed = false;
+ bool is_dump_needed = true;
+ int pixelSize = 0;
+
+ if ((!sysfs_finfo.is_c1_caldata_read &&
+ (cam_id == CAMERA_SINGLE_REAR /* || cam_id == CAMERA_DUAL_FRONT*/)) ||
+ force_caldata_dump) {
+ is_dumped_c1_fw_loading_needed = false;
+ if (force_caldata_dump)
+ pr_info("forced caldata dump!!\n");
+
+ pr_info("Load companion fw from FROM\n");
+ sysfs_finfo.is_c1_caldata_read = true;
+
+ /*ret = fimc_is_sec_core_voltage_select(dev, sysfs_finfo.header_ver);
+ if (ret < 0) {
+ err("failed to fimc_is_sec_core_voltage_select (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }*/
+
+ if (fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_2P2_F) ||
+ fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_2P2_I)) {
+ if (sysfs_finfo.concord_header_ver[9] == '0') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_EVT0);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_EVT0), "%s", FIMC_IS_FW_COMPANION_EVT0);
+ } else if (sysfs_finfo.concord_header_ver[9] == '1') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_2P2_EVT1);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_2P2_EVT1), "%s", FIMC_IS_FW_COMPANION_2P2_EVT1);
+ } else {
+ pr_info("Camera : Wrong companion module version.\n");
+ }
+ sysfs_finfo.sensor_id = COMPANION_SENSOR_2P2;
+ snprintf(master_setf_name, sizeof(FIMC_IS_COMPANION_2P2_MASTER_SETF), "%s", FIMC_IS_COMPANION_2P2_MASTER_SETF);
+ snprintf(mode_setf_name, sizeof(FIMC_IS_COMPANION_2P2_MODE_SETF), "%s", FIMC_IS_COMPANION_2P2_MODE_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_IMX240) ||
+ fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_IMX240_Q_C1) ||
+ fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_IMX240_Q)) {
+ if (sysfs_finfo.concord_header_ver[9] == '0') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_EVT0);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_EVT0), "%s", FIMC_IS_FW_COMPANION_EVT0);
+ } else if (sysfs_finfo.concord_header_ver[9] == '1') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_IMX240_EVT1);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_IMX240_EVT1), "%s", FIMC_IS_FW_COMPANION_IMX240_EVT1);
+ } else {
+ pr_info("Camera : Wrong companion module version.\n");
+ }
+ sysfs_finfo.sensor_id = COMPANION_SENSOR_IMX240;
+ snprintf(master_setf_name, sizeof(FIMC_IS_COMPANION_IMX240_MASTER_SETF), "%s", FIMC_IS_COMPANION_IMX240_MASTER_SETF);
+ snprintf(mode_setf_name, sizeof(FIMC_IS_COMPANION_IMX240_MODE_SETF), "%s", FIMC_IS_COMPANION_IMX240_MODE_SETF);
+ } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_2P2_12M)) {
+ if (sysfs_finfo.concord_header_ver[9] == '0') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_EVT0);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_EVT0), "%s", FIMC_IS_FW_COMPANION_EVT0);
+ } else if (sysfs_finfo.concord_header_ver[9] == '1') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_2P2_12M_EVT1);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_2P2_12M_EVT1), "%s", FIMC_IS_FW_COMPANION_2P2_12M_EVT1);
+ } else {
+ pr_info("Camera : Wrong companion module version.\n");
+ }
+ sysfs_finfo.sensor_id = COMPANION_SENSOR_2P2;
+ snprintf(master_setf_name, sizeof(FIMC_IS_COMPANION_2P2_12M_MASTER_SETF), "%s", FIMC_IS_COMPANION_2P2_12M_MASTER_SETF);
+ snprintf(mode_setf_name, sizeof(FIMC_IS_COMPANION_2P2_12M_MODE_SETF), "%s", FIMC_IS_COMPANION_2P2_12M_MODE_SETF);
+ } else {
+ pixelSize = fimc_is_sec_get_pixel_size(sysfs_finfo.concord_header_ver);
+ if (pixelSize == 16) {
+ if (sysfs_finfo.concord_header_ver[9] == '0') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_EVT0);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_EVT0), "%s", FIMC_IS_FW_COMPANION_EVT0);
+ } else if (sysfs_finfo.concord_header_ver[9] == '1') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_2P2_EVT1);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_2P2_EVT1), "%s", FIMC_IS_FW_COMPANION_2P2_EVT1);
+ } else {
+ pr_info("Camera : Wrong companion module version.\n");
+ }
+ sysfs_finfo.sensor_id = COMPANION_SENSOR_2P2;
+ snprintf(master_setf_name, sizeof(FIMC_IS_COMPANION_2P2_MASTER_SETF), "%s", FIMC_IS_COMPANION_2P2_MASTER_SETF);
+ snprintf(mode_setf_name, sizeof(FIMC_IS_COMPANION_2P2_MODE_SETF), "%s", FIMC_IS_COMPANION_2P2_MODE_SETF);
+ } else if (pixelSize == 12) {
+ if (sysfs_finfo.concord_header_ver[9] == '0') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_EVT0);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_EVT0), "%s", FIMC_IS_FW_COMPANION_EVT0);
+ } else if (sysfs_finfo.concord_header_ver[9] == '1') {
+ snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s",
+ FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_2P2_12M_EVT1);
+ snprintf(fw_name, sizeof(FIMC_IS_FW_COMPANION_2P2_12M_EVT1), "%s", FIMC_IS_FW_COMPANION_2P2_12M_EVT1);
+ } else {
+ pr_info("Camera : Wrong companion module version.\n");
+ }
+ sysfs_finfo.sensor_id = COMPANION_SENSOR_2P2;
+ snprintf(master_setf_name, sizeof(FIMC_IS_COMPANION_2P2_12M_MASTER_SETF), "%s", FIMC_IS_COMPANION_2P2_12M_MASTER_SETF);
+ snprintf(mode_setf_name, sizeof(FIMC_IS_COMPANION_2P2_12M_MODE_SETF), "%s", FIMC_IS_COMPANION_2P2_12M_MODE_SETF);
+ }
+ }
+
+ strcpy(sysfs_finfo.load_c1_fw_name, fw_name);
+ strcpy(sysfs_finfo.load_c1_mastersetf_name, master_setf_name);
+ strcpy(sysfs_finfo.load_c1_modesetf_name, mode_setf_name);
+
+ if (sysfs_finfo.concord_header_ver[9] == '0') {
+ snprintf(dump_c1_fw_path, sizeof(dump_c1_fw_path), "%s%s",
+ FIMC_IS_FW_DUMP_PATH, FIMC_IS_FW_COMPANION_EVT0);
+ } else if (sysfs_finfo.concord_header_ver[9] == '1') {
+ snprintf(dump_c1_fw_path, sizeof(dump_c1_fw_path), "%s%s",
+ FIMC_IS_FW_DUMP_PATH, sysfs_finfo.load_c1_fw_name);
+ }
+ pr_info("Camera: f-rom fw version: %s\n", sysfs_finfo.concord_header_ver);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = 0;
+ fp = filp_open(dump_c1_fw_path, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ pr_info("Camera: There is no dumped Companion firmware\n");
+ is_dump_existed = false;
+ goto read_phone_fw;
+ } else {
+ is_dump_existed = true;
+ }
+
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start, file path %s, size %ld Bytes\n",
+ dump_c1_fw_path, fsize);
+ c1_fw_buf = vmalloc(fsize);
+ if (!c1_fw_buf) {
+ pr_err("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto read_phone_fw;
+ }
+ nread = vfs_read(fp, (char __user *)c1_fw_buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ pr_err("failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto read_phone_fw;
+ }
+
+ strncpy(dump_c1_fw_version, c1_fw_buf+nread - 16, 11);
+ pr_info("Camera: dumped companion fw version: %s\n", dump_c1_fw_version);
+read_phone_fw:
+ if (c1_fw_buf) {
+ vfree(c1_fw_buf);
+ c1_fw_buf = NULL;
+ }
+
+ if (fp && is_dump_existed) {
+ filp_close(fp, current->files);
+ fp = NULL;
+ }
+
+ set_fs(old_fs);
+ if (ret < 0)
+ goto exit;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ fp = filp_open(c1_fw_path, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ pr_err("Camera: Failed open phone companion firmware\n");
+ ret = -EIO;
+ fp = NULL;
+ goto read_phone_fw_exit;
+ }
+
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ pr_info("start, file path %s, size %ld Bytes\n",
+ c1_fw_path, fsize);
+ c1_fw_buf = vmalloc(fsize);
+ if (!c1_fw_buf) {
+ pr_err("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto read_phone_fw_exit;
+ }
+ nread = vfs_read(fp, (char __user *)c1_fw_buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ pr_err("failed to read companion firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto read_phone_fw_exit;
+ }
+
+ strncpy(phone_c1_fw_version, c1_fw_buf + nread - 16, 11);
+ strncpy(sysfs_pinfo.concord_header_ver, c1_fw_buf + nread - 16, 11);
+ pr_info("Camera: phone companion fw version: %s\n", phone_c1_fw_version);
+read_phone_fw_exit:
+ if (c1_fw_buf) {
+ vfree(c1_fw_buf);
+ c1_fw_buf = NULL;
+ }
+
+ if (fp) {
+ filp_close(fp, current->files);
+ fp = NULL;
+ }
+
+ set_fs(old_fs);
+
+ if (ret < 0)
+ goto exit;
+
+ from_c1_fw_revision = fimc_is_sec_fw_revision(sysfs_finfo.concord_header_ver);
+ phone_c1_fw_revision = fimc_is_sec_fw_revision(phone_c1_fw_version);
+ if (is_dump_existed)
+ dump_c1_fw_revision = fimc_is_sec_fw_revision(dump_c1_fw_version);
+
+ if ((!fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, phone_c1_fw_version)) ||
+ (from_c1_fw_revision > phone_c1_fw_revision)) {
+ is_dumped_c1_fw_loading_needed = true;
+ if (is_dump_existed) {
+ if (!fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver,
+ dump_c1_fw_version)) {
+ is_dump_needed = true;
+ } else if (from_c1_fw_revision > dump_c1_fw_revision) {
+ is_dump_needed = true;
+ } else {
+ is_dump_needed = false;
+ }
+ } else {
+ is_dump_needed = true;
+ }
+ } else {
+ is_dump_needed = false;
+ if (is_dump_existed) {
+ if (!fimc_is_sec_fw_module_compare(phone_c1_fw_version,
+ dump_c1_fw_version)) {
+ is_dumped_c1_fw_loading_needed = false;
+ } else if (phone_c1_fw_revision > dump_c1_fw_revision) {
+ is_dumped_c1_fw_loading_needed = false;
+ } else {
+ is_dumped_c1_fw_loading_needed = true;
+ }
+ } else {
+ is_dumped_c1_fw_loading_needed = false;
+ }
+ }
+#if 0
+ if (is_dump_needed) {
+ ret = fimc_is_sec_read_companion_fw(core);
+ if (ret < 0) {
+ if (!crc32_c1_fw_check) {
+ is_dumped_c1_fw_loading_needed = false;
+ ret = 0;
+ } else
+ goto exit;
+ }
+ }
+#endif
+ if (is_dump_needed && is_dumped_c1_fw_loading_needed) {
+ strncpy(loaded_companion_fw, sysfs_finfo.concord_header_ver, 11);
+ } else if (!is_dump_needed && is_dumped_c1_fw_loading_needed) {
+ strncpy(loaded_companion_fw, dump_c1_fw_version, 11);
+ } else
+ strncpy(loaded_companion_fw, phone_c1_fw_version, 11);
+ } else {
+ pr_info("Did not Load companion fw from FROM, Companion version = %s\n", sysfs_finfo.concord_header_ver);
+ strcpy(fw_name, sysfs_finfo.load_c1_fw_name);
+ strcpy(master_setf_name, sysfs_finfo.load_c1_mastersetf_name);
+ strcpy(mode_setf_name, sysfs_finfo.load_c1_modesetf_name);
+ }
+
+exit:
+ return ret;
+}
+#endif
--- /dev/null
+#ifndef FIMC_IS_SEC_DEFINE_H
+#define FIMC_IS_SEC_DEFINE_H
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+#include <linux/syscalls.h>
+#include <linux/vmalloc.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <linux/regulator/consumer.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+#include "fimc-is-device-sensor.h"
+#include "fimc-is-device-ischain.h"
+#include "crc32.h"
+#include "fimc-is-companion.h"
+
+#define FW_CORE_VER 0
+#define FW_PIXEL_SIZE 1
+#define FW_ISP_COMPANY 3
+#define FW_SENSOR_MAKER 4
+#define FW_PUB_YEAR 5
+#define FW_PUB_MON 6
+#define FW_PUB_NUM 7
+#define FW_MODULE_COMPANY 9
+#define FW_VERSION_INFO 10
+
+#define FW_ISP_COMPANY_BROADCOMM 'B'
+#define FW_ISP_COMPANY_TN 'C'
+#define FW_ISP_COMPANY_FUJITSU 'F'
+#define FW_ISP_COMPANY_INTEL 'I'
+#define FW_ISP_COMPANY_LSI 'L'
+#define FW_ISP_COMPANY_MARVELL 'M'
+#define FW_ISP_COMPANY_QUALCOMM 'Q'
+#define FW_ISP_COMPANY_RENESAS 'R'
+#define FW_ISP_COMPANY_STE 'S'
+#define FW_ISP_COMPANY_TI 'T'
+#define FW_ISP_COMPANY_DMC 'D'
+
+#define FW_SENSOR_MAKER_SF 'F'
+#define FW_SENSOR_MAKER_SLSI 'L'
+#define FW_SENSOR_MAKER_SONY 'S'
+
+#define FW_MODULE_COMPANY_SEMCO 'S'
+#define FW_MODULE_COMPANY_GUMI 'O'
+#define FW_MODULE_COMPANY_CAMSYS 'C'
+#define FW_MODULE_COMPANY_PATRON 'P'
+#define FW_MODULE_COMPANY_MCNEX 'M'
+#define FW_MODULE_COMPANY_LITEON 'L'
+#define FW_MODULE_COMPANY_VIETNAM 'V'
+#define FW_MODULE_COMPANY_SHARP 'J'
+#define FW_MODULE_COMPANY_NAMUGA 'N'
+#define FW_MODULE_COMPANY_POWER_LOGIX 'A'
+#define FW_MODULE_COMPANY_DI 'D'
+
+#define FW_2P2_F "F16LL"
+#define FW_2P2_I "I16LL"
+#define FW_3L2 "C13LL"
+#define FW_IMX135 "C13LS"
+#define FW_IMX134 "D08LS"
+#define FW_IMX240 "H16LS"
+#define FW_IMX240_Q "H16US"
+#define FW_IMX240_Q_C1 "H16UL"
+#define FW_2P2_12M "G16LL"
+#define FW_4H5 "F08LL"
+#define FW_2P3 "J16LL"
+
+#define SDCARD_FW
+#define FIMC_IS_SETFILE_SDCARD_PATH "/data/media/0/"
+#define FIMC_IS_FW "fimc_is_fw2.bin"
+#define FIMC_IS_FW_2P2 "fimc_is_fw2_2p2.bin"
+#define FIMC_IS_FW_2P2_12M "fimc_is_fw2_2p2_12m.bin"
+#define FIMC_IS_FW_2P3 "fimc_is_fw2_2p3.bin"
+#define FIMC_IS_FW_3L2 "fimc_is_fw2_3l2.bin"
+#define FIMC_IS_FW_4H5 "fimc_is_fw2_4h5.bin"
+#define FIMC_IS_FW_IMX134 "fimc_is_fw2_imx134.bin"
+#define FIMC_IS_FW_IMX240 "fimc_is_fw2_imx240.bin"
+#define FIMC_IS_FW_COMPANION_EVT0 "companion_fw_evt0.bin"
+#define FIMC_IS_FW_COMPANION_EVT1 "companion_fw_evt1.bin"
+#define FIMC_IS_FW_COMPANION_2P2_EVT1 "companion_fw_2p2_evt1.bin"
+#define FIMC_IS_FW_COMPANION_2P2_12M_EVT1 "companion_fw_2p2_12m_evt1.bin"
+#define FIMC_IS_FW_COMPANION_IMX240_EVT1 "companion_fw_imx240_evt1.bin"
+#define FIMC_IS_FW_SDCARD "/data/media/0/fimc_is_fw2.bin"
+#define FIMC_IS_IMX240_SETF "setfile_imx240.bin"
+#define FIMC_IS_IMX135_SETF "setfile_imx135.bin"
+#define FIMC_IS_IMX134_SETF "setfile_imx134.bin"
+#define FIMC_IS_4H5_SETF "setfile_4h5.bin"
+#define FIMC_IS_3L2_SETF "setfile_3l2.bin"
+#define FIMC_IS_6B2_SETF "setfile_6b2.bin"
+#define FIMC_IS_8B1_SETF "setfile_8b1.bin"
+#define FIMC_IS_6D1_SETF "setfile_6d1.bin"
+#define FIMC_IS_2P2_SETF "setfile_2p2.bin"
+#define FIMC_IS_2P2_12M_SETF "setfile_2p2_12m.bin"
+#define FIMC_IS_2P3_SETF "setfile_2p3.bin"
+#define FIMC_IS_COMPANION_MASTER_SETF "companion_master_setfile.bin"
+#define FIMC_IS_COMPANION_MODE_SETF "companion_mode_setfile.bin"
+#define FIMC_IS_COMPANION_2P2_MASTER_SETF "companion_2p2_master_setfile.bin"
+#define FIMC_IS_COMPANION_2P2_MODE_SETF "companion_2p2_mode_setfile.bin"
+#define FIMC_IS_COMPANION_IMX240_MASTER_SETF "companion_imx240_master_setfile.bin"
+#define FIMC_IS_COMPANION_IMX240_MODE_SETF "companion_imx240_mode_setfile.bin"
+#define FIMC_IS_COMPANION_2P2_12M_MASTER_SETF "companion_2p2_12m_master_setfile.bin"
+#define FIMC_IS_COMPANION_2P2_12M_MODE_SETF "companion_2p2_12m_mode_setfile.bin"
+#define FIMC_IS_FW_PATH "/system/vendor/firmware/"
+#define FIMC_IS_FW_DUMP_PATH "/data/"
+
+#define FIMC_IS_FW_BASE_MASK ((1 << 26) - 1)
+#define FIMC_IS_VERSION_SIZE 42
+#define FIMC_IS_SETFILE_VER_OFFSET 0x40
+#define FIMC_IS_SETFILE_VER_SIZE 52
+
+#define FIMC_IS_CAL_SDCARD "/data/cal_data.bin"
+#define FIMC_IS_CAL_SDCARD_FRONT "/data/cal_data_front.bin"
+
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+#define FIMC_IS_MAX_FW_SIZE (8 * 1024)
+#define HEADER_CRC32_LEN (80 / 2)
+#define OEM_CRC32_LEN (64 / 2)
+#define AWB_CRC32_LEN (32 / 2)
+#define SHADING_CRC32_LEN (6623 / 2)
+#else
+/*#define FIMC_IS_MAX_CAL_SIZE (20 * 1024)*/
+#define FIMC_IS_MAX_FW_SIZE (2048 * 1024)
+#define HEADER_CRC32_LEN (224 / 2)
+#define OEM_CRC32_LEN (192 / 2)
+#define AWB_CRC32_LEN (32 / 2)
+#define SHADING_CRC32_LEN (2336 / 2)
+#endif
+
+#define FIMC_IS_MAX_COMPANION_FW_SIZE (120 * 1024)
+#define FIMC_IS_CAL_START_ADDR (0x013D0000)
+#define FIMC_IS_CAL_START_ADDR_FRONT (0x013E0000)
+
+#define FIMC_IS_CAL_RETRY_CNT (2)
+#define FIMC_IS_FW_RETRY_CNT (2)
+#define FROM_VERSION_V004 '4'
+#define FROM_VERSION_V005 '5'
+
+enum {
+ CC_BIN1 = 0,
+ CC_BIN2,
+ CC_BIN3,
+ CC_BIN4,
+ CC_BIN5,
+ CC_BIN6,
+ CC_BIN_MAX,
+};
+
+int fimc_is_sec_set_force_caldata_dump(bool fcd);
+
+ssize_t write_data_to_file(char *name, char *buf, size_t count, loff_t *pos);
+ssize_t read_data_from_file(char *name, char *buf, size_t count, loff_t *pos);
+
+int fimc_is_sec_get_sysfs_finfo(struct fimc_is_from_info **finfo);
+int fimc_is_sec_get_sysfs_pinfo(struct fimc_is_from_info **pinfo);
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+int fimc_is_sec_get_sysfs_finfo_front(struct fimc_is_from_info **finfo);
+int fimc_is_sec_get_sysfs_pinfo_front(struct fimc_is_from_info **pinfo);
+int fimc_is_sec_get_front_cal_buf(char **buf);
+#endif
+
+int fimc_is_sec_get_cal_buf(char **buf);
+int fimc_is_sec_get_loaded_fw(char **buf);
+int fimc_is_sec_get_loaded_c1_fw(char **buf);
+
+int fimc_is_sec_get_camid_from_hal(char *fw_name, char *setf_name);
+int fimc_is_sec_get_camid(void);
+int fimc_is_sec_set_camid(int id);
+int fimc_is_sec_get_pixel_size(char *header_ver);
+int fimc_is_sec_fw_find(struct fimc_is_core *core, char *fw_name, char *setf_name);
+
+int fimc_is_sec_readfw(struct fimc_is_core *core);
+#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT)
+int fimc_is_sec_fw_sel_eeprom(struct device *dev, char *fw_name, char *setf_name, int id, bool headerOnly);
+#endif
+#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR)
+int fimc_is_sec_readcal(struct fimc_is_core *core);
+int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, char *fw_name, char *setf_name, bool headerOnly);
+#endif
+#ifdef CONFIG_COMPANION_USE
+int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev,
+ char *fw_name, char *master_setf_name, char *mode_setf_name);
+#endif
+int fimc_is_sec_fw_revision(char *fw_ver);
+int fimc_is_sec_fw_revision(char *fw_ver);
+bool fimc_is_sec_fw_module_compare(char *fw_ver1, char *fw_ver2);
+
+bool fimc_is_sec_check_fw_crc32(char *buf);
+bool fimc_is_sec_check_cal_crc32(char *buf, int id);
+void fimc_is_sec_make_crc32_table(u32 *table, u32 id);
+
+int fimc_is_sec_gpio_enable(struct exynos_platform_fimc_is *pdata, char *name, bool on);
+int fimc_is_sec_core_voltage_select(struct device *dev, char *header_ver);
+int fimc_is_sec_ldo_enable(struct device *dev, char *name, bool on);
+
+int fimc_is_spi_reset_by_core(struct spi_device *spi, void *buf, u32 rx_addr, size_t size);
+int fimc_is_spi_read_by_core(struct spi_device *spi, void *buf, u32 rx_addr, size_t size);
+#ifdef CONFIG_COMPANION_USE
+void fimc_is_set_spi_config(struct fimc_is_spi_gpio *spi_gpio, int func, bool ssn);
+#endif
+#endif /* FIMC_IS_SEC_DEFINE_H */
--- /dev/null
+/*
+ * driver for FIMC-IS SPI
+ *
+ * Copyright (c) 2011, Samsung Electronics. All rights reserved
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#include "fimc-is-core.h"
+#include "fimc-is-regs.h"
+
+#define STREAM_TO_U16(var16, p) {(var16) = ((u16)(*((u8 *)p+1)) + \
+ ((u8)(*((u8 *)p) << 8))); }
+
+#ifndef __devinit
+#define __devinit
+#endif
+
+#ifndef __devexit
+#define __devexit
+#endif
+
+#ifndef __devexit_p
+#define __devexit_p(x) x
+#endif
+
+static struct spi_device *g_spi;
+
+int fimc_is_spi_reset(void *buf, u32 rx_addr, size_t size)
+{
+ unsigned char req_rst[1] = { 0x99 };
+ int ret;
+
+ struct spi_transfer t_c;
+ struct spi_transfer t_r;
+
+ struct spi_message m;
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ t_c.tx_buf = req_rst;
+ t_c.len = 1;
+ t_c.cs_change = 0;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+
+ ret = spi_sync(g_spi, &m);
+ if (ret) {
+ err("spi sync error - can't get device information");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int fimc_is_spi_read(void *buf, u32 rx_addr, size_t size)
+{
+ unsigned char req_data[4] = { 0x03, };
+ int ret;
+
+ struct spi_transfer t_c;
+ struct spi_transfer t_r;
+
+ struct spi_message m;
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ req_data[1] = (rx_addr & 0xFF0000) >> 16;
+ req_data[2] = (rx_addr & 0xFF00) >> 8;
+ req_data[3] = (rx_addr & 0xFF);
+
+ t_c.tx_buf = req_data;
+ t_c.len = 4;
+ t_c.cs_change = 1;
+ t_c.bits_per_word = 32;
+
+ t_r.rx_buf = buf;
+ t_r.len = size;
+ t_r.cs_change = 0;
+ t_r.bits_per_word = 32;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+ spi_message_add_tail(&t_r, &m);
+
+ ret = spi_sync(g_spi, &m);
+ if (ret) {
+ err("spi sync error - can't read data");
+ return -EIO;
+ } else
+ return 0;
+}
+
+int fimc_is_spi_reset_by_core(struct spi_device *spi, void *buf, u32 rx_addr, size_t size)
+{
+ unsigned char req_rst[1] = { 0x99 };
+ int ret;
+
+ struct spi_transfer t_c;
+ struct spi_transfer t_r;
+
+ struct spi_message m;
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ t_c.tx_buf = req_rst;
+ t_c.len = 1;
+ t_c.cs_change = 0;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+
+ ret = spi_sync(spi, &m);
+ if (ret) {
+ err("spi sync error - can't get device information");
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(fimc_is_spi_reset_by_core);
+
+int fimc_is_spi_read_by_core(struct spi_device *spi, void *buf, u32 rx_addr, size_t size)
+{
+ unsigned char req_data[4] = { 0x03, };
+ int ret;
+
+ struct spi_transfer t_c;
+ struct spi_transfer t_r;
+
+ struct spi_message m;
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ req_data[1] = (rx_addr & 0xFF0000) >> 16;
+ req_data[2] = (rx_addr & 0xFF00) >> 8;
+ req_data[3] = (rx_addr & 0xFF);
+
+ t_c.tx_buf = req_data;
+ t_c.len = 4;
+ t_c.cs_change = 1;
+ t_c.bits_per_word = 32;
+
+ t_r.rx_buf = buf;
+ t_r.len = size;
+ t_r.cs_change = 0;
+ t_r.bits_per_word = 32;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+ spi_message_add_tail(&t_r, &m);
+
+ spi->max_speed_hz = 48000000;
+ ret = spi_sync(spi, &m);
+ if (ret) {
+ err("spi sync error - can't read data");
+ return -EIO;
+ } else {
+ return 0;
+ }
+}
+EXPORT_SYMBOL(fimc_is_spi_read_by_core);
+
+int fimc_is_spi_read_module_id(struct spi_device *spi, void *buf, u16 rx_addr, size_t size)
+{
+ unsigned char req_data[4] = { 0x90, };
+ int ret;
+
+ struct spi_transfer t_c;
+ struct spi_transfer t_r;
+
+ struct spi_message m;
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ req_data[1] = (rx_addr & 0xFF00) >> 8;
+ req_data[2] = (rx_addr & 0xFF);
+
+ t_c.tx_buf = req_data;
+ t_c.len = 4;
+ t_c.cs_change = 1;
+ t_c.bits_per_word = 32;
+
+ t_r.rx_buf = buf;
+ t_r.len = size;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+ spi_message_add_tail(&t_r, &m);
+
+ spi->max_speed_hz = 48000000;
+ ret = spi_sync(spi, &m);
+ if (ret) {
+ err("spi sync error - can't read data");
+ return -EIO;
+ } else {
+ return 0;
+ }
+}
+EXPORT_SYMBOL(fimc_is_spi_read_module_id);
+
+
+static int __devinit fimc_is_spi_probe(struct spi_device *spi)
+{
+ int ret = 0;
+
+ dbg_core("%s\n", __func__);
+
+ /* spi->bits_per_word = 16; */
+ if (spi_setup(spi)) {
+ pr_err("failed to setup spi for fimc_is_spi\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ g_spi = spi;
+
+exit:
+ return ret;
+}
+
+static int __devexit fimc_is_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static struct spi_driver fimc_is_spi_driver = {
+ .driver = {
+ .name = "fimc_is_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = fimc_is_spi_probe,
+ .remove = __devexit_p(fimc_is_spi_remove),
+};
+
+static int __init fimc_is_spi_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&fimc_is_spi_driver);
+
+ if (ret)
+ pr_err("failed to register imc_is_spi- %x\n", ret);
+
+ return ret;
+}
+
+static void __exit fimc_is_spi_exit(void)
+{
+ spi_unregister_driver(&fimc_is_spi_driver);
+}
+
+module_init(fimc_is_spi_init);
+module_exit(fimc_is_spi_exit);
+
+MODULE_DESCRIPTION("FIMC-IS SPI driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+#include <linux/module.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+
+int fimc_is_subdev_open(struct fimc_is_subdev *subdev,
+ struct fimc_is_video_ctx *vctx,
+ const struct param_control *init_ctl)
+{
+ int ret = 0;
+
+ if (test_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state)) {
+ warn("subdev%d already open", subdev->entry);
+ goto p_err;
+ }
+
+ mutex_init(&subdev->mutex_state);
+ subdev->vctx = vctx;
+ subdev->input.width = 0;
+ subdev->input.height = 0;
+ subdev->output.width = 0;
+ subdev->output.height = 0;
+
+ if (init_ctl) {
+ if (init_ctl->cmd != CONTROL_COMMAND_START) {
+ if ((subdev->entry == ENTRY_DIS) ||
+ (subdev->entry == ENTRY_TDNR)) {
+#if defined(ENABLE_VDIS) || defined(ENABLE_TDNR)
+ err("%d entry is not start", subdev->entry);
+#endif
+ } else {
+ err("%d entry is not start", subdev->entry);
+ }
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (init_ctl->bypass == CONTROL_BYPASS_ENABLE)
+ clear_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+ else if (init_ctl->bypass == CONTROL_BYPASS_DISABLE)
+ set_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+ else {
+ err("%d entry has invalid bypass value(%d)",
+ subdev->entry, init_ctl->bypass);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ } else {
+ /* isp, scc, scp do not use bypass(memory interface)*/
+ clear_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+ }
+
+ set_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_subdev_close(struct fimc_is_subdev *subdev)
+{
+ clear_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state);
+
+ return 0;
+}
+
+int fimc_is_subdev_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue)
+{
+ return 0;
+}
+
+int fimc_is_subdev_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!queue);
+
+ framemgr = &queue->framemgr;
+
+/*
+ if (!test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) {
+ mwarn("already stop", device);
+ goto p_err;
+ }
+*/
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_4, flags);
+
+ if (framemgr->frame_pro_cnt > 0) {
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_4, flags);
+ merr("being processed, can't stop", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ fimc_is_frame_complete_head(framemgr, &frame);
+ }
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_req_to_fre(framemgr, frame);
+ fimc_is_frame_request_head(framemgr, &frame);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_4, flags);
+
+ clear_bit(FIMC_IS_SUBDEV_START, &subdev->state);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_subdev_s_format(struct fimc_is_subdev *subdev,
+ u32 width, u32 height)
+{
+ int ret = 0;
+
+ BUG_ON(!subdev);
+
+ subdev->output.width = width;
+ subdev->output.height = height;
+
+ return ret;
+}
+
+int fimc_is_subdev_buffer_queue(struct fimc_is_subdev *subdev,
+ u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!subdev);
+ BUG_ON(!subdev->vctx);
+ BUG_ON(index >= FRAMEMGR_MAX_REQUEST);
+
+ vctx = subdev->vctx;
+ framemgr = GET_DST_FRAMEMGR(vctx);
+
+ /* 1. check frame validation */
+ frame = &framemgr->frame[index];
+ if (!frame) {
+ merr("frame is null\n", vctx);
+ ret = EINVAL;
+ goto p_err;
+ }
+
+ if (unlikely(!test_bit(FRAME_INI_MEM, &frame->memory))) {
+ err("frame %d is NOT init", index);
+ ret = EINVAL;
+ goto p_err;
+ }
+
+ /* 2. update frame manager */
+ framemgr_e_barrier_irqs(framemgr, index, flags);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_FREE) {
+ if (frame->req_flag) {
+ warn("%d request flag is not clear(%08X)\n",
+ frame->index, (u32)frame->req_flag);
+ frame->req_flag = 0;
+ }
+
+ fimc_is_frame_trans_fre_to_req(framemgr, frame);
+ } else {
+ merr("frame(%d) is invalid state(%d)\n", vctx, index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, index, flags);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_subdev_buffer_finish(struct fimc_is_subdev *subdev,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!subdev);
+ BUG_ON(index >= FRAMEMGR_MAX_REQUEST);
+
+ framemgr = GET_SUBDEV_FRAMEMGR(subdev);
+ if (!framemgr) {
+ err("framemgr is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr_e_barrier_irq(framemgr, index);
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ if (frame) {
+ if (frame->index == index) {
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ } else {
+ err("buffer index is NOT matched(%d != %d)\n",
+ index, frame->index);
+ fimc_is_frame_print_all(framemgr);
+ ret = -EINVAL;
+ }
+ } else {
+ err("frame is empty from complete");
+ fimc_is_frame_print_all(framemgr);
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irq(framemgr, index);
+
+p_err:
+ return ret;
+}
+
+const struct fimc_is_queue_ops fimc_is_ischain_sub_ops = {
+ .start_streaming = fimc_is_subdev_start,
+ .stop_streaming = fimc_is_subdev_stop
+};
+
+void fimc_is_subdev_dis_start(struct fimc_is_device_ischain *device,
+ struct dis_param *param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+#ifdef ENABLE_VDIS
+ param->control.cmd = CONTROL_COMMAND_START;
+ param->control.bypass = CONTROL_BYPASS_DISABLE;
+ param->control.buffer_number = SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF;
+ param->control.buffer_address = device->imemory.dvaddr_shared + 300 * sizeof(u32);
+ device->is_region->shared[300] = device->imemory.dvaddr_dis;
+#else
+ merr("can't start hw vdis", device);
+ BUG();
+#endif
+
+ *lindex |= LOWBIT_OF(PARAM_DIS_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_DIS_CONTROL);
+ (*indexes)++;
+}
+
+void fimc_is_subdev_dis_stop(struct fimc_is_device_ischain *device,
+ struct dis_param *param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ param->control.cmd = CONTROL_COMMAND_STOP;
+ param->control.bypass = CONTROL_BYPASS_DISABLE;
+
+ *lindex |= LOWBIT_OF(PARAM_DIS_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_DIS_CONTROL);
+ (*indexes)++;
+}
+
+void fimc_is_subdev_dis_bypass(struct fimc_is_device_ischain *device,
+ struct dis_param *param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ if (device->pdata->subip_info->_dis.full_bypass)
+ param->control.cmd = CONTROL_COMMAND_STOP;
+ else
+ param->control.cmd = CONTROL_COMMAND_START;
+ /*
+ * special option
+ * bypass command should be 2 for enabling software dis
+ * software dis is not active because output format of software
+ * can't support multi-plane.
+ */
+ param->control.bypass = CONTROL_BYPASS_ENABLE;
+
+ *lindex |= LOWBIT_OF(PARAM_DIS_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_DIS_CONTROL);
+ (*indexes)++;
+}
+
+void fimc_is_subdev_dnr_start(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!ctl_param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ ctl_param->cmd = CONTROL_COMMAND_START;
+ ctl_param->bypass = CONTROL_BYPASS_DISABLE;
+ ctl_param->buffer_number = SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF;
+ ctl_param->buffer_address = device->imemory.dvaddr_shared + 350 * sizeof(u32);
+ device->is_region->shared[350] = device->imemory.dvaddr_3dnr;
+
+ *lindex |= LOWBIT_OF(PARAM_TDNR_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_TDNR_CONTROL);
+ (*indexes)++;
+}
+
+void fimc_is_subdev_dnr_stop(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!ctl_param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ ctl_param->cmd = CONTROL_COMMAND_STOP;
+ ctl_param->bypass = CONTROL_BYPASS_DISABLE;
+
+ *lindex |= LOWBIT_OF(PARAM_TDNR_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_TDNR_CONTROL);
+ (*indexes)++;
+}
+
+void fimc_is_subdev_dnr_bypass(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!ctl_param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ if (device->pdata->subip_info->_dnr.full_bypass)
+ ctl_param->cmd = CONTROL_COMMAND_STOP;
+ else
+ ctl_param->cmd = CONTROL_COMMAND_START;
+
+ ctl_param->bypass = CONTROL_BYPASS_ENABLE;
+
+ *lindex |= LOWBIT_OF(PARAM_TDNR_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_TDNR_CONTROL);
+ (*indexes)++;
+}
+
+void fimc_is_subdev_drc_start(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!ctl_param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ ctl_param->cmd = CONTROL_COMMAND_START;
+ ctl_param->bypass = CONTROL_BYPASS_DISABLE;
+ *lindex |= LOWBIT_OF(PARAM_DRC_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_DRC_CONTROL);
+ (*indexes)++;
+}
+
+void fimc_is_subdev_drc_bypass(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes)
+{
+ BUG_ON(!device);
+ BUG_ON(!ctl_param);
+ BUG_ON(!lindex);
+ BUG_ON(!hindex);
+ BUG_ON(!indexes);
+
+ if (device->pdata->subip_info->_drc.full_bypass)
+ ctl_param->cmd = CONTROL_COMMAND_STOP;
+ else
+ ctl_param->cmd = CONTROL_COMMAND_START;
+
+ ctl_param->bypass = CONTROL_BYPASS_ENABLE;
+
+ *lindex |= LOWBIT_OF(PARAM_DRC_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_DRC_CONTROL);
+ (*indexes)++;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_SUBDEV_H
+#define FIMC_IS_SUBDEV_H
+
+#include "fimc-is-param.h"
+#include "fimc-is-video.h"
+
+struct fimc_is_group;
+struct fimc_is_device_ischain;
+
+enum fimc_is_subdev_state {
+ FIMC_IS_SUBDEV_OPEN,
+ FIMC_IS_SUBDEV_START
+};
+
+struct fimc_is_subdev_path {
+ u32 width;
+ u32 height;
+};
+
+struct fimc_is_subdev {
+ u32 id;
+ u32 entry;
+ unsigned long state;
+ struct mutex mutex_state;
+
+ struct fimc_is_subdev_path input;
+ struct fimc_is_subdev_path output;
+
+ struct fimc_is_group *group;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_subdev *leader;
+};
+
+#define GET_LEADER_FRAMEMGR(leader) \
+ (((leader) && (leader)->vctx) ? (&(leader)->vctx->q_src->framemgr) : NULL)
+#define GET_SUBDEV_FRAMEMGR(subdev) \
+ (((subdev) && (subdev)->vctx) ? (&(subdev)->vctx->q_dst->framemgr) : NULL)
+
+#define GET_LEADER_QUEUE(leader) \
+ (((leader) && (leader)->vctx) ? ((leader)->vctx->q_src) : NULL)
+#define GET_SUBDEV_QUEUE(subdev) \
+ (((subdev) && (subdev)->vctx) ? ((subdev)->vctx->q_dst) : NULL)
+
+/*common subdev*/
+int fimc_is_subdev_open(struct fimc_is_subdev *subdev,
+ struct fimc_is_video_ctx *vctx,
+ const struct param_control *init_ctl);
+int fimc_is_subdev_close(struct fimc_is_subdev *subdev);
+int fimc_is_subdev_start(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+int fimc_is_subdev_stop(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+int fimc_is_subdev_s_format(struct fimc_is_subdev *subdev,
+ u32 width, u32 height);
+int fimc_is_subdev_buffer_queue(struct fimc_is_subdev *subdev,
+ u32 index);
+int fimc_is_subdev_buffer_finish(struct fimc_is_subdev *subdev,
+ u32 index);
+
+void fimc_is_subdev_dis_start(struct fimc_is_device_ischain *device,
+ struct dis_param *param, u32 *lindex, u32 *hindex, u32 *indexes);
+void fimc_is_subdev_dis_stop(struct fimc_is_device_ischain *device,
+ struct dis_param *param, u32 *lindex, u32 *hindex, u32 *indexes);
+void fimc_is_subdev_dis_bypass(struct fimc_is_device_ischain *device,
+ struct dis_param *param, u32 *lindex, u32 *hindex, u32 *indexes);
+void fimc_is_subdev_dnr_start(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes);
+void fimc_is_subdev_dnr_stop(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes);
+void fimc_is_subdev_dnr_bypass(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes);
+void fimc_is_subdev_drc_start(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes);
+void fimc_is_subdev_drc_bypass(struct fimc_is_device_ischain *device,
+ struct param_control *ctl_param, u32 *lindex, u32 *hindex, u32 *indexes);
+#endif
--- /dev/null
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+
+#include "fimc-is-time.h"
+
+static struct timeval itime1;
+
+void TIME_STR1(void)
+{
+ do_gettimeofday(&itime1);
+}
+
+void TIME_END1(void)
+{
+ u32 time;
+ struct timeval temp;
+
+ do_gettimeofday(&temp);
+ time = (temp.tv_sec - itime1.tv_sec)*1000000 +
+ (temp.tv_usec - itime1.tv_usec);
+
+ pr_info("TIME_MEASURE : %dus\n", time);
+}
+
+uint64_t fimc_is_get_timestamp(void)
+{
+ struct timespec curtime;
+
+ do_posix_clock_monotonic_gettime(&curtime);
+
+ return (uint64_t)curtime.tv_sec*1000000000 + curtime.tv_nsec;
+}
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+
+void measure_init(struct fimc_is_time *time,
+ u32 instance,
+ u32 group_id,
+ u32 report_period)
+{
+ time->instance = instance;
+ time->group_id = group_id;
+ time->report_period = report_period;
+ time->time_count = 0;
+ time->time1_min = 0;
+ time->time1_max = 0;
+ time->time1_tot = 0;
+ time->time2_min = 0;
+ time->time2_max = 0;
+ time->time2_tot = 0;
+ time->time3_min = 0;
+ time->time3_max = 0;
+ time->time3_tot = 0;
+ time->time4_cur = 0;
+ time->time4_old = 0;
+ time->time4_tot = 0;
+}
+
+void measure_period(struct fimc_is_time *time,
+ u32 report_period)
+{
+ time->report_period = report_period;
+}
+
+void measure_time(
+ struct fimc_is_time *time,
+ struct timeval *time_queued,
+ struct timeval *time_shot,
+ struct timeval *time_shotdone,
+ struct timeval *time_dequeued)
+{
+ u32 temp1, temp2, temp3;
+
+ temp1 = (time_shot->tv_sec - time_queued->tv_sec)*1000000 +
+ (time_shot->tv_usec - time_queued->tv_usec);
+ temp2 = (time_shotdone->tv_sec - time_shot->tv_sec)*1000000 +
+ (time_shotdone->tv_usec - time_shot->tv_usec);
+ temp3 = (time_dequeued->tv_sec - time_shotdone->tv_sec)*1000000 +
+ (time_dequeued->tv_usec - time_shotdone->tv_usec);
+
+ if (!time->time_count) {
+ time->time1_min = temp1;
+ time->time1_max = temp1;
+ time->time2_min = temp2;
+ time->time2_max = temp2;
+ time->time3_min = temp3;
+ time->time3_max = temp3;
+ } else {
+ if (time->time1_min > temp1)
+ time->time1_min = temp1;
+
+ if (time->time1_max < temp1)
+ time->time1_max = temp1;
+
+ if (time->time2_min > temp2)
+ time->time2_min = temp2;
+
+ if (time->time2_max < temp2)
+ time->time2_max = temp2;
+
+ if (time->time3_min > temp3)
+ time->time3_min = temp3;
+
+ if (time->time3_max < temp3)
+ time->time3_max = temp3;
+ }
+
+ time->time1_tot += temp1;
+ time->time2_tot += temp2;
+ time->time3_tot += temp3;
+
+ time->time4_cur = time_queued->tv_sec*1000000 + time_queued->tv_usec;
+ time->time4_tot += (time->time4_cur - time->time4_old);
+ time->time4_old = time->time4_cur;
+
+ time->time_count++;
+
+ if (time->time_count % time->report_period)
+ return;
+
+ pr_info("I%dG%d t1(%05d,%05d,%05d), t2(%05d,%05d,%05d), t3(%05d,%05d,%05d) : %d(%dfps)",
+ time->instance, time->group_id,
+ temp1, time->time1_max, time->time1_tot / time->time_count,
+ temp2, time->time2_max, time->time2_tot / time->time_count,
+ temp3, time->time3_max, time->time3_tot / time->time_count,
+ time->time4_tot / time->report_period,
+ (1000000 * time->report_period) / time->time4_tot);
+
+ time->time_count = 0;
+ time->time1_tot = 0;
+ time->time2_tot = 0;
+ time->time3_tot = 0;
+ time->time4_tot = 0;
+}
+
+#endif
+
+#ifdef INTERFACE_TIME
+void measure_init(struct fimc_is_interface_time *time, u32 cmd)
+{
+ time->cmd = cmd;
+ time->time_max = 0;
+ time->time_min = 0;
+ time->time_tot = 0;
+ time->time_cnt = 0;
+}
+
+void measure_time(struct fimc_is_interface_time *time,
+ u32 instance,
+ u32 group,
+ struct timeval *start,
+ struct timeval *end)
+{
+ u32 temp;
+
+ temp = (end->tv_sec - start->tv_sec)*1000000 + (end->tv_usec - start->tv_usec);
+
+ if (time->time_cnt) {
+ time->time_max = temp;
+ time->time_min = temp;
+ } else {
+ if (time->time_min > temp)
+ time->time_min = temp;
+
+ if (time->time_max < temp)
+ time->time_max = temp;
+ }
+
+ time->time_tot += temp;
+ time->time_cnt++;
+
+ pr_info("cmd[%d][%d](%d) : curr(%d), max(%d), avg(%d)\n",
+ instance, group, time->cmd, temp, time->time_max, time->time_tot / time->time_cnt);
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_TIME_H
+#define FIMC_IS_TIME_H
+
+/* #define MEASURE_TIME */
+/* #define INTERNAL_TIME */
+/* #define EXTERNAL_TIME */
+/* #define INTERFACE_TIME */
+
+#define INSTANCE_MASK 0x3
+
+#define TM_FLITE_STR 0
+#define TM_FLITE_END 1
+#define TM_SHOT 2
+#define TM_SHOT_D 3
+#define TM_META_D 4
+#define TM_MAX_INDEX 5
+
+struct fimc_is_time {
+ u32 instance;
+ u32 group_id;
+ u32 report_period;
+ u32 time_count;
+ u32 time1_min;
+ u32 time1_max;
+ u32 time1_tot;
+ u32 time2_min;
+ u32 time2_max;
+ u32 time2_tot;
+ u32 time3_min;
+ u32 time3_max;
+ u32 time3_tot;
+ u32 time4_cur;
+ u32 time4_old;
+ u32 time4_tot;
+};
+
+void TIME_STR1(void);
+void TIME_END1(void);
+uint64_t fimc_is_get_timestamp(void);
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+void measure_init(struct fimc_is_time *time,
+ u32 instance,
+ u32 group_id,
+ u32 report_period);
+void measure_period(struct fimc_is_time *time,
+ u32 report_period);
+void measure_time(
+ struct fimc_is_time *time,
+ struct timeval *time_queued,
+ struct timeval *time_shot,
+ struct timeval *time_shotdone,
+ struct timeval *time_dequeued);
+#endif
+#ifdef INTERFACE_TIME
+struct fimc_is_interface_time {
+ u32 cmd;
+ u32 time_tot;
+ u32 time_min;
+ u32 time_max;
+ u32 time_cnt;
+};
+
+void measure_init(struct fimc_is_interface_time *time, u32 cmd);
+void measure_time(struct fimc_is_interface_time *time,
+ u32 instance,
+ u32 group,
+ struct timeval *start,
+ struct timeval *end);
+#endif
+#endif
+
+#endif
--- /dev/null
+#ifndef FIMC_IS_TYPE_H
+#define FIMC_IS_TYPE_H
+
+#include <linux/v4l2-mediabus.h>
+
+#include <media/v4l2-device.h>
+
+enum fimc_is_device_type {
+ FIMC_IS_DEVICE_SENSOR,
+ FIMC_IS_DEVICE_ISCHAIN
+};
+
+struct fimc_is_window {
+ u32 o_width;
+ u32 o_height;
+ u32 width;
+ u32 height;
+ u32 offs_h;
+ u32 offs_v;
+ u32 otf_width;
+ u32 otf_height;
+};
+
+struct fimc_is_fmt {
+ char *name;
+ enum v4l2_mbus_pixelcode mbus_code;
+ u32 pixelformat;
+ u32 field;
+ u32 num_planes;
+};
+
+struct fimc_is_image {
+ u32 framerate;
+ struct fimc_is_window window;
+ struct fimc_is_fmt format;
+};
+
+#define TO_WORD_OFFSET(byte_offset) ((byte_offset) >> 2)
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/exynos_mc.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-metadata.h"
+
+const struct v4l2_file_operations fimc_is_3aa_video_fops;
+const struct v4l2_ioctl_ops fimc_is_3aa_video_ioctl_ops;
+const struct vb2_ops fimc_is_3aa_qops;
+
+int fimc_is_3a0_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_3a0;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_3AA_NAME(0),
+ FIMC_IS_VIDEO_3A0_NUM,
+ VFL_DIR_M2M,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_3aa_video_fops,
+ &fimc_is_3aa_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_3a1_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_3a1;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_3AA_NAME(1),
+ FIMC_IS_VIDEO_3A1_NUM,
+ VFL_DIR_M2M,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_3aa_video_fops,
+ &fimc_is_3aa_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Video File Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_3aa_video_open(struct file *file)
+{
+ int ret = 0;
+ u32 refcount;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_ischain *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+
+ if (video->id == FIMC_IS_VIDEO_3A0_NUM)
+ core = container_of(video, struct fimc_is_core, video_3a0);
+ else
+ core = container_of(video, struct fimc_is_core, video_3a1);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_3AA_GRP, FRAMEMGR_ID_3AAP);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[3A%d:V:%d] %s\n", GET_3AA_ID(video), vctx->instance, __func__);
+
+ refcount = atomic_read(&core->video_isp.refcount);
+ if (refcount > FIMC_IS_MAX_NODES || refcount < 1) {
+ err("invalid ischain refcount(%d)", refcount);
+ close_vctx(file, video, vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device = &core->ischain[refcount - 1];
+ info("[3A%d:V:%d] <-> [ISP:V:%d] \n", GET_3AA_ID(video),
+ vctx->instance, device->instance);
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_3AA_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_M2M,
+ &fimc_is_3aa_qops,
+ &fimc_is_ischain_3aa_ops,
+ &fimc_is_ischain_sub_ops);
+ if (ret) {
+ err("fimc_is_video_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_3aa_open(device, vctx);
+ if (ret) {
+ err("fimc_is_ischain_3aa_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_3aa_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_video *video = NULL;
+ struct fimc_is_device_ischain *device = NULL;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ err("video is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[3A%d:V:%d] %s\n", GET_3AA_ID(video), vctx->instance, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_ischain_3aa_close(device, vctx);
+ fimc_is_video_close(vctx);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret < 0)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_3aa_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+ if (ret)
+ merr("fimc_is_video_poll is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aa_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_3aa_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_3aa_video_open,
+ .release = fimc_is_3aa_video_close,
+ .poll = fimc_is_3aa_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_3aa_video_mmap,
+};
+
+/*
+ * =============================================================================
+ * Video Ioctl Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_3aa_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ /* Todo : add to query capability code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ /* Todo : add to enumerate format code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ /* Todo : add to get format code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ device = vctx->device;
+ leader = &device->group_3aa.leader;
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret) {
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(format->type)) {
+ queue = vctx->q_src;
+ fimc_is_ischain_3aa_s_format(device,
+ queue->framecfg.width,
+ queue->framecfg.height);
+ } else {
+ queue = vctx->q_dst;
+ fimc_is_subdev_s_format(leader,
+ queue->framecfg.width,
+ queue->framecfg.height);
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_3aa_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ /* Todo : add to crop capability code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ /* Todo : add to get crop control code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_group *group;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ ischain = vctx->device;
+ BUG_ON(!ischain);
+ group = &ischain->group_3aa;
+ BUG_ON(!group);
+ subdev = &group->leader;
+
+ if (V4L2_TYPE_IS_OUTPUT(crop->type))
+ fimc_is_ischain_3aa_s_format(ischain,
+ crop->c.width, crop->c.height);
+ else
+ fimc_is_subdev_s_format(subdev,
+ crop->c.width, crop->c.height);
+
+ return 0;
+}
+
+static int fimc_is_3aa_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+
+ mdbgv_3aa("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ device = vctx->device;
+ if (!device) {
+ merr("device is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(buf->type)) {
+ ret = fimc_is_ischain_3aa_reqbufs(device, buf->count);
+ if (ret) {
+ merr("3a0_reqbufs is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+ }
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_3aa_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aa_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ BUG_ON(!vctx);
+
+#ifdef DBG_STREAMING
+ mdbgv_3aa("%s(%02d:%d)\n", vctx, __func__, buf->type, buf->index);
+#endif
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_qbuf(type %d) is fail(%d)", vctx, buf->type, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aa_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ BUG_ON(!vctx);
+
+#ifdef DBG_STREAMING
+ mdbgv_3aa("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ /* HACK : this log is commented until timeout issue fixed */
+ /* if (ret)
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+ */
+ return ret;
+}
+
+static int fimc_is_3aa_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aa_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aa_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo: add enum input control code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ /* Todo: add to get input control code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+
+ mdbgv_3aa("%s(input : %08X)\n", vctx, __func__, input);
+
+ device = vctx->device;
+
+ ret = fimc_is_ischain_3aa_s_input(device, input);
+ if (ret) {
+ merr("fimc_is_ischain_3aa_s_input is fail", vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_init_wrap(device, input);
+ if (ret) {
+ merr("fimc_is_device_init(%d) is fail", vctx, input);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_3aa_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+
+ dbg_isp("%s\n", __func__);
+
+ device = vctx->device;
+ if (!device) {
+ merr("device is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_INTENT:
+ device->group_3aa.intent_ctl.aa.captureIntent = ctrl->value;
+ minfo("[3AA:V] s_ctrl intent(%d)\n", vctx, ctrl->value);
+ break;
+ case V4L2_CID_IS_FORCE_DONE:
+ set_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &device->group_3aa.state);
+ break;
+ case V4L2_CID_IS_MAP_BUFFER:
+ {
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attachment;
+ dma_addr_t dva;
+ struct v4l2_buffer *buf = NULL;
+ struct v4l2_plane *planes;
+ size_t size;
+ u32 write, plane, group_id;
+
+ size = sizeof(struct v4l2_buffer);
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf) {
+ merr("kmalloc is fail", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = copy_from_user(buf, (void __user *)ctrl->value, size);
+ if (ret) {
+ merr("copy_from_user is fail(%d)", vctx, ret);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+ merr("single plane is not supported", vctx);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (buf->index >= FRAMEMGR_MAX_REQUEST) {
+ merr("buffer index is invalid(%d)", vctx, buf->index);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (buf->length > VIDEO_MAX_PLANES) {
+ merr("planes[%d] is invalid", vctx, buf->length);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ queue = GET_QUEUE(vctx, buf->type);
+ if (queue->vbq->memory != V4L2_MEMORY_DMABUF) {
+ merr("memory type(%d) is not supported", vctx, queue->vbq->memory);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ size = sizeof(struct v4l2_plane) * buf->length;
+ planes = kmalloc(size, GFP_KERNEL);
+ if (IS_ERR(planes)) {
+ merr("kmalloc is fail(%p)", vctx, planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = copy_from_user(planes, (void __user *)buf->m.planes, size);
+ if (ret) {
+ merr("copy_from_user is fail(%d)", vctx, ret);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr = &queue->framemgr;
+ frame = &framemgr->frame[buf->index];
+ if (test_bit(FRAME_MAP_MEM, &frame->memory)) {
+ merr("this buffer(%d) is already mapped", vctx, buf->index);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* only last buffer need to map */
+ if (buf->length > 0) {
+ plane = buf->length - 1;
+ } else {
+ merr("buf size is abnormal(%d)", vctx, buf->length);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ dmabuf = dma_buf_get(planes[plane].m.fd);
+ if (IS_ERR(dmabuf)) {
+ merr("dma_buf_get is fail(%p)", vctx, dmabuf);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ attachment = dma_buf_attach(dmabuf, &device->pdev->dev);
+ if (IS_ERR(attachment)) {
+ merr("dma_buf_attach is fail(%p)", vctx, attachment);
+ kfree(planes);
+ kfree(buf);
+ dma_buf_put(dmabuf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ write = !V4L2_TYPE_IS_OUTPUT(buf->type);
+ dva = ion_iovmm_map(attachment, 0, dmabuf->size, write, plane);
+ if (IS_ERR_VALUE(dva)) {
+ merr("ion_iovmm_map is fail(%X)", vctx, dva);
+ kfree(planes);
+ kfree(buf);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ group_id = GROUP_ID(device->group_3aa.id);
+ ret = fimc_is_itf_map(device, group_id, dva, dmabuf->size);
+ if (ret) {
+ merr("fimc_is_itf_map is fail(%d)", vctx, ret);
+ kfree(planes);
+ kfree(buf);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+ goto p_err;
+ }
+
+ minfo("[3AA:V] buffer%d.plane%d mapping\n", vctx, buf->index, plane);
+ set_bit(FRAME_MAP_MEM, &frame->memory);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+ kfree(planes);
+ kfree(buf);
+ }
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_3aa_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ /* Todo: add to get control code */
+ return 0;
+}
+
+static int fimc_is_3aa_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ /* Todo: add to get extra control code */
+ return 0;
+}
+
+const struct v4l2_ioctl_ops fimc_is_3aa_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_3aa_video_querycap,
+
+ .vidioc_enum_fmt_vid_out_mplane = fimc_is_3aa_video_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_3aa_video_enum_fmt_mplane,
+
+ .vidioc_g_fmt_vid_out_mplane = fimc_is_3aa_video_get_format_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_3aa_video_get_format_mplane,
+
+ .vidioc_s_fmt_vid_out_mplane = fimc_is_3aa_video_set_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_3aa_video_set_format_mplane,
+
+ .vidioc_querybuf = fimc_is_3aa_video_querybuf,
+ .vidioc_reqbufs = fimc_is_3aa_video_reqbufs,
+
+ .vidioc_qbuf = fimc_is_3aa_video_qbuf,
+ .vidioc_dqbuf = fimc_is_3aa_video_dqbuf,
+
+ .vidioc_streamon = fimc_is_3aa_video_streamon,
+ .vidioc_streamoff = fimc_is_3aa_video_streamoff,
+
+ .vidioc_enum_input = fimc_is_3aa_video_enum_input,
+ .vidioc_g_input = fimc_is_3aa_video_g_input,
+ .vidioc_s_input = fimc_is_3aa_video_s_input,
+
+ .vidioc_s_ctrl = fimc_is_3aa_video_s_ctrl,
+ .vidioc_g_ctrl = fimc_is_3aa_video_g_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_3aa_video_g_ext_ctrl,
+
+ .vidioc_cropcap = fimc_is_3aa_video_cropcap,
+ .vidioc_g_crop = fimc_is_3aa_video_get_crop,
+ .vidioc_s_crop = fimc_is_3aa_video_set_crop,
+};
+
+static int fimc_is_3aa_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ queue = GET_VCTX_QUEUE(vctx, vbq);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aa_buffer_prepare(struct vb2_buffer *vb)
+{
+ /* Todo : add to prepare buffer */
+ return 0;
+}
+
+static inline void fimc_is_3aa_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_3aa_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_3aa_start_streaming(struct vb2_queue *vbq,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ device = vctx->device;
+
+ if (V4L2_TYPE_IS_OUTPUT(vbq->type)) {
+ queue = GET_SRC_QUEUE(vctx);
+ subdev = &device->group_3aa.leader;
+ } else {
+ queue = GET_DST_QUEUE(vctx);
+ subdev = &device->taap;
+ }
+
+ ret = fimc_is_queue_start_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_start_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aa_stop_streaming(struct vb2_queue *vbq)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+
+ mdbgv_3aa("%s\n", vctx, __func__);
+
+ device = vctx->device;
+
+ if (V4L2_TYPE_IS_OUTPUT(vbq->type)) {
+ queue = GET_SRC_QUEUE(vctx);
+ subdev = &device->group_3aa.leader;
+ } else {
+ queue = GET_DST_QUEUE(vctx);
+ subdev = &device->taap;
+ }
+
+ ret = fimc_is_queue_stop_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_stop_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static void fimc_is_3aa_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ u32 index;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ index = vb->v4l2_buf.index;
+
+#ifdef DBG_STREAMING
+ mdbgv_3aa("%s(%02d:%d)\n", vctx, __func__, vb->v4l2_buf.type, index);
+#endif
+
+ video = vctx->video;
+ device = vctx->device;
+ leader = &device->group_3aa.leader;
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->v4l2_buf.type)) {
+ queue = GET_SRC_QUEUE(vctx);
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_ischain_3aa_buffer_queue(device, queue, index);
+ if (ret) {
+ merr("fimc_is_ischain_3aa_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+ } else {
+ queue = GET_DST_QUEUE(vctx);
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_subdev_buffer_queue(leader, index);
+ if (ret) {
+ merr("fimc_is_subdev_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+ }
+}
+
+static int fimc_is_3aa_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ u32 index = vb->v4l2_buf.index;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *device = vctx->device;
+ struct fimc_is_group *group = &device->group_3aa;
+ struct fimc_is_subdev *subdev = &group->leader;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!device);
+
+#ifdef DBG_STREAMING
+ mdbgv_3aa("%s(%02d:%d)\n", vctx, __func__, vb->v4l2_buf.type, index);
+#endif
+
+ if (V4L2_TYPE_IS_OUTPUT(vb->v4l2_buf.type)) {
+ queue = vctx->q_src;
+ fimc_is_ischain_3aa_buffer_finish(device, index);
+ } else {
+ queue = vctx->q_dst;
+ fimc_is_subdev_buffer_finish(subdev, index);
+ }
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_3aa_qops = {
+ .queue_setup = fimc_is_3aa_queue_setup,
+ .buf_prepare = fimc_is_3aa_buffer_prepare,
+ .buf_queue = fimc_is_3aa_buffer_queue,
+ .buf_finish = fimc_is_3aa_buffer_finish,
+ .wait_prepare = fimc_is_3aa_wait_prepare,
+ .wait_finish = fimc_is_3aa_wait_finish,
+ .start_streaming = fimc_is_3aa_start_streaming,
+ .stop_streaming = fimc_is_3aa_stop_streaming,
+};
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+const struct v4l2_file_operations fimc_is_3aac_video_fops;
+const struct v4l2_ioctl_ops fimc_is_3aac_video_ioctl_ops;
+const struct vb2_ops fimc_is_3aac_qops;
+
+int fimc_is_3a0c_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_3a0c;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_3AAC_NAME(0),
+ FIMC_IS_VIDEO_3A0C_NUM,
+ VFL_DIR_RX,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_3aac_video_fops,
+ &fimc_is_3aac_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_3a1c_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_3a1c;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_3AAC_NAME(1),
+ FIMC_IS_VIDEO_3A1C_NUM,
+ VFL_DIR_RX,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_3aac_video_fops,
+ &fimc_is_3aac_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ info("[3AC1:V:1] %s(%d)\n", __func__, ret);
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Video File Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_3aac_video_open(struct file *file)
+{
+ int ret = 0;
+ u32 refcount;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_ischain *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+
+ if (video->id == FIMC_IS_VIDEO_3A0C_NUM)
+ core = container_of(video, struct fimc_is_core, video_3a0c);
+ else
+ core = container_of(video, struct fimc_is_core, video_3a1c);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_INVALID, FRAMEMGR_ID_3AAC);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[3A%dC:V:%d] %s\n", GET_3AAC_ID(video), vctx->instance, __func__);
+
+ refcount = atomic_read(&core->video_isp.refcount);
+ if (refcount > FIMC_IS_MAX_NODES || refcount < 1) {
+ err("invalid ischain refcount(%d)", refcount);
+ close_vctx(file, video, vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device = &core->ischain[refcount - 1];
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_3AAC_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_CAPTURE,
+ &fimc_is_3aac_qops,
+ NULL,
+ &fimc_is_ischain_sub_ops);
+ if (ret) {
+ err("fimc_is_video_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_subdev_open(&device->taac, vctx, NULL);
+ if (ret) {
+ err("fimc_is_subdev_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_3aac_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_video *video = NULL;
+ struct fimc_is_device_ischain *device = NULL;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ merr("video is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[3A%dC:V:%d] %s\n", GET_3AAC_ID(video), vctx->instance, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_subdev_close(&device->taac);
+ fimc_is_video_close(vctx);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret < 0)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_3aac_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+ if (ret)
+ merr("fimc_is_video_poll is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_3aac_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_3aac_video_open,
+ .release = fimc_is_3aac_video_close,
+ .poll = fimc_is_3aac_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_3aac_video_mmap,
+};
+
+/*
+ * =============================================================================
+ * Video Ioctl Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_3aac_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ /* Todo : add to query capability code */
+ return 0;
+}
+
+static int fimc_is_3aac_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3aac_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3aac_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+ BUG_ON(!format);
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ subdev = &device->taac;
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret) {
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_subdev_s_format(subdev, queue->framecfg.width, queue->framecfg.height);
+ if (ret) {
+ merr("fimc_is_ischain_3aac_s_format is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_3aac_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3aac_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3aac_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3aac_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3aac_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_3aac("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ device = vctx->device;
+ subdev = &device->taac;
+ leader = subdev->leader;
+
+ if (!leader) {
+ merr("leader is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ merr("leader still running, not applied", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(%d)", vctx, ret);
+
+ p_err:
+ return ret;
+}
+
+static int fimc_is_3aac_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_3aac("%s(index : %d)\n", vctx, __func__, buf->index);
+#endif
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+
+ if (ret)
+ merr("fimc_is_video_qbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_3aac("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo: add enum input control code */
+ return 0;
+}
+
+static int fimc_is_3aac_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3aac_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ return 0;
+}
+
+static int fimc_is_3aac_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_framemgr *framemgr;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ctrl);
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ framemgr = GET_DST_FRAMEMGR(vctx);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_G_COMPLETES:
+ ctrl->value = framemgr->frame_com_cnt;
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_3aac_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ return 0;
+}
+
+static int fimc_is_3aac_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ctrl);
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ switch (ctrl->id) {
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+const struct v4l2_ioctl_ops fimc_is_3aac_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_3aac_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_3aac_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_3aac_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_3aac_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_is_3aac_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_3aac_video_cropcap,
+ .vidioc_g_crop = fimc_is_3aac_video_get_crop,
+ .vidioc_s_crop = fimc_is_3aac_video_set_crop,
+ .vidioc_reqbufs = fimc_is_3aac_video_reqbufs,
+ .vidioc_querybuf = fimc_is_3aac_video_querybuf,
+ .vidioc_qbuf = fimc_is_3aac_video_qbuf,
+ .vidioc_dqbuf = fimc_is_3aac_video_dqbuf,
+ .vidioc_streamon = fimc_is_3aac_video_streamon,
+ .vidioc_streamoff = fimc_is_3aac_video_streamoff,
+ .vidioc_enum_input = fimc_is_3aac_video_enum_input,
+ .vidioc_g_input = fimc_is_3aac_video_g_input,
+ .vidioc_s_input = fimc_is_3aac_video_s_input,
+ .vidioc_g_ctrl = fimc_is_3aac_video_g_ctrl,
+ .vidioc_s_ctrl = fimc_is_3aac_video_s_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_3aac_video_g_ext_ctrl,
+};
+
+static int fimc_is_3aac_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ queue = GET_VCTX_QUEUE(vctx, vbq);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_buffer_prepare(struct vb2_buffer *vb)
+{
+ return 0;
+}
+
+static inline void fimc_is_3aac_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_3aac_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_3aac_start_streaming(struct vb2_queue *vbq,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ queue = GET_VCTX_QUEUE(vctx, vbq);
+ device = vctx->device;
+ subdev = &device->taac;
+
+ ret = fimc_is_queue_start_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_start_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_3aac_stop_streaming(struct vb2_queue *vbq)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+
+ mdbgv_3aac("%s\n", vctx, __func__);
+
+ queue = GET_VCTX_QUEUE(vctx, vbq);
+ device = vctx->device;
+ subdev = &device->taac;
+
+ ret = fimc_is_queue_stop_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_stop_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static void fimc_is_3aac_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_video *video;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+#ifdef DBG_STREAMING
+ mdbgv_3aac("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index);
+#endif
+
+ queue = GET_DST_QUEUE(vctx);
+ video = vctx->video;
+ device = vctx->device;
+ subdev = &device->taac;
+
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_subdev_buffer_queue(subdev, vb->v4l2_buf.index);
+ if (ret) {
+ merr("fimc_is_subdev_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+}
+
+static int fimc_is_3aac_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *ischain = vctx->device;
+ struct fimc_is_subdev *subdev = &ischain->taac;
+
+#ifdef DBG_STREAMING
+ mdbgv_3aac("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_subdev_buffer_finish(subdev, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_3aac_qops = {
+ .queue_setup = fimc_is_3aac_queue_setup,
+ .buf_prepare = fimc_is_3aac_buffer_prepare,
+ .buf_queue = fimc_is_3aac_buffer_queue,
+ .buf_finish = fimc_is_3aac_buffer_finish,
+ .wait_prepare = fimc_is_3aac_wait_prepare,
+ .wait_finish = fimc_is_3aac_wait_finish,
+ .start_streaming = fimc_is_3aac_start_streaming,
+ .stop_streaming = fimc_is_3aac_stop_streaming,
+};
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include "fimc-is-device-companion.h"
+#include "fimc-is-video.h"
+
+const struct v4l2_file_operations fimc_is_comp_video_fops;
+const struct v4l2_ioctl_ops fimc_is_comp_video_ioctl_ops;
+const struct vb2_ops fimc_is_comp_qops;
+
+int fimc_is_comp_video_probe(void *data)
+{
+ int ret = 0;
+ char name[255];
+ u32 number;
+ struct fimc_is_device_companion *device;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ device = (struct fimc_is_device_companion *)data;
+ video = &device->video;
+ snprintf(name, sizeof(name), "%s%d", FIMC_IS_VIDEO_SENSOR_NAME, 9);
+ number = FIMC_IS_VIDEO_SS0_NUM + 9;
+
+ if (!device->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ name,
+ number,
+ VFL_DIR_RX,
+ &device->mem,
+ &device->v4l2_dev,
+ &video->lock,
+ &fimc_is_comp_video_fops,
+ &fimc_is_comp_video_ioctl_ops);
+ if (ret)
+ dev_err(&device->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ info("[CP%d:V:X] %s(%d)\n", number, __func__, ret);
+ return ret;
+}
+
+#ifdef CONFIG_OIS_USE
+extern int fimc_is_ois_sine_mode(struct fimc_is_core *core, int mode);
+#endif
+
+static int fimc_is_comp_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video *video;
+ struct fimc_is_device_companion *device;
+
+ dbg_isp("%s\n", __func__);
+
+ video = video_drvdata(file);
+ device = container_of(video, struct fimc_is_device_companion, video);
+
+ if (!device->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ switch (ctrl->id) {
+#ifdef CONFIG_OIS_USE
+ case V4L2_CID_CAMERA_OIS_SINE_MODE:
+ if (fimc_is_ois_sine_mode(device->private_data, ctrl->value)) {
+ err("failed to set ois sine mode : %d\n - %d",
+ ctrl->value, ret);
+ ret = -EINVAL;
+ }
+ break;
+#endif
+
+ default:
+ info("unsupported ioctl(%d, sine id = %d)\n", ctrl->id, V4L2_CID_CAMERA_OIS_SINE_MODE);
+ ret = -EINVAL;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Video File Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_comp_video_open(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_companion *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+ device = container_of(video, struct fimc_is_device_companion, video);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_INVALID, FRAMEMGR_ID_INVALID);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[CP%d:V:%d] %s\n", video->id, vctx->instance, __func__);
+
+ ret = fimc_is_companion_open(device);
+ if (ret) {
+ merr("fimc_is_comp_open is fail(%d)", vctx, ret);
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_comp_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video = NULL;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_device_companion *device = NULL;
+
+ BUG_ON(!file);
+
+ video = video_drvdata(file);
+ device = container_of(video, struct fimc_is_device_companion, video);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[CP:V:%d] %s\n", vctx->instance, __func__);
+
+ ret = fimc_is_companion_close(device);
+ if (ret)
+ err("fimc_is_companion_close is fail(%d)", ret);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_comp_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_comp_video_open,
+ .release = fimc_is_comp_video_close,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+/*
+ * =============================================================================
+ * Video Ioctl Opertation
+ * =============================================================================
+ */
+
+const struct v4l2_ioctl_ops fimc_is_comp_video_ioctl_ops = {
+ .vidioc_s_ctrl = fimc_is_comp_video_s_ctrl,
+};
+
+const struct vb2_ops fimc_is_comp_qops = {
+};
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/pm_qos.h>
+#include <linux/bug.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-metadata.h"
+
+extern struct fimc_is_from_info *sysfs_finfo;
+extern struct fimc_is_from_info *sysfs_pinfo;
+extern bool is_dumped_fw_loading_needed;
+
+const struct v4l2_file_operations fimc_is_isp_video_fops;
+const struct v4l2_ioctl_ops fimc_is_isp_video_ioctl_ops;
+const struct vb2_ops fimc_is_isp_qops;
+
+int fimc_is_isp_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_isp;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_ISP_NAME,
+ FIMC_IS_VIDEO_ISP_NUM,
+ VFL_DIR_M2M,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_isp_video_fops,
+ &fimc_is_isp_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Video File Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_isp_video_open(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_ischain *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+ core = container_of(video, struct fimc_is_core, video_isp);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_ISP_GRP, FRAMEMGR_ID_INVALID);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[ISP:V:%d] %s\n", vctx->instance, __func__);
+
+ device = &core->ischain[vctx->instance];
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_ISP_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_OUTPUT,
+ &fimc_is_isp_qops,
+ &fimc_is_ischain_isp_ops,
+ NULL);
+ if (ret) {
+ err("fimc_is_video_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_open(device, vctx, &core->minfo);
+ if (ret) {
+ err("fimc_is_ischain_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_isp_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video = NULL;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_device_ischain *device = NULL;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ err("video is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[ISP:V:%d] %s\n", video->id, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (pm_qos_request_active(&device->user_qos))
+ pm_qos_remove_request(&device->user_qos);
+
+ fimc_is_ischain_close(device, vctx);
+ fimc_is_video_close(vctx);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret < 0)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_isp_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+ if (ret)
+ merr("fimc_is_video_poll is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_isp_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_isp_video_open,
+ .release = fimc_is_isp_video_close,
+ .poll = fimc_is_isp_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_isp_video_mmap,
+};
+
+/*
+ * =============================================================================
+ * Video Ioctl Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_isp_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg_isp("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_isp_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ queue = GET_VCTX_QUEUE(vctx, format);
+ device = vctx->device;
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret)
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+
+ fimc_is_ischain_isp_s_format(device,
+ queue->framecfg.width,
+ queue->framecfg.height);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *ischain;
+
+ BUG_ON(!vctx);
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ ischain = vctx->device;
+ BUG_ON(!ischain);
+
+ fimc_is_ischain_isp_s_format(ischain,
+ crop->c.width, crop->c.height);
+
+ return 0;
+}
+
+static int fimc_is_isp_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+
+ mdbgv_isp("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ device = vctx->device;
+ if (!device) {
+ merr("device is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_isp_reqbufs(device, buf->count);
+ if (ret) {
+ merr("isp_reqbufs is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(error %d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_isp_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+
+#ifdef DBG_STREAMING
+ mdbgv_isp("%s(index : %d)\n", vctx, __func__, buf->index);
+#endif
+
+ queue = GET_VCTX_QUEUE(vctx, buf);
+
+ if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ merr("stream off state, can NOT qbuf", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_qbuf is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_isp_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_isp("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo : add to enum input control code */
+ return 0;
+}
+
+static int fimc_is_isp_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ /* Todo : add to get input control code */
+ return 0;
+}
+
+static int fimc_is_isp_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+
+ mdbgv_isp("%s(input : %08X)\n", vctx, __func__, input);
+
+ device = vctx->device;
+
+ ret = fimc_is_ischain_isp_s_input(device, input);
+ if (ret) {
+ merr("fimc_is_ischain_isp_s_input is fail", vctx);
+ goto p_err;
+ }
+
+ /* if there's only one group of isp, defines group id to 3a0 connected */
+ if (GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a0)
+ || GET_FIMC_IS_NUM_OF_SUBIP2(device, 3a1))
+ goto p_err;
+
+ ret = fimc_is_ischain_init_wrap(device, input);
+ if (ret) {
+ merr("fimc_is_device_init(%d) is fail", vctx, input);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_isp_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ int i2c_clk;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_core *core;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+ BUG_ON(!vctx->video);
+
+ dbg_isp("%s\n", __func__);
+
+ device = vctx->device;
+ video = vctx->video;
+ core = container_of(video, struct fimc_is_core, video_isp);
+
+ if (core->resourcemgr.dvfs_ctrl.cur_int_qos == DVFS_L0)
+ i2c_clk = I2C_L0;
+ else
+ i2c_clk = I2C_L1;
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_DEBUG_DUMP:
+ info("Print fimc-is info dump by HAL");
+ if (device != NULL) {
+ fimc_is_hw_logdump(device->interface);
+ fimc_is_hw_regdump(device->interface);
+ CALL_POPS(device, print_clk, device->pdev);
+ }
+ if (ctrl->value) {
+ err("BUG_ON from HAL");
+ BUG();
+ }
+ break;
+ case V4L2_CID_IS_DEBUG_SYNC_LOG:
+ fimc_is_logsync(device->interface, ctrl->value, IS_MSG_TEST_SYNC_LOG);
+ break;
+ case V4L2_CID_IS_G_CAPABILITY:
+ ret = fimc_is_ischain_g_capability(device, ctrl->value);
+ dbg_isp("V4L2_CID_IS_G_CAPABILITY : %X\n", ctrl->value);
+ break;
+ case V4L2_CID_IS_FORCE_DONE:
+ set_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &device->group_isp.state);
+ break;
+ case V4L2_CID_IS_DVFS_LOCK:
+ ret = fimc_is_itf_i2c_lock(device, I2C_L0, true);
+ if (ret) {
+ err("fimc_is_itf_i2_clock fail\n");
+ break;
+ }
+ pm_qos_add_request(&device->user_qos, PM_QOS_DEVICE_THROUGHPUT,
+ ctrl->value);
+ ret = fimc_is_itf_i2c_lock(device, I2C_L0, false);
+ if (ret) {
+ err("fimc_is_itf_i2c_unlock fail\n");
+ break;
+ }
+ dbg_isp("V4L2_CID_IS_DVFS_LOCK : %d\n", ctrl->value);
+ break;
+ case V4L2_CID_IS_DVFS_UNLOCK:
+ ret = fimc_is_itf_i2c_lock(device, i2c_clk, true);
+ if (ret) {
+ err("fimc_is_itf_i2_clock fail\n");
+ break;
+ }
+ pm_qos_remove_request(&device->user_qos);
+ ret = fimc_is_itf_i2c_lock(device, i2c_clk, false);
+ if (ret) {
+ err("fimc_is_itf_i2c_unlock fail\n");
+ break;
+ }
+ dbg_isp("V4L2_CID_IS_DVFS_UNLOCK : %d I2C(%d)\n", ctrl->value, i2c_clk);
+ break;
+ case V4L2_CID_IS_SET_SETFILE:
+ if (test_bit(FIMC_IS_SUBDEV_START, &device->group_isp.leader.state)) {
+ err("Setting setfile is only avaiable before starting device!! (0x%08x)",
+ ctrl->value);
+ ret = -EINVAL;
+ } else {
+ device->setfile = ctrl->value;
+ minfo("[ISP:V] setfile: 0x%08X\n", vctx, ctrl->value);
+ }
+ break;
+ case V4L2_CID_IS_COLOR_RANGE:
+ if (test_bit(FIMC_IS_SUBDEV_START, &device->group_isp.leader.state)) {
+ err("failed to change color range: device started already (0x%08x)",
+ ctrl->value);
+ ret = -EINVAL;
+ } else {
+ device->color_range &= ~FIMC_IS_ISP_CRANGE_MASK;
+
+ if (ctrl->value)
+ device->color_range |=
+ (FIMC_IS_CRANGE_LIMITED << FIMC_IS_ISP_CRANGE_SHIFT);
+ }
+ break;
+ case V4L2_CID_IS_MAP_BUFFER:
+ {
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attachment;
+ dma_addr_t dva;
+ struct v4l2_buffer *buf = NULL;
+ struct v4l2_plane *planes;
+ size_t size;
+ u32 write, plane, group_id;
+
+ size = sizeof(struct v4l2_buffer);
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf) {
+ merr("kmalloc is fail", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = copy_from_user(buf, (void __user *)ctrl->value, size);
+ if (ret) {
+ merr("copy_from_user is fail(%d)", vctx, ret);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+ merr("single plane is not supported", vctx);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (buf->index >= FRAMEMGR_MAX_REQUEST) {
+ merr("buffer index is invalid(%d)", vctx, buf->index);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (buf->length > VIDEO_MAX_PLANES) {
+ merr("planes[%d] is invalid", vctx, buf->length);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ queue = GET_QUEUE(vctx, buf->type);
+ if (queue->vbq->memory != V4L2_MEMORY_DMABUF) {
+ merr("memory type(%d) is not supported", vctx, queue->vbq->memory);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ size = sizeof(struct v4l2_plane) * buf->length;
+ planes = kmalloc(size, GFP_KERNEL);
+ if (IS_ERR(planes)) {
+ merr("kmalloc is fail(%p)", vctx, planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = copy_from_user(planes, (void __user *)buf->m.planes, size);
+ if (ret) {
+ merr("copy_from_user is fail(%d)", vctx, ret);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr = &queue->framemgr;
+ frame = &framemgr->frame[buf->index];
+ if (test_bit(FRAME_MAP_MEM, &frame->memory)) {
+ merr("this buffer(%d) is already mapped", vctx, buf->index);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /* only last buffer need to map */
+ if (buf->length > 0) {
+ plane = buf->length - 1;
+ } else {
+ merr("buf size is abnormal(%d)", vctx, buf->length);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ dmabuf = dma_buf_get(planes[plane].m.fd);
+ if (IS_ERR(dmabuf)) {
+ merr("dma_buf_get is fail(%p)", vctx, dmabuf);
+ kfree(planes);
+ kfree(buf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ attachment = dma_buf_attach(dmabuf, &device->pdev->dev);
+ if (IS_ERR(attachment)) {
+ merr("dma_buf_attach is fail(%p)", vctx, attachment);
+ kfree(planes);
+ kfree(buf);
+ dma_buf_put(dmabuf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ write = !V4L2_TYPE_IS_OUTPUT(buf->type);
+ dva = ion_iovmm_map(attachment, 0, dmabuf->size, write, plane);
+ if (IS_ERR_VALUE(dva)) {
+ merr("ion_iovmm_map is fail(%X)", vctx, dva);
+ kfree(planes);
+ kfree(buf);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ group_id = GROUP_ID(device->group_isp.id);
+ ret = fimc_is_itf_map(device, group_id, dva, dmabuf->size);
+ if (ret) {
+ merr("fimc_is_itf_map is fail(%d)", vctx, ret);
+ kfree(planes);
+ kfree(buf);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+ goto p_err;
+ }
+
+ minfo("[ISP:V] buffer%d.plane%d mapping\n", vctx, buf->index, plane);
+ set_bit(FRAME_MAP_MEM, &frame->memory);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+ kfree(planes);
+ kfree(buf);
+ }
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_isp_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *ischain = vctx->device;
+
+ dbg_isp("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_BDS_WIDTH:
+ ctrl->value = ischain->chain0_width;
+ break;
+ case V4L2_CID_IS_BDS_HEIGHT:
+ ctrl->value = ischain->chain0_height;
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_isp_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ int ret = 0;
+ struct v4l2_ext_control *ctrl;
+
+ dbg_isp("%s\n", __func__);
+
+
+ ctrl = ctrls->controls;
+
+ switch (ctrl->id) {
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+const struct v4l2_ioctl_ops fimc_is_isp_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_isp_video_querycap,
+ .vidioc_enum_fmt_vid_out_mplane = fimc_is_isp_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_out_mplane = fimc_is_isp_video_get_format_mplane,
+ .vidioc_s_fmt_vid_out_mplane = fimc_is_isp_video_set_format_mplane,
+ .vidioc_cropcap = fimc_is_isp_video_cropcap,
+ .vidioc_g_crop = fimc_is_isp_video_get_crop,
+ .vidioc_s_crop = fimc_is_isp_video_set_crop,
+ .vidioc_reqbufs = fimc_is_isp_video_reqbufs,
+ .vidioc_querybuf = fimc_is_isp_video_querybuf,
+ .vidioc_qbuf = fimc_is_isp_video_qbuf,
+ .vidioc_dqbuf = fimc_is_isp_video_dqbuf,
+ .vidioc_streamon = fimc_is_isp_video_streamon,
+ .vidioc_streamoff = fimc_is_isp_video_streamoff,
+ .vidioc_enum_input = fimc_is_isp_video_enum_input,
+ .vidioc_g_input = fimc_is_isp_video_g_input,
+ .vidioc_s_input = fimc_is_isp_video_s_input,
+ .vidioc_s_ctrl = fimc_is_isp_video_s_ctrl,
+ .vidioc_g_ctrl = fimc_is_isp_video_g_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_isp_video_g_ext_ctrl,
+};
+
+static int fimc_is_isp_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ queue = GET_SRC_QUEUE(vctx);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_buffer_prepare(struct vb2_buffer *vb)
+{
+ /*dbg_isp("%s\n", __func__);*/
+ return 0;
+}
+
+static inline void fimc_is_isp_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_isp_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_isp_start_streaming(struct vb2_queue *vbq,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ queue = GET_SRC_QUEUE(vctx);
+ device = vctx->device;
+ leader = &device->group_isp.leader;
+
+ ret = fimc_is_queue_start_streaming(queue, device, leader, vctx);
+ if (ret)
+ merr("fimc_is_queue_start_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ queue = GET_SRC_QUEUE(vctx);
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+ leader = &device->group_isp.leader;
+
+ ret = fimc_is_queue_stop_streaming(queue, device, leader, vctx);
+ if (ret)
+ merr("fimc_is_queue_stop_streaming is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static void fimc_is_isp_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ u32 index;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_video *video;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+ index = vb->v4l2_buf.index;
+
+#ifdef DBG_STREAMING
+ mdbgv_isp("%s(%d)\n", vctx, __func__, index);
+#endif
+
+ queue = GET_SRC_QUEUE(vctx);
+ video = vctx->video;
+ device = vctx->device;
+
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_ischain_isp_buffer_queue(device, queue, index);
+ if (ret) {
+ merr("fimc_is_ischain_isp_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+}
+
+static int fimc_is_isp_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *device = vctx->device;
+
+#ifdef DBG_STREAMING
+ mdbgv_isp("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_ischain_isp_buffer_finish(device, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_isp_qops = {
+ .queue_setup = fimc_is_isp_queue_setup,
+ .buf_prepare = fimc_is_isp_buffer_prepare,
+ .buf_queue = fimc_is_isp_buffer_queue,
+ .buf_finish = fimc_is_isp_buffer_finish,
+ .wait_prepare = fimc_is_isp_wait_prepare,
+ .wait_finish = fimc_is_isp_wait_finish,
+ .start_streaming = fimc_is_isp_start_streaming,
+ .stop_streaming = fimc_is_isp_stop_streaming,
+};
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+const struct v4l2_file_operations fimc_is_scc_video_fops;
+const struct v4l2_ioctl_ops fimc_is_scc_video_ioctl_ops;
+const struct vb2_ops fimc_is_scc_qops;
+
+int fimc_is_scc_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_scc;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_SCC_NAME,
+ FIMC_IS_VIDEO_SCC_NUM,
+ VFL_DIR_RX,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_scc_video_fops,
+ &fimc_is_scc_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Video File Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_scc_video_open(struct file *file)
+{
+ int ret = 0;
+ u32 refcount;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_ischain *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+ core = container_of(video, struct fimc_is_core, video_scc);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_INVALID, FRAMEMGR_ID_SCC);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[SCC:V:%d] %s\n", vctx->instance, __func__);
+
+ refcount = atomic_read(&core->video_isp.refcount);
+ if (refcount > FIMC_IS_MAX_NODES || refcount < 1) {
+ err("invalid ischain refcount(%d)", refcount);
+ close_vctx(file, video, vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device = &core->ischain[refcount - 1];
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_SCC_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_CAPTURE,
+ &fimc_is_scc_qops,
+ NULL,
+ &fimc_is_ischain_sub_ops);
+ if (ret) {
+ err("fimc_is_video_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_subdev_open(&device->scc, vctx, NULL);
+ if (ret) {
+ err("fimc_is_subdev_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_scc_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video = NULL;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_device_ischain *device = NULL;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ merr("video is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[SCC:V:%d] %s\n", vctx->instance, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_subdev_close(&device->scc);
+ fimc_is_video_close(vctx);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret < 0)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_scc_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+
+ return ret;
+}
+
+static int fimc_is_scc_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_scc_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_scc_video_open,
+ .release = fimc_is_scc_video_close,
+ .poll = fimc_is_scc_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_scc_video_mmap,
+};
+
+/*
+ * =============================================================================
+ * Video Ioctl Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_scc_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("(devname : %s)\n", cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_scc_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scc_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scc_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_scc("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret)
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scc_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scc_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scc_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scc_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scc_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_scc("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ device = vctx->device;
+ subdev = &device->scc;
+ leader = subdev->leader;
+
+ if (!leader) {
+ merr("leader is NULL ptr", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ merr("leader still running, not applied", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_scc_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdo("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scc_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_scc("%s(index : %d)\n", vctx, __func__, buf->index);
+#endif
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_qbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scc_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_scc("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scc_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_scc("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scc_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_scc("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scc_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo : add to enum input control code */
+ return 0;
+}
+
+static int fimc_is_scc_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scc_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ return 0;
+}
+
+static int fimc_is_scc_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_framemgr *framemgr = GET_DST_FRAMEMGR(vctx);
+
+ dbg_scc("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_G_COMPLETES:
+ ctrl->value = framemgr->frame_com_cnt;
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_scc_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ctrl);
+
+ mdbgv_scc("%s\n", vctx, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ merr("device is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr = GET_DST_FRAMEMGR(vctx);
+ frame = NULL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_FORCE_DONE:
+ if (framemgr->frame_pro_cnt) {
+ err("force done can be performed(process count %d)",
+ framemgr->frame_pro_cnt);
+ ret = -EINVAL;
+ } else if (!framemgr->frame_req_cnt) {
+ err("force done can be performed(request count %d)",
+ framemgr->frame_req_cnt);
+ ret = -EINVAL;
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ buffer_done(vctx, frame->index);
+ } else {
+ err("frame is NULL");
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+ break;
+ case V4L2_CID_IS_COLOR_RANGE:
+ if (test_bit(FIMC_IS_SUBDEV_START, &device->group_isp.leader.state)) {
+ err("failed to change color range: device started already (0x%08x)",
+ ctrl->value);
+ ret = -EINVAL;
+ } else {
+ device->color_range &= ~FIMC_IS_SCC_CRANGE_MASK;
+
+ if (ctrl->value)
+ device->color_range |=
+ (FIMC_IS_CRANGE_LIMITED << FIMC_IS_SCC_CRANGE_SHIFT);
+ }
+ break;
+ default:
+ merr("unsupported ioctl(%d)\n", vctx, ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+const struct v4l2_ioctl_ops fimc_is_scc_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_scc_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_scc_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_scc_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_scc_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_is_scc_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_scc_video_cropcap,
+ .vidioc_g_crop = fimc_is_scc_video_get_crop,
+ .vidioc_s_crop = fimc_is_scc_video_set_crop,
+ .vidioc_reqbufs = fimc_is_scc_video_reqbufs,
+ .vidioc_querybuf = fimc_is_scc_video_querybuf,
+ .vidioc_qbuf = fimc_is_scc_video_qbuf,
+ .vidioc_dqbuf = fimc_is_scc_video_dqbuf,
+ .vidioc_streamon = fimc_is_scc_video_streamon,
+ .vidioc_streamoff = fimc_is_scc_video_streamoff,
+ .vidioc_enum_input = fimc_is_scc_video_enum_input,
+ .vidioc_g_input = fimc_is_scc_video_g_input,
+ .vidioc_s_input = fimc_is_scc_video_s_input,
+ .vidioc_g_ctrl = fimc_is_scc_video_g_ctrl,
+ .vidioc_s_ctrl = fimc_is_scc_video_s_ctrl,
+};
+
+static int fimc_is_scc_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_scc("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+static int fimc_is_scc_buffer_prepare(struct vb2_buffer *vb)
+{
+ return 0;
+}
+
+static inline void fimc_is_scc_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_scc_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_scc_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+ mdbgv_scc("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ subdev = &device->scc;
+
+ ret = fimc_is_queue_start_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_start_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scc_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ mdbgv_scc("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+ subdev = &device->scc;
+
+ ret = fimc_is_queue_stop_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_stop_streaming is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static void fimc_is_scc_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_queue *queue = vctx->q_dst;
+ struct fimc_is_video *video = vctx->video;
+ struct fimc_is_device_ischain *ischain = vctx->device;
+ struct fimc_is_subdev *scc = &ischain->scc;
+
+#ifdef DBG_STREAMING
+ dbg_scc("%s\n", __func__);
+#endif
+
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_subdev_buffer_queue(scc, vb->v4l2_buf.index);
+ if (ret) {
+ merr("fimc_is_subdev_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+}
+
+static int fimc_is_scc_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+#ifdef DBG_STREAMING
+ mdbgv_scc("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index);
+#endif
+
+ device = vctx->device;
+ subdev = &device->scc;
+
+ ret = fimc_is_subdev_buffer_finish(subdev, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_scc_qops = {
+ .queue_setup = fimc_is_scc_queue_setup,
+ .buf_prepare = fimc_is_scc_buffer_prepare,
+ .buf_queue = fimc_is_scc_buffer_queue,
+ .buf_finish = fimc_is_scc_buffer_finish,
+ .wait_prepare = fimc_is_scc_wait_prepare,
+ .wait_finish = fimc_is_scc_wait_finish,
+ .start_streaming = fimc_is_scc_start_streaming,
+ .stop_streaming = fimc_is_scc_stop_streaming,
+};
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+const struct v4l2_file_operations fimc_is_scp_video_fops;
+const struct v4l2_ioctl_ops fimc_is_scp_video_ioctl_ops;
+const struct vb2_ops fimc_is_scp_qops;
+
+int fimc_is_scp_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_scp;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_SCP_NAME,
+ FIMC_IS_VIDEO_SCP_NUM,
+ VFL_DIR_RX,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_scp_video_fops,
+ &fimc_is_scp_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Video File Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_scp_video_open(struct file *file)
+{
+ int ret = 0;
+ u32 refcount;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_ischain *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+ core = container_of(video, struct fimc_is_core, video_scp);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_INVALID, FRAMEMGR_ID_SCP);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[SCP:V:%d] %s\n", vctx->instance, __func__);
+
+ refcount = atomic_read(&core->video_isp.refcount);
+ if (refcount > FIMC_IS_MAX_NODES || refcount < 1) {
+ err("invalid ischain refcount(%d)", refcount);
+ close_vctx(file, video, vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device = &core->ischain[refcount - 1];
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_SCP_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_CAPTURE,
+ &fimc_is_scp_qops,
+ NULL,
+ &fimc_is_ischain_sub_ops);
+ if (ret) {
+ err("fimc_is_video_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_subdev_open(&device->scp, vctx, NULL);
+ if (ret) {
+ err("fimc_is_subdev_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_scp_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video = NULL;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_device_ischain *device = NULL;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ merr("video is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[SCP:V:%d] %s\n", vctx->instance, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_subdev_close(&device->scp);
+ fimc_is_video_close(vctx);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret < 0)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_scp_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+
+ return ret;
+}
+
+static int fimc_is_scp_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_scp_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_scp_video_open,
+ .release = fimc_is_scp_video_close,
+ .poll = fimc_is_scp_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_scp_video_mmap,
+};
+
+/*
+ * =============================================================================
+ * Video Ioctl Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_scp_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *core = video_drvdata(file);
+
+ strncpy(cap->driver, core->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, core->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_scp_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scp_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scp_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *ischain;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->device);
+ BUG_ON(!format);
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ ischain = vctx->device;
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret) {
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_scp_s_format(ischain,
+ queue->framecfg.format.pixelformat,
+ queue->framecfg.width,
+ queue->framecfg.height);
+ if (ret)
+ merr("fimc_is_ischain_scp_s_format is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_scp_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scp_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scp_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scp_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ if (!device) {
+ merr("device is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_scp_s_format(device,
+ queue->framecfg.format.pixelformat,
+ crop->c.width,
+ crop->c.height);
+ if (ret)
+ merr("fimc_is_ischain_scp_s_format is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_scp_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_scp("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ device = vctx->device;
+ subdev = &device->scp;
+ leader = subdev->leader;
+
+ if (!leader) {
+ merr("leader is NULL ptr", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ merr("leader still running, not applied", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_scp_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scp_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_scp("%s(index : %d)\n", vctx, __func__, buf->index);
+#endif
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_qbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scp_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_scp("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scp_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scp_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scp_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo : add to enum input control code */
+ return 0;
+}
+
+static int fimc_is_scp_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scp_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ return 0;
+}
+
+static int fimc_is_scp_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_framemgr *framemgr;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ctrl);
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ framemgr = GET_DST_FRAMEMGR(vctx);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_G_COMPLETES:
+ ctrl->value = framemgr->frame_com_cnt;
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_scp_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ return 0;
+}
+
+static int fimc_is_scp_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ctrl);
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ merr("device is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr = GET_DST_FRAMEMGR(vctx);
+ frame = NULL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_FORCE_DONE:
+ if (framemgr->frame_pro_cnt) {
+ err("force done can be performed(process count %d)",
+ framemgr->frame_pro_cnt);
+ ret = -EINVAL;
+ } else if (!framemgr->frame_req_cnt) {
+ err("force done can be performed(request count %d)",
+ framemgr->frame_req_cnt);
+ ret = -EINVAL;
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ buffer_done(vctx, frame->index);
+ } else {
+ err("frame is NULL");
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+ break;
+ case V4L2_CID_IS_COLOR_RANGE:
+ if (test_bit(FIMC_IS_SUBDEV_START, &device->group_isp.leader.state)) {
+ err("failed to change color range: device started already (0x%08x)",
+ ctrl->value);
+ ret = -EINVAL;
+ } else {
+ device->color_range &= ~FIMC_IS_SCP_CRANGE_MASK;
+
+ if (ctrl->value)
+ device->color_range |=
+ (FIMC_IS_CRANGE_LIMITED << FIMC_IS_SCP_CRANGE_SHIFT);
+ }
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+const struct v4l2_ioctl_ops fimc_is_scp_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_scp_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_scp_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_scp_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_scp_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_is_scp_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_scp_video_cropcap,
+ .vidioc_g_crop = fimc_is_scp_video_get_crop,
+ .vidioc_s_crop = fimc_is_scp_video_set_crop,
+ .vidioc_reqbufs = fimc_is_scp_video_reqbufs,
+ .vidioc_querybuf = fimc_is_scp_video_querybuf,
+ .vidioc_qbuf = fimc_is_scp_video_qbuf,
+ .vidioc_dqbuf = fimc_is_scp_video_dqbuf,
+ .vidioc_streamon = fimc_is_scp_video_streamon,
+ .vidioc_streamoff = fimc_is_scp_video_streamoff,
+ .vidioc_enum_input = fimc_is_scp_video_enum_input,
+ .vidioc_g_input = fimc_is_scp_video_g_input,
+ .vidioc_s_input = fimc_is_scp_video_s_input,
+ .vidioc_g_ctrl = fimc_is_scp_video_g_ctrl,
+ .vidioc_s_ctrl = fimc_is_scp_video_s_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_scp_video_g_ext_ctrl,
+};
+
+static int fimc_is_scp_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scp_buffer_prepare(struct vb2_buffer *vb)
+{
+ return 0;
+}
+
+static inline void fimc_is_scp_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_scp_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_scp_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ subdev = &device->scp;
+
+ ret = fimc_is_queue_start_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_start_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_scp_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+ mdbgv_scp("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+ subdev = &device->scp;
+
+ ret = fimc_is_queue_stop_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_stop_streaming is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static void fimc_is_scp_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_video *video;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+#ifdef DBG_STREAMING
+ dbg_scp("%s\n", __func__);
+#endif
+
+ queue = GET_DST_QUEUE(vctx);
+ video = vctx->video;
+ device = vctx->device;
+ subdev = &device->scp;
+
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_subdev_buffer_queue(subdev, vb->v4l2_buf.index);
+ if (ret) {
+ merr("fimc_is_subdev_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+}
+
+static int fimc_is_scp_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *ischain = vctx->device;
+ struct fimc_is_subdev *scp = &ischain->scp;
+
+#ifdef DBG_STREAMING
+ dbg_scp("%s(%d)\n", __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_subdev_buffer_finish(scp, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_scp_qops = {
+ .queue_setup = fimc_is_scp_queue_setup,
+ .buf_prepare = fimc_is_scp_buffer_prepare,
+ .buf_queue = fimc_is_scp_buffer_queue,
+ .buf_finish = fimc_is_scp_buffer_finish,
+ .wait_prepare = fimc_is_scp_wait_prepare,
+ .wait_finish = fimc_is_scp_wait_finish,
+ .start_streaming = fimc_is_scp_start_streaming,
+ .stop_streaming = fimc_is_scp_stop_streaming,
+};
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include "fimc-is-device-sensor.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-metadata.h"
+
+const struct v4l2_file_operations fimc_is_sen_video_fops;
+const struct v4l2_ioctl_ops fimc_is_sen_video_ioctl_ops;
+const struct vb2_ops fimc_is_sen_qops;
+
+int fimc_is_sen_video_probe(void *data)
+{
+ int ret = 0;
+ char name[255];
+ u32 number;
+ struct fimc_is_device_sensor *device;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ device = (struct fimc_is_device_sensor *)data;
+ video = &device->video;
+ snprintf(name, sizeof(name), "%s%d", FIMC_IS_VIDEO_SENSOR_NAME, device->instance);
+ number = FIMC_IS_VIDEO_SS0_NUM + device->instance;
+
+ if (!device->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ name,
+ number,
+ VFL_DIR_RX,
+ &device->mem,
+ &device->v4l2_dev,
+ &video->lock,
+ &fimc_is_sen_video_fops,
+ &fimc_is_sen_video_ioctl_ops);
+ if (ret)
+ dev_err(&device->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Video File Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_sen_video_open(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_sensor *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+ device = container_of(video, struct fimc_is_device_sensor, video);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_INVALID, FRAMEMGR_ID_SENSOR);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[SS%d:V:%d] %s\n", video->id, vctx->instance, __func__);
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_SENSOR_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_CAPTURE,
+ &fimc_is_sen_qops,
+ NULL,
+ NULL);
+ if (ret) {
+ merr("fimc_is_video_open is fail(%d)", vctx, ret);
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_open(device, vctx);
+ if (ret) {
+ merr("fimc_is_sen_open is fail(%d)", vctx, ret);
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sen_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video = NULL;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_device_sensor *device = NULL;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ merr("video is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[SS0:V:%d] %s\n", vctx->instance, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ merr("device is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_close(device);
+ if (ret)
+ err("fimc_is_sensor_close is fail(%d)", ret);
+
+ ret = fimc_is_video_close(vctx);
+ if (ret)
+ err("fimc_is_video_close is fail(%d)", ret);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_sen_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+
+ return ret;
+}
+
+static int fimc_is_sen_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_sen_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_sen_video_open,
+ .release = fimc_is_sen_video_close,
+ .poll = fimc_is_sen_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_sen_video_mmap,
+};
+
+/*
+ * =============================================================================
+ * Video Ioctl Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_sen_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ /* Todo : add to query capability code */
+ return 0;
+}
+
+static int fimc_is_sen_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ /* Todo : add to enumerate format code */
+ return 0;
+}
+
+static int fimc_is_sen_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ /* Todo : add to get format code */
+ return 0;
+}
+
+static int fimc_is_sen_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_sensor *device;
+
+ BUG_ON(!vctx);
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret) {
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_s_format(device,
+ &queue->framecfg.format,
+ queue->framecfg.width,
+ queue->framecfg.height);
+ if (ret) {
+ merr("fimc_is_sensor_s_format is fail(%d)", vctx, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sen_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ /* Todo : add to crop capability code */
+ return 0;
+}
+
+static int fimc_is_sen_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ /* Todo : add to get crop control code */
+ return 0;
+}
+
+static int fimc_is_sen_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_sensor *sensor;
+
+ BUG_ON(!vctx);
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ sensor = vctx->device;
+ BUG_ON(!sensor);
+
+ fimc_is_sensor_s_format(sensor, &sensor->image.format, crop->c.width, crop->c.height);
+
+ return 0;
+}
+
+static int fimc_is_sen_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ BUG_ON(!vctx);
+
+ mdbgv_sensor("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(error %d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_sen_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_sen_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ /*dbg_sensor("%s\n", __func__);*/
+#endif
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_qbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_sen_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ bool blocking;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_sensor("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ if (ret) {
+ blocking = file->f_flags & O_NONBLOCK;
+ if (!blocking || (ret != -EAGAIN))
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+ }
+
+ return ret;
+}
+
+static int fimc_is_sen_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_sen_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_sen_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo: add to enumerate input code */
+ info("%s is calld\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sen_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ /* Todo: add to get input control code */
+ return 0;
+}
+
+static int fimc_is_sen_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ int ret = 0;
+ u32 scenario;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_sensor *device;
+ struct fimc_is_framemgr *framemgr;
+
+ BUG_ON(!vctx);
+
+ mdbgv_sensor("%s(input : %08X)\n", vctx, __func__, input);
+
+ device = vctx->device;
+ framemgr = GET_DST_FRAMEMGR(vctx);
+ scenario = (input & SENSOR_SCENARIO_MASK) >> SENSOR_SCENARIO_SHIFT;
+ input = (input & SENSOR_MODULE_MASK) >> SENSOR_MODULE_SHIFT;
+
+ ret = fimc_is_sensor_s_input(device, input, scenario);
+ if (ret) {
+ merr("fimc_is_sensor_s_input is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sen_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_sensor *device;
+ struct v4l2_subdev *subdev_flite;
+
+ BUG_ON(!ctrl);
+ BUG_ON(!vctx);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ subdev_flite = device->subdev_flite;
+ if (!subdev_flite) {
+ err("subdev_flite is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_S_STREAM:
+ {
+ u32 sstream, instant, noblock;
+
+ sstream = (ctrl->value & SENSOR_SSTREAM_MASK) >> SENSOR_SSTREAM_SHIFT;
+ instant = (ctrl->value & SENSOR_INSTANT_MASK) >> SENSOR_INSTANT_SHIFT;
+ noblock = (ctrl->value & SENSOR_NOBLOCK_MASK) >> SENSOR_NOBLOCK_SHIFT;
+ /*
+ * nonblock(0) : blocking command
+ * nonblock(1) : non-blocking command
+ */
+
+ if (sstream == IS_ENABLE_STREAM) {
+ ret = fimc_is_sensor_front_start(device, instant, noblock);
+ if (ret) {
+ merr("fimc_is_sensor_front_start is fail(%d)", device, ret);
+ goto p_err;
+ }
+ } else {
+ ret = fimc_is_sensor_front_stop(device);
+ if (ret) {
+ merr("fimc_is_sensor_front_stop is fail(%d)", device, ret);
+ goto p_err;
+ }
+ }
+ }
+ break;
+ case V4L2_CID_IS_S_BNS:
+ if (device->pdata->is_bns == false) {
+ mwarn("Could not support BNS\n", device);
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_s_bns(device, ctrl->value);
+ if (ret) {
+ merr("fimc_is_sensor_s_bns is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ ret = v4l2_subdev_call(subdev_flite, core, s_ctrl, ctrl);
+ if (ret) {
+ merr("v4l2_flite_call(s_ctrl) is fail(%d)", device, ret);
+ goto p_err;
+ }
+ break;
+ /*
+ * gain boost: min_target_fps, max_target_fps, scene_mode
+ */
+ case V4L2_CID_IS_MIN_TARGET_FPS:
+ if (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) {
+ err("failed to set min_target_fps: %d - sensor stream on already\n",
+ ctrl->value);
+ ret = -EINVAL;
+ } else {
+ device->min_target_fps = ctrl->value;
+ }
+ break;
+ case V4L2_CID_IS_MAX_TARGET_FPS:
+ if (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) {
+ err("failed to set max_target_fps: %d - sensor stream on already\n",
+ ctrl->value);
+ ret = -EINVAL;
+ } else {
+ device->max_target_fps = ctrl->value;
+ }
+ break;
+ case V4L2_CID_SCENEMODE:
+ if (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) {
+ err("failed to set scene_mode: %d - sensor stream on already\n",
+ ctrl->value);
+ ret = -EINVAL;
+ } else {
+ device->scene_mode = ctrl->value;
+ }
+ break;
+ case V4L2_CID_SENSOR_SET_FRAME_RATE:
+ if (fimc_is_sensor_s_frame_duration(device, ctrl->value)) {
+ err("failed to set frame duration : %d\n - %d",
+ ctrl->value, ret);
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_SENSOR_SET_AE_TARGET:
+ if (fimc_is_sensor_s_exposure_time(device, ctrl->value)) {
+ err("failed to set exposure time : %d\n - %d",
+ ctrl->value, ret);
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ ret = fimc_is_sensor_s_ctrl(device, ctrl);
+ if (ret) {
+ err("invalid ioctl(0x%08X) is requested", ctrl->id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sen_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_sensor *device;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ctrl);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_G_STREAM:
+ if (device->instant_ret)
+ ctrl->value = device->instant_ret;
+ else
+ ctrl->value = (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state) ?
+ IS_ENABLE_STREAM : IS_DISABLE_STREAM);
+ break;
+ case V4L2_CID_IS_G_BNS_SIZE:
+ {
+ u32 width, height;
+
+ width = fimc_is_sensor_g_bns_width(device);
+ height = fimc_is_sensor_g_bns_height(device);
+
+ ctrl->value = (width << 16) | height;
+ }
+ break;
+ case V4L2_CID_IS_G_DTPSTATUS:
+ if (test_bit(FIMC_IS_SENSOR_FRONT_DTP_STOP, &device->state))
+ ctrl->value = 1;
+ else
+ ctrl->value = 0;
+ break;
+ default:
+ ret = fimc_is_sensor_g_ctrl(device, ctrl);
+ if (ret) {
+ err("invalid ioctl(0x%08X) is requested", ctrl->id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_sen_video_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_sensor *device = vctx->device;
+ struct v4l2_captureparm *cp = &parm->parm.capture;
+ struct v4l2_fract *tfp = &cp->timeperframe;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ cp->capability |= V4L2_CAP_TIMEPERFRAME;
+ tfp->numerator = 1;
+ tfp->denominator = device->image.framerate;
+
+ return 0;
+}
+
+static int fimc_is_sen_video_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_sensor *device;
+
+ BUG_ON(!vctx);
+ BUG_ON(!parm);
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_s_framerate(device, parm);
+ if (ret) {
+ merr("fimc_is_sen_s_framerate is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+const struct v4l2_ioctl_ops fimc_is_sen_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_sen_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_sen_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_sen_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_sen_video_set_format_mplane,
+ .vidioc_cropcap = fimc_is_sen_video_cropcap,
+ .vidioc_g_crop = fimc_is_sen_video_get_crop,
+ .vidioc_s_crop = fimc_is_sen_video_set_crop,
+ .vidioc_reqbufs = fimc_is_sen_video_reqbufs,
+ .vidioc_querybuf = fimc_is_sen_video_querybuf,
+ .vidioc_qbuf = fimc_is_sen_video_qbuf,
+ .vidioc_dqbuf = fimc_is_sen_video_dqbuf,
+ .vidioc_streamon = fimc_is_sen_video_streamon,
+ .vidioc_streamoff = fimc_is_sen_video_streamoff,
+ .vidioc_enum_input = fimc_is_sen_video_enum_input,
+ .vidioc_g_input = fimc_is_sen_video_g_input,
+ .vidioc_s_input = fimc_is_sen_video_s_input,
+ .vidioc_s_ctrl = fimc_is_sen_video_s_ctrl,
+ .vidioc_g_ctrl = fimc_is_sen_video_g_ctrl,
+ .vidioc_g_parm = fimc_is_sen_video_g_parm,
+ .vidioc_s_parm = fimc_is_sen_video_s_parm,
+};
+
+static int fimc_is_sen_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_sen_buffer_prepare(struct vb2_buffer *vb)
+{
+ return 0;
+}
+
+static inline void fimc_is_sen_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_sen_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_sen_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_sensor *device;
+
+ BUG_ON(!vctx);
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+
+ if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state) &&
+ test_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state)) {
+ set_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state);
+ fimc_is_sensor_back_start(device);
+ } else {
+ err("already stream on or buffer is not ready(%ld)",
+ queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state);
+ fimc_is_sensor_back_stop(device);
+ ret = -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fimc_is_sen_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_sensor *device;
+
+ BUG_ON(!vctx);
+
+ mdbgv_sensor("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+
+ if (test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ clear_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state);
+ ret = fimc_is_sensor_back_stop(device);
+ } else {
+ err("already stream off");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void fimc_is_sen_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_video *video;
+ struct fimc_is_device_sensor *device;
+
+#ifdef DBG_STREAMING
+ mdbgv_sensor("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index);
+#endif
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ video = vctx->video;
+ if (!video) {
+ merr("video is NULL", device);
+ return;
+ }
+
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", device, ret);
+ return;
+ }
+
+ ret = fimc_is_sensor_buffer_queue(device, vb->v4l2_buf.index);
+ if (ret) {
+ merr("fimc_is_sensor_buffer_queue is fail(%d)", device, ret);
+ return;
+ }
+}
+
+static int fimc_is_sen_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_sensor *device;
+
+#ifdef DBG_STREAMING
+ mdbgv_sensor("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index);
+#endif
+ device = vctx->device;
+
+ ret = fimc_is_sensor_buffer_finish(
+ device,
+ vb->v4l2_buf.index);
+ if (ret) {
+ merr("fimc_is_sensor_buffer_finish is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+const struct vb2_ops fimc_is_sen_qops = {
+ .queue_setup = fimc_is_sen_queue_setup,
+ .buf_prepare = fimc_is_sen_buffer_prepare,
+ .buf_queue = fimc_is_sen_buffer_queue,
+ .buf_finish = fimc_is_sen_buffer_finish,
+ .wait_prepare = fimc_is_sen_wait_prepare,
+ .wait_finish = fimc_is_sen_wait_finish,
+ .start_streaming = fimc_is_sen_start_streaming,
+ .stop_streaming = fimc_is_sen_stop_streaming,
+};
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+const struct v4l2_file_operations fimc_is_vdc_video_fops;
+const struct v4l2_ioctl_ops fimc_is_vdc_video_ioctl_ops;
+const struct vb2_ops fimc_is_vdc_qops;
+
+int fimc_is_vdc_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_vdc;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_VDC_NAME,
+ FIMC_IS_VIDEO_VDC_NUM,
+ VFL_DIR_RX,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_vdc_video_fops,
+ &fimc_is_vdc_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_vdc_video_open(struct file *file)
+{
+ int ret = 0;
+ u32 refcount;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_ischain *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+ core = container_of(video, struct fimc_is_core, video_vdc);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_INVALID, FRAMEMGR_ID_DIS);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[VDC:V:%d] %s\n", vctx->instance, __func__);
+
+ refcount = atomic_read(&core->video_isp.refcount);
+ if (refcount > FIMC_IS_MAX_NODES || refcount < 1) {
+ err("invalid ischain refcount(%d)", refcount);
+ close_vctx(file, video, vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device = &core->ischain[refcount - 1];
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_VDISC_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_CAPTURE,
+ &fimc_is_vdc_qops,
+ NULL,
+ &fimc_is_ischain_sub_ops);
+ if (ret) {
+ err("fimc_is_video_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_subdev_open(&device->dis, vctx, NULL);
+ if (ret) {
+ err("fimc_is_subdev_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_vdc_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ merr("video is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[VDC:V:%d] %s\n", vctx->instance, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_subdev_close(&device->dis);
+ fimc_is_video_close(vctx);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret < 0)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_vdc_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+ if (ret)
+ merr("fimc_is_video_poll is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *core = video_drvdata(file);
+
+ dbg_vdisc("%s(devname : %s)\n", __func__, core->pdev->name);
+
+ strncpy(cap->driver, core->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, core->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_vdc_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ /* Todo: add enum format control code */
+ return 0;
+}
+
+static int fimc_is_vdc_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ /* Todo: add get format control code */
+ return 0;
+}
+
+static int fimc_is_vdc_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_queue *queue = vctx->q_dst;
+ struct fimc_is_device_ischain *ischain = vctx->device;
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret)
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+
+ dbg_vdisc("req w : %d req h : %d\n",
+ queue->framecfg.width,
+ queue->framecfg.height);
+
+ fimc_is_ischain_vdc_s_format(ischain,
+ queue->framecfg.width,
+ queue->framecfg.height);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *ischain;
+
+ BUG_ON(!vctx);
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ ischain = vctx->device;
+ BUG_ON(!ischain);
+
+ fimc_is_ischain_vdc_s_format(ischain,
+ crop->c.width, crop->c.height);
+
+ return 0;
+}
+
+static int fimc_is_vdc_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_vdc("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ device = vctx->device;
+ subdev = &device->dis;
+ leader = subdev->leader;
+
+ if (!leader) {
+ merr("leader is NULL ptr", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) {
+ merr("leader still running, not applied", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_vdc_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_vdc("%s(index : %d)\n", vctx, __func__, buf->index);
+#endif
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_qbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_vdc("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo : add to enum input control code */
+ return 0;
+}
+
+static int fimc_is_vdc_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ /* Todo: add get input control code */
+ return 0;
+}
+
+static int fimc_is_vdc_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ /* Todo: add set input control code */
+ return 0;
+}
+
+static int fimc_is_vdc_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_framemgr *framemgr = &vctx->q_dst->framemgr;
+
+ dbg_vdisc("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_G_COMPLETES:
+ ctrl->value = framemgr->frame_com_cnt;
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_vdc_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ /* Todo: add get extra control code */
+ return 0;
+}
+
+static int fimc_is_vdc_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ BUG_ON(!vctx);
+ BUG_ON(!ctrl);
+
+ dbg_vdisc("%s\n", __func__);
+
+ framemgr = GET_DST_FRAMEMGR(vctx);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_FORCE_DONE:
+ if (framemgr->frame_pro_cnt) {
+ err("force done can be performed(process count %d)",
+ framemgr->frame_pro_cnt);
+ ret = -EINVAL;
+ } else if (!framemgr->frame_req_cnt) {
+ err("force done can be performed(request count %d)",
+ framemgr->frame_req_cnt);
+ ret = -EINVAL;
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ buffer_done(vctx, frame->index);
+ } else {
+ err("frame is NULL");
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_vdc_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_vdc_video_open,
+ .release = fimc_is_vdc_video_close,
+ .poll = fimc_is_vdc_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_vdc_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_vdc_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_vdc_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_vdc_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_vdc_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_vdc_video_set_format_mplane,
+ .vidioc_s_crop = fimc_is_vdc_video_set_crop,
+ .vidioc_reqbufs = fimc_is_vdc_video_reqbufs,
+ .vidioc_querybuf = fimc_is_vdc_video_querybuf,
+ .vidioc_qbuf = fimc_is_vdc_video_qbuf,
+ .vidioc_dqbuf = fimc_is_vdc_video_dqbuf,
+ .vidioc_streamon = fimc_is_vdc_video_streamon,
+ .vidioc_streamoff = fimc_is_vdc_video_streamoff,
+ .vidioc_enum_input = fimc_is_vdc_video_enum_input,
+ .vidioc_g_input = fimc_is_vdc_video_g_input,
+ .vidioc_s_input = fimc_is_vdc_video_s_input,
+ .vidioc_g_ctrl = fimc_is_vdc_video_g_ctrl,
+ .vidioc_s_ctrl = fimc_is_vdc_video_s_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_vdc_video_g_ext_ctrl,
+};
+
+static int fimc_is_vdc_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_buffer_prepare(struct vb2_buffer *vb)
+{
+ /* Todo: add buffer prepare control code */
+ return 0;
+}
+
+static inline void fimc_is_vdc_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_vdc_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_vdc_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ subdev = &device->dis;
+
+ ret = fimc_is_queue_start_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_start_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdc_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *subdev;
+
+ BUG_ON(!vctx);
+
+ mdbgv_vdc("%s\n", vctx, __func__);
+
+ queue = GET_DST_QUEUE(vctx);
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+ subdev = &device->dis;
+
+ ret = fimc_is_queue_stop_streaming(queue, device, subdev, vctx);
+ if (ret)
+ merr("fimc_is_queue_stop_streaming is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static void fimc_is_vdc_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_queue *queue = vctx->q_dst;
+ struct fimc_is_video *video = vctx->video;
+ struct fimc_is_device_ischain *ischain = vctx->device;
+ struct fimc_is_subdev *subdev = &ischain->dis;
+
+#ifdef DBG_STREAMING
+ dbg_vdisc("%s\n", __func__);
+#endif
+
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_subdev_buffer_queue(subdev, vb->v4l2_buf.index);
+ if (ret) {
+ merr("fimc_is_subdev_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+}
+
+static int fimc_is_vdc_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *ischain = vctx->device;
+ struct fimc_is_subdev *dis = &ischain->dis;
+
+#ifdef DBG_STREAMING
+ dbg_vdisc("%s(%d)\n", __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_subdev_buffer_finish(dis, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_vdc_qops = {
+ .queue_setup = fimc_is_vdc_queue_setup,
+ .buf_prepare = fimc_is_vdc_buffer_prepare,
+ .buf_queue = fimc_is_vdc_buffer_queue,
+ .buf_finish = fimc_is_vdc_buffer_finish,
+ .wait_prepare = fimc_is_vdc_wait_prepare,
+ .wait_finish = fimc_is_vdc_wait_finish,
+ .start_streaming = fimc_is_vdc_start_streaming,
+ .stop_streaming = fimc_is_vdc_stop_streaming,
+};
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-metadata.h"
+
+const struct v4l2_file_operations fimc_is_vdo_video_fops;
+const struct v4l2_ioctl_ops fimc_is_vdo_video_ioctl_ops;
+const struct vb2_ops fimc_is_vdo_qops;
+
+int fimc_is_vdo_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+
+ BUG_ON(!data);
+
+ core = (struct fimc_is_core *)data;
+ video = &core->video_vdo;
+
+ if (!core->pdev) {
+ err("pdev is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_probe(video,
+ FIMC_IS_VIDEO_VDO_NAME,
+ FIMC_IS_VIDEO_VDO_NUM,
+ VFL_DIR_TX,
+ &core->mem,
+ &core->v4l2_dev,
+ &video->lock,
+ &fimc_is_vdo_video_fops,
+ &fimc_is_vdo_video_ioctl_ops);
+ if (ret)
+ dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_vdo_video_open(struct file *file)
+{
+ int ret = 0;
+ u32 refcount;
+ struct fimc_is_core *core;
+ struct fimc_is_video *video;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_device_ischain *device;
+
+ vctx = NULL;
+ video = video_drvdata(file);
+ core = container_of(video, struct fimc_is_core, video_vdo);
+
+ ret = open_vctx(file, video, &vctx, FRAMEMGR_ID_DIS_GRP, FRAMEMGR_ID_INVALID);
+ if (ret) {
+ err("open_vctx is fail(%d)", ret);
+ goto p_err;
+ }
+
+ info("[VDO:V:%d] %s\n", vctx->instance, __func__);
+
+ refcount = atomic_read(&core->video_isp.refcount);
+ if (refcount > FIMC_IS_MAX_NODES || refcount < 1) {
+ err("invalid ischain refcount(%d)", refcount);
+ close_vctx(file, video, vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ device = &core->ischain[refcount - 1];
+
+ ret = fimc_is_video_open(vctx,
+ device,
+ VIDEO_VDISO_READY_BUFFERS,
+ video,
+ FIMC_IS_VIDEO_TYPE_OUTPUT,
+ &fimc_is_vdo_qops,
+ &fimc_is_ischain_vdo_ops,
+ &fimc_is_ischain_sub_ops);
+ if (ret) {
+ err("fimc_is_video_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+ ret = fimc_is_ischain_vdo_open(device, vctx);
+ if (ret) {
+ err("fimc_is_ischain_vdo_open is fail");
+ close_vctx(file, video, vctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_vdo_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = NULL;
+ struct fimc_is_video *video;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!file);
+
+ vctx = file->private_data;
+ if (!vctx) {
+ err("vctx is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video = vctx->video;
+ if (!video) {
+ err("video is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ info("[VDO:V:%d] %s\n", vctx->instance, __func__);
+
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ fimc_is_ischain_vdo_close(device, vctx);
+ fimc_is_video_close(vctx);
+
+ ret = close_vctx(file, video, vctx);
+ if (ret < 0)
+ err("close_vctx is fail(%d)", ret);
+
+p_err:
+ return ret;
+}
+
+static unsigned int fimc_is_vdo_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_poll(file, vctx, wait);
+ if (ret)
+ merr("fimc_is_video_poll is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ ret = fimc_is_video_mmap(file, vctx, vma);
+ if (ret)
+ merr("fimc_is_video_mmap is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_vdo_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_vdo_video_open,
+ .release = fimc_is_vdo_video_close,
+ .poll = fimc_is_vdo_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_vdo_video_mmap,
+};
+
+static int fimc_is_vdo_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *core = video_drvdata(file);
+
+ strncpy(cap->driver, core->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg_vdiso("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, core->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_vdo_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ /* Todo: add enum format control code */
+ return 0;
+}
+
+static int fimc_is_vdo_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ /* Todo: add get format control code */
+ return 0;
+}
+
+static int fimc_is_vdo_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdo("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_set_format_mplane(file, vctx, format);
+ if (ret)
+ merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret);
+
+ dbg_vdiso("req w : %d req h : %d\n",
+ vctx->q_src->framecfg.width,
+ vctx->q_src->framecfg.height);
+
+ return ret;
+}
+
+static int fimc_is_vdo_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdo("%s(buffers : %d)\n", vctx, __func__, buf->count);
+
+ ret = fimc_is_video_reqbufs(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_reqbufs is fail(error %d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdo("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_querybuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_querybuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+ struct fimc_is_queue *queue;
+
+#ifdef DBG_STREAMING
+ dbg_vdiso("%s\n", __func__);
+#endif
+
+ queue = GET_SRC_QUEUE(vctx);
+
+ if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ merr("stream off state, can NOT qbuf", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_video_qbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_qbuf is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_vdo_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+#ifdef DBG_STREAMING
+ mdbgv_vdo("%s\n", vctx, __func__);
+#endif
+
+ ret = fimc_is_video_dqbuf(file, vctx, buf);
+ if (ret)
+ merr("fimc_is_video_dqbuf is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdo("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamon(file, vctx, type);
+ if (ret)
+ merr("fimc_is_vdo_video_streamon is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = file->private_data;
+
+ mdbgv_vdo("%s\n", vctx, __func__);
+
+ ret = fimc_is_video_streamoff(file, vctx, type);
+ if (ret)
+ merr("fimc_is_video_streamoff is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ /* Todo : add to enum input control code */
+ return 0;
+}
+
+static int fimc_is_vdo_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ /* Todo: add get input control code */
+ return 0;
+}
+
+static int fimc_is_vdo_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ /* Todo: add set input control code */
+ return 0;
+}
+
+static int fimc_is_vdo_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ /* Todo: add set control code */
+ return 0;
+}
+
+static int fimc_is_vdo_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ /* Todo: add get control code */
+ return 0;
+}
+
+static int fimc_is_vdo_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ /* Todo: add get extra control code */
+ return 0;
+}
+
+const struct v4l2_ioctl_ops fimc_is_vdo_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_vdo_video_querycap,
+ .vidioc_enum_fmt_vid_out_mplane = fimc_is_vdo_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_out_mplane = fimc_is_vdo_video_get_format_mplane,
+ .vidioc_s_fmt_vid_out_mplane = fimc_is_vdo_video_set_format_mplane,
+ .vidioc_reqbufs = fimc_is_vdo_video_reqbufs,
+ .vidioc_querybuf = fimc_is_vdo_video_querybuf,
+ .vidioc_qbuf = fimc_is_vdo_video_qbuf,
+ .vidioc_dqbuf = fimc_is_vdo_video_dqbuf,
+ .vidioc_streamon = fimc_is_vdo_video_streamon,
+ .vidioc_streamoff = fimc_is_vdo_video_streamoff,
+ .vidioc_enum_input = fimc_is_vdo_video_enum_input,
+ .vidioc_g_input = fimc_is_vdo_video_g_input,
+ .vidioc_s_input = fimc_is_vdo_video_s_input,
+ .vidioc_s_ctrl = fimc_is_vdo_video_s_ctrl,
+ .vidioc_g_ctrl = fimc_is_vdo_video_g_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_vdo_video_g_ext_ctrl,
+};
+
+static int fimc_is_vdo_queue_setup(struct vb2_queue *vbq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vbq->drv_priv;
+ struct fimc_is_video *video;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+
+ mdbgv_isp("%s\n", vctx, __func__);
+
+ queue = GET_SRC_QUEUE(vctx);
+ video = vctx->video;
+
+ ret = fimc_is_queue_setup(queue,
+ video->alloc_ctx,
+ num_planes,
+ sizes,
+ allocators);
+ if (ret)
+ merr("fimc_is_queue_setup is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_buffer_prepare(struct vb2_buffer *vb)
+{
+ /* Todo: add buffer prepare control code */
+ return 0;
+}
+
+static inline void fimc_is_vdo_wait_prepare(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_prepare(vbq);
+}
+
+static inline void fimc_is_vdo_wait_finish(struct vb2_queue *vbq)
+{
+ fimc_is_queue_wait_finish(vbq);
+}
+
+static int fimc_is_vdo_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_vdo("%s\n", vctx, __func__);
+
+ queue = GET_SRC_QUEUE(vctx);
+ device = vctx->device;
+ leader = &device->group_dis.leader;
+
+ ret = fimc_is_queue_start_streaming(queue, device, leader, vctx);
+ if (ret)
+ merr("fimc_is_queue_start_streaming is fail(%d)", vctx, ret);
+
+ return ret;
+}
+
+static int fimc_is_vdo_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = q->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_device_ischain *device;
+ struct fimc_is_subdev *leader;
+
+ BUG_ON(!vctx);
+
+ mdbgv_vdo("%s\n", vctx, __func__);
+
+ queue = GET_SRC_QUEUE(vctx);
+ device = vctx->device;
+ if (!device) {
+ err("device is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+ leader = &device->group_dis.leader;
+
+ ret = fimc_is_queue_stop_streaming(queue, device, leader, vctx);
+ if (ret)
+ merr("fimc_is_queue_stop_streaming is fail(%d)", vctx, ret);
+
+p_err:
+ return ret;
+}
+
+static void fimc_is_vdo_buffer_queue(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ u32 index;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_queue *queue;
+ struct fimc_is_video *video;
+ struct fimc_is_device_ischain *device;
+
+ BUG_ON(!vctx);
+ index = vb->v4l2_buf.index;
+
+#ifdef DBG_STREAMING
+ dbg_vdiso("%s(%d)\n", __func__, index);
+#endif
+
+ queue = GET_SRC_QUEUE(vctx);
+ video = vctx->video;
+ device = vctx->device;
+
+ ret = fimc_is_queue_buffer_queue(queue, video->vb2, vb);
+ if (ret) {
+ merr("fimc_is_queue_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+
+ ret = fimc_is_ischain_vdo_buffer_queue(device, queue, index);
+ if (ret) {
+ merr("fimc_is_ischain_vdo_buffer_queue is fail(%d)", vctx, ret);
+ return;
+ }
+}
+
+static int fimc_is_vdo_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *device = vctx->device;
+
+#ifdef DBG_STREAMING
+ mdbgv_vdo("%s(%d)\n", vctx, __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_ischain_vdo_buffer_finish(device, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_vdo_qops = {
+ .queue_setup = fimc_is_vdo_queue_setup,
+ .buf_prepare = fimc_is_vdo_buffer_prepare,
+ .buf_queue = fimc_is_vdo_buffer_queue,
+ .buf_finish = fimc_is_vdo_buffer_finish,
+ .wait_prepare = fimc_is_vdo_wait_prepare,
+ .wait_finish = fimc_is_vdo_wait_finish,
+ .start_streaming = fimc_is_vdo_start_streaming,
+ .stop_streaming = fimc_is_vdo_stop_streaming,
+};
+
--- /dev/null
+/*
+* Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/exynos_mc.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+
+#define SPARE_PLANE 1
+#define SPARE_SIZE (32 * 1024)
+
+struct fimc_is_fmt fimc_is_formats[] = {
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .num_planes = 1 + SPARE_PLANE,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .num_planes = 1 + SPARE_PLANE,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12M,
+ .num_planes = 2 + SPARE_PLANE,
+ }, {
+ .name = "YVU 4:2:0 non-contiguous 2-planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21M,
+ .num_planes = 2 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV420M,
+ .num_planes = 3 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
+ .pixelformat = V4L2_PIX_FMT_YVU420M,
+ .num_planes = 3 + SPARE_PLANE,
+ }, {
+ .name = "BAYER 8 bit",
+ .pixelformat = V4L2_PIX_FMT_SGRBG8,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "BAYER 10 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "BAYER 12 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR12,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "BAYER 16 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR16,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "JPEG",
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .num_planes = 1 + SPARE_PLANE,
+ .mbus_code = V4L2_MBUS_FMT_JPEG_1X8,
+ }
+};
+
+struct fimc_is_fmt *fimc_is_find_format(u32 *pixelformat,
+ u32 *mbus_code, int index)
+{
+ struct fimc_is_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+
+ if (index >= ARRAY_SIZE(fimc_is_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_is_formats); ++i) {
+ fmt = &fimc_is_formats[i];
+ if (pixelformat && fmt->pixelformat == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->mbus_code == *mbus_code)
+ return fmt;
+ if (index == i)
+ def_fmt = fmt;
+ }
+ return def_fmt;
+
+}
+
+int get_plane_size_flite(int width, int height)
+{
+ int PlaneSize;
+ int Alligned_Width;
+ int Bytes;
+
+ Alligned_Width = (width + 9) / 10 * 10;
+ Bytes = Alligned_Width * 8 / 5 ;
+
+ PlaneSize = Bytes * height;
+
+ return PlaneSize;
+}
+
+void fimc_is_set_plane_size(struct fimc_is_frame_cfg *frame, unsigned int sizes[])
+{
+ u32 plane;
+ u32 width[FIMC_IS_MAX_PLANES];
+
+ for (plane = 0; plane < FIMC_IS_MAX_PLANES; ++plane)
+ width[plane] = frame->width + frame->width_stride[plane];
+
+ switch (frame->format.pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ dbg("V4L2_PIX_FMT_YUYV(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0]*frame->height*2;
+ sizes[1] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ dbg("V4L2_PIX_FMT_NV12(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0] * frame->height * 3 / 2;
+ sizes[1] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ dbg("V4L2_PIX_FMT_NV12M(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0]*frame->height;
+ sizes[1] = width[1]*frame->height/2;
+ sizes[2] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ dbg("V4L2_PIX_FMT_NV21(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0] * frame->height * 3 / 2;
+ sizes[1] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ dbg("V4L2_PIX_FMT_NV21M(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0]*frame->height;
+ sizes[1] = width[1]*frame->height/2;
+ sizes[2] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ dbg("V4L2_PIX_FMT_YVU420M(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0]*frame->height;
+ sizes[1] = width[1]*frame->height/4;
+ sizes[2] = width[2]*frame->height/4;
+ sizes[3] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_SGRBG8:
+ dbg("V4L2_PIX_FMT_SGRBG8(w:%d)(h:%d)\n", frame->width, frame->height);
+ sizes[0] = frame->width*frame->height;
+ sizes[1] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ dbg("V4L2_PIX_FMT_SBGGR10(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = get_plane_size_flite(frame->width,frame->height);
+ if (frame->bytesperline[0]) {
+ if (frame->bytesperline[0] >= frame->width * 5 / 4) {
+ sizes[0] = frame->bytesperline[0]
+ * frame->height;
+ } else {
+ err("Bytesperline too small\
+ (fmt(V4L2_PIX_FMT_SBGGR10), W(%d), Bytes(%d))",
+ frame->width,
+ frame->bytesperline[0]);
+ }
+ }
+ sizes[1] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_SBGGR16:
+ dbg("V4L2_PIX_FMT_SBGGR16(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height*2;
+ if (frame->bytesperline[0]) {
+ if (frame->bytesperline[0] >= frame->width * 2) {
+ sizes[0] = frame->bytesperline[0]
+ * frame->height;
+ } else {
+ err("Bytesperline too small\
+ (fmt(V4L2_PIX_FMT_SBGGR16), W(%d), Bytes(%d))",
+ frame->width,
+ frame->bytesperline[0]);
+ }
+ }
+ sizes[1] = SPARE_SIZE;
+ break;
+ case V4L2_PIX_FMT_SBGGR12:
+ dbg("V4L2_PIX_FMT_SBGGR12(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = get_plane_size_flite(frame->width,frame->height);
+ if (frame->bytesperline[0]) {
+ if (frame->bytesperline[0] >= frame->width * 3 / 2) {
+ sizes[0] = frame->bytesperline[0]
+ * frame->height;
+ } else {
+ err("Bytesperline too small\
+ (fmt(V4L2_PIX_FMT_SBGGR12), W(%d), Bytes(%d))",
+ frame->width,
+ frame->bytesperline[0]);
+ }
+ }
+ sizes[1] = SPARE_SIZE;
+ break;
+ default:
+ err("unknown pixelformat\n");
+ break;
+ }
+}
+
+static inline void vref_init(struct fimc_is_video *video)
+{
+ atomic_set(&video->refcount, 0);
+}
+
+static inline int vref_get(struct fimc_is_video *video)
+{
+ return atomic_inc_return(&video->refcount) - 1;
+}
+
+static inline int vref_put(struct fimc_is_video *video,
+ void (*release)(struct fimc_is_video *video))
+{
+ int ret = 0;
+
+ ret = atomic_sub_and_test(1, &video->refcount);
+ if (ret)
+ pr_debug("closed all instacne");
+
+ return atomic_read(&video->refcount);
+}
+
+static int queue_init(void *priv, struct vb2_queue *vbq_src,
+ struct vb2_queue *vbq_dst)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx = priv;
+
+ BUG_ON(!vctx);
+
+ if (vctx->type == FIMC_IS_VIDEO_TYPE_OUTPUT) {
+ BUG_ON(!vbq_src);
+
+ vbq_src->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ vbq_src->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ vbq_src->drv_priv = vctx;
+ vbq_src->ops = vctx->vb2_ops;
+ vbq_src->mem_ops = vctx->mem_ops;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ vbq_src->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+#endif
+ ret = vb2_queue_init(vbq_src);
+ if (ret) {
+ err("vb2_queue_init fail");
+ goto p_err;
+ }
+ vctx->q_src->vbq = vbq_src;
+ } else if (vctx->type == FIMC_IS_VIDEO_TYPE_CAPTURE) {
+ BUG_ON(!vbq_dst);
+
+ vbq_dst->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ vbq_dst->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ vbq_dst->drv_priv = vctx;
+ vbq_dst->ops = vctx->vb2_ops;
+ vbq_dst->mem_ops = vctx->mem_ops;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ vbq_dst->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+#endif
+ ret = vb2_queue_init(vbq_dst);
+ if (ret) {
+ err("vb2_queue_init fail");
+ goto p_err;
+ }
+ vctx->q_dst->vbq = vbq_dst;
+ } else if (vctx->type == FIMC_IS_VIDEO_TYPE_M2M) {
+ BUG_ON(!vbq_src);
+ BUG_ON(!vbq_dst);
+
+ vbq_src->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ vbq_src->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ vbq_src->drv_priv = vctx;
+ vbq_src->ops = vctx->vb2_ops;
+ vbq_src->mem_ops = vctx->mem_ops;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ vbq_src->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+#endif
+ ret = vb2_queue_init(vbq_src);
+ if (ret) {
+ err("vb2_queue_init fail");
+ goto p_err;
+ }
+ vctx->q_src->vbq = vbq_src;
+
+ vbq_dst->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ vbq_dst->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ vbq_dst->drv_priv = vctx;
+ vbq_dst->ops = vctx->vb2_ops;
+ vbq_dst->mem_ops = vctx->mem_ops;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ vbq_dst->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+#endif
+ ret = vb2_queue_init(vbq_dst);
+ if (ret) {
+ err("vb2_queue_init fail");
+ goto p_err;
+ }
+ vctx->q_dst->vbq = vbq_dst;
+ } else {
+ merr("video type is invalid(%d)", vctx, vctx->type);
+ ret = -EINVAL;
+ }
+
+p_err:
+ return ret;
+}
+
+int open_vctx(struct file *file,
+ struct fimc_is_video *video,
+ struct fimc_is_video_ctx **vctx,
+ u32 id_src, u32 id_dst)
+{
+ int ret = 0;
+ struct fimc_is_queue *q_src = NULL;
+ struct fimc_is_queue *q_dst = NULL;
+
+ BUG_ON(!file);
+ BUG_ON(!video);
+
+ if (atomic_read(&video->refcount) > FIMC_IS_MAX_NODES) {
+ err("can't open vctx, refcount is invalid");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ *vctx = kzalloc(sizeof(struct fimc_is_video_ctx), GFP_KERNEL);
+ if (*vctx == NULL) {
+ err("kzalloc is fail");
+ ret = -ENOMEM;
+ *vctx = NULL;
+ goto exit;
+ }
+
+ q_src = kzalloc(sizeof(struct fimc_is_queue), GFP_KERNEL);
+ if (q_src == NULL) {
+ err("kzalloc is fail(q_src)");
+ ret = -ENOMEM;
+ kfree(*vctx);
+ *vctx = NULL;
+ goto exit;
+ }
+
+ q_dst = kzalloc(sizeof(struct fimc_is_queue), GFP_KERNEL);
+ if (q_dst == NULL) {
+ err("kzalloc is fail(q_dst)");
+ ret = -ENOMEM;
+ kfree(*vctx);
+ kfree(q_src);
+ *vctx = NULL;
+ goto exit;
+ }
+
+ (*vctx)->instance = vref_get(video);
+ (*vctx)->q_src = q_src;
+ (*vctx)->q_dst = q_dst;
+ (*vctx)->q_src->id = id_src;
+ (*vctx)->q_dst->id = id_dst;
+
+ file->private_data = *vctx;
+
+exit:
+ return ret;
+}
+
+int close_vctx(struct file *file,
+ struct fimc_is_video *video,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+
+ kfree(vctx->q_src);
+ kfree(vctx->q_dst);
+ kfree(vctx);
+ file->private_data = NULL;
+ ret = vref_put(video, NULL);
+
+ return ret;
+}
+
+/*
+ * =============================================================================
+ * Queue Opertation
+ * =============================================================================
+ */
+
+static int fimc_is_queue_open(struct fimc_is_queue *queue,
+ u32 rdycount)
+{
+ int ret = 0;
+
+ queue->buf_maxcount = 0;
+ queue->buf_refcount = 0;
+ queue->buf_rdycount = rdycount;
+ clear_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state);
+ memset(&queue->framecfg, 0, sizeof(struct fimc_is_frame_cfg));
+ fimc_is_frame_probe(&queue->framemgr, queue->id);
+
+ return ret;
+}
+
+static int fimc_is_queue_close(struct fimc_is_queue *queue)
+{
+ int ret = 0;
+
+ queue->buf_maxcount = 0;
+ queue->buf_refcount = 0;
+ clear_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state);
+ fimc_is_frame_close(&queue->framemgr);
+
+ return ret;
+}
+
+static int fimc_is_queue_set_format_mplane(struct fimc_is_queue *queue,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ u32 plane;
+ struct v4l2_pix_format_mplane *pix;
+ struct fimc_is_fmt *fmt;
+
+ pix = &format->fmt.pix_mp;
+ fmt = fimc_is_find_format(&pix->pixelformat, NULL, 0);
+ if (!fmt) {
+ err("pixel format is not found\n");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ queue->framecfg.format.pixelformat = fmt->pixelformat;
+ queue->framecfg.format.mbus_code = fmt->mbus_code;
+ queue->framecfg.format.num_planes = fmt->num_planes;
+ queue->framecfg.width = pix->width;
+ queue->framecfg.height = pix->height;
+
+ for (plane = 0; plane < fmt->num_planes; ++plane) {
+ if (pix->plane_fmt[plane].bytesperline) {
+ queue->framecfg.bytesperline[plane] =
+ pix->plane_fmt[plane].bytesperline;
+ queue->framecfg.width_stride[plane] =
+ pix->plane_fmt[plane].bytesperline - pix->width;
+ } else {
+ queue->framecfg.bytesperline[plane] = 0;
+ queue->framecfg.width_stride[plane] = 0;
+ }
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_queue_setup(struct fimc_is_queue *queue,
+ void *alloc_ctx,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ u32 ret = 0;
+ u32 plane;
+
+ BUG_ON(!queue);
+ BUG_ON(!alloc_ctx);
+ BUG_ON(!num_planes);
+ BUG_ON(!sizes);
+ BUG_ON(!allocators);
+
+ *num_planes = (unsigned int)(queue->framecfg.format.num_planes);
+ fimc_is_set_plane_size(&queue->framecfg, sizes);
+
+ for (plane = 0; plane < *num_planes; plane++) {
+ allocators[plane] = alloc_ctx;
+ queue->framecfg.size[plane] = sizes[plane];
+ mdbgv_vid("queue[%d] size : %d\n", plane, sizes[plane]);
+ }
+
+ return ret;
+}
+
+int fimc_is_queue_buffer_queue(struct fimc_is_queue *queue,
+ const struct fimc_is_vb2 *vb2,
+ struct vb2_buffer *vb)
+{
+ u32 ret = 0, i;
+ u32 index;
+ u32 ext_size;
+ u32 spare;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame *frame;
+
+ index = vb->v4l2_buf.index;
+ framemgr = &queue->framemgr;
+
+ BUG_ON(framemgr->id == FRAMEMGR_ID_INVALID);
+
+ for (i = 0; i < vb->num_planes; i++)
+ queue->buf_dva[index][i] = vb2->plane_addr(vb, i);
+
+ frame = &framemgr->frame[index];
+
+ /* uninitialized frame need to get info */
+ if (!test_bit(FRAME_INI_MEM, &frame->memory))
+ goto set_info;
+
+ /* plane count check */
+ if (frame->planes != vb->num_planes) {
+ err("plane count is changed(%08X != %08X)",
+ frame->planes, vb->num_planes);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* plane address check */
+ for (i = 0; i < frame->planes; i++) {
+ if (frame->dvaddr_buffer[i] != queue->buf_dva[index][i]) {
+ err("buffer %d plane %d is changed(%08X != %08X)",
+ index, i,
+ frame->dvaddr_buffer[i],
+ queue->buf_dva[index][i]);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ goto exit;
+
+set_info:
+ if (test_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state)) {
+ err("already prepared but new index(%d) is came", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ frame->vb = vb;
+ frame->planes = vb->num_planes;
+ spare = frame->planes - 1;
+
+ for (i = 0; i < frame->planes; i++) {
+ frame->dvaddr_buffer[i] = queue->buf_dva[index][i];
+#ifdef PRINT_BUFADDR
+ info("%04X %d.%d %08X\n", framemgr->id, index, i, frame->dvaddr_buffer[i]);
+#endif
+ }
+
+ if (framemgr->id & FRAMEMGR_ID_SHOT) {
+ ext_size = sizeof(struct camera2_shot_ext) - sizeof(struct camera2_shot);
+
+ /* Create Kvaddr for Metadata */
+ queue->buf_kva[index][spare] = vb2->plane_kvaddr(vb, spare);
+ if (!queue->buf_kva[index][spare]) {
+ err("plane_kvaddr is fail(%08X)", framemgr->id);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ frame->dvaddr_shot = queue->buf_dva[index][spare] + ext_size;
+ frame->kvaddr_shot = queue->buf_kva[index][spare] + ext_size;
+ frame->cookie_shot = (u32)vb2_plane_cookie(vb, spare);
+ frame->shot = (struct camera2_shot *)frame->kvaddr_shot;
+ frame->shot_ext = (struct camera2_shot_ext *)queue->buf_kva[index][spare];
+ frame->shot_size = queue->framecfg.size[spare] - ext_size;
+#ifdef MEASURE_TIME
+ frame->tzone = (struct timeval *)frame->shot_ext->timeZone;
+#endif
+ } else {
+ /* Create Kvaddr for frame sync */
+ queue->buf_kva[index][spare] = vb2->plane_kvaddr(vb, spare);
+ if (!queue->buf_kva[index][spare]) {
+ err("plane_kvaddr is fail(%08X)", framemgr->id);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ frame->stream = (struct camera2_stream *)queue->buf_kva[index][spare];
+ frame->stream->address = queue->buf_kva[index][spare];
+ frame->stream_size = queue->framecfg.size[spare];
+ }
+
+ set_bit(FRAME_INI_MEM, &frame->memory);
+
+ queue->buf_refcount++;
+
+ if (queue->buf_rdycount == queue->buf_refcount)
+ set_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+
+ if (queue->buf_maxcount == queue->buf_refcount)
+ set_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state);
+
+exit:
+ return ret;
+}
+
+void fimc_is_queue_wait_prepare(struct vb2_queue *vbq)
+{
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_video *video;
+
+ BUG_ON(!vbq);
+
+ vctx = vbq->drv_priv;
+ if (!vctx) {
+ err("vctx is NULL");
+ return;
+ }
+
+ video = vctx->video;
+ mutex_unlock(&video->lock);
+}
+
+void fimc_is_queue_wait_finish(struct vb2_queue *vbq)
+{
+ int ret = 0;
+ struct fimc_is_video_ctx *vctx;
+ struct fimc_is_video *video;
+
+ BUG_ON(!vbq);
+
+ vctx = vbq->drv_priv;
+ if (!vctx) {
+ err("vctx is NULL");
+ return;
+ }
+
+ video = vctx->video;
+ ret = mutex_lock_interruptible(&video->lock);
+ if (ret)
+ err("mutex_lock_interruptible is fail(%d)", ret);
+}
+
+int fimc_is_queue_start_streaming(struct fimc_is_queue *queue,
+ struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+
+ BUG_ON(!queue);
+ BUG_ON(!device);
+ BUG_ON(!subdev);
+ BUG_ON(!vctx);
+
+ if (test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ merr("already stream on(%ld)", vctx, queue->state);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state)) {
+ merr("buffer state is not ready(%ld)", vctx, queue->state);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = CALL_QOPS(queue, start_streaming, device, subdev, queue);
+ if (ret) {
+ merr("start_streaming is fail(%d)", vctx, ret);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ set_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_queue_stop_streaming(struct fimc_is_queue *queue,
+ struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+
+ BUG_ON(!queue);
+ BUG_ON(!device);
+ BUG_ON(!subdev);
+ BUG_ON(!vctx);
+
+ if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ merr("already stream off(%ld)", vctx, queue->state);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = CALL_QOPS(queue, stop_streaming, device, subdev, queue);
+ if (ret) {
+ merr("stop_streaming is fail(%d)", vctx, ret);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+p_err:
+ /* HACK: this state must be clear only if all ops was finished */
+ clear_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state);
+
+ return ret;
+}
+
+int fimc_is_video_probe(struct fimc_is_video *video,
+ char *video_name,
+ u32 video_number,
+ u32 vfl_dir,
+ struct fimc_is_mem *mem,
+ struct v4l2_device *v4l2_dev,
+ struct mutex *lock,
+ const struct v4l2_file_operations *fops,
+ const struct v4l2_ioctl_ops *ioctl_ops)
+{
+ int ret = 0;
+ u32 video_id;
+
+ vref_init(video);
+ mutex_init(&video->lock);
+ snprintf(video->vd.name, sizeof(video->vd.name), "%s", video_name);
+ video->id = video_number;
+ video->vb2 = mem->vb2;
+ video->alloc_ctx = mem->alloc_ctx;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0))
+ video->vd.vfl_dir = vfl_dir;
+#endif
+ video->vd.v4l2_dev = v4l2_dev;
+ video->vd.fops = fops;
+ video->vd.ioctl_ops = ioctl_ops;
+ video->vd.minor = -1;
+ video->vd.release = video_device_release;
+ video->vd.lock = lock;
+ video_set_drvdata(&video->vd, video);
+
+ video_id = EXYNOS_VIDEONODE_FIMC_IS + video_number;
+ ret = video_register_device(&video->vd,
+ VFL_TYPE_GRABBER,
+ (EXYNOS_VIDEONODE_FIMC_IS + video_number));
+ if (ret) {
+ err("Failed to register video device");
+ goto p_err;
+ }
+
+p_err:
+ info("[VID] %s(%d) is created\n", video_name, video_id);
+ return ret;
+}
+
+int fimc_is_video_open(struct fimc_is_video_ctx *vctx,
+ void *device,
+ u32 buf_rdycount,
+ struct fimc_is_video *video,
+ u32 video_type,
+ const struct vb2_ops *vb2_ops,
+ const struct fimc_is_queue_ops *src_qops,
+ const struct fimc_is_queue_ops *dst_qops)
+{
+ int ret = 0;
+ struct fimc_is_queue *q_src, *q_dst;
+
+ BUG_ON(!video);
+ BUG_ON(!video->vb2);
+ BUG_ON(!vb2_ops);
+
+ q_src = vctx->q_src;
+ q_dst = vctx->q_dst;
+ q_src->vbq = NULL;
+ q_dst->vbq = NULL;
+ q_src->qops = src_qops;
+ q_dst->qops = dst_qops;
+
+ vctx->type = video_type;
+ vctx->device = device;
+ vctx->video = video;
+ vctx->vb2_ops = vb2_ops;
+ vctx->mem_ops = video->vb2->ops;
+ mutex_init(&vctx->lock);
+
+ switch (video_type) {
+ case FIMC_IS_VIDEO_TYPE_OUTPUT:
+ fimc_is_queue_open(q_src, buf_rdycount);
+
+ q_src->vbq = kzalloc(sizeof(struct vb2_queue), GFP_KERNEL);
+ if (!q_src->vbq) {
+ err("kzalloc is fail");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ ret = queue_init(vctx, q_src->vbq, NULL);
+ if (ret) {
+ err("queue_init fail");
+ kfree(q_src->vbq);
+ goto p_err;
+ }
+ break;
+ case FIMC_IS_VIDEO_TYPE_CAPTURE:
+ fimc_is_queue_open(q_dst, buf_rdycount);
+
+ q_dst->vbq = kzalloc(sizeof(struct vb2_queue), GFP_KERNEL);
+ if (!q_dst->vbq) {
+ err("kzalloc is fail");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ ret = queue_init(vctx, NULL, q_dst->vbq);
+ if (ret) {
+ err("queue_init fail");
+ kfree(q_dst->vbq);
+ goto p_err;
+ }
+ break;
+ case FIMC_IS_VIDEO_TYPE_M2M:
+ fimc_is_queue_open(q_src, buf_rdycount);
+ fimc_is_queue_open(q_dst, buf_rdycount);
+
+ q_src->vbq = kzalloc(sizeof(struct vb2_queue), GFP_KERNEL);
+ if (!q_src->vbq) {
+ err("kzalloc is fail");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ q_dst->vbq = kzalloc(sizeof(struct vb2_queue), GFP_KERNEL);
+ if (!q_dst->vbq) {
+ err("kzalloc is fail");
+ kfree(q_src->vbq);
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ ret = queue_init(vctx, q_src->vbq, q_dst->vbq);
+ if (ret) {
+ err("queue_init fail");
+ kfree(q_src->vbq);
+ kfree(q_dst->vbq);
+ goto p_err;
+ }
+ break;
+ default:
+ merr("invalid type(%d)", vctx, video_type);
+ ret = -EINVAL;
+ break;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_video_close(struct fimc_is_video_ctx *vctx)
+{
+ int ret = 0;
+ u32 video_type;
+ struct fimc_is_queue *q_src, *q_dst;
+
+ BUG_ON(!vctx);
+
+ video_type = vctx->type;
+
+ q_src = vctx->q_src;
+ q_dst = vctx->q_dst;
+
+ switch (video_type) {
+ case FIMC_IS_VIDEO_TYPE_OUTPUT:
+ BUG_ON(!q_src->vbq);
+ fimc_is_queue_close(q_src);
+ vb2_queue_release(q_src->vbq);
+ kfree(q_src->vbq);
+ break;
+ case FIMC_IS_VIDEO_TYPE_CAPTURE:
+ BUG_ON(!q_dst->vbq);
+ fimc_is_queue_close(q_dst);
+ vb2_queue_release(q_dst->vbq);
+ kfree(q_dst->vbq);
+ break;
+ case FIMC_IS_VIDEO_TYPE_M2M:
+ BUG_ON(!q_src->vbq);
+ BUG_ON(!q_dst->vbq);
+ fimc_is_queue_close(q_src);
+ vb2_queue_release(q_src->vbq);
+ fimc_is_queue_close(q_dst);
+ vb2_queue_release(q_dst->vbq);
+ kfree(q_src->vbq);
+ kfree(q_dst->vbq);
+ break;
+ default:
+ merr("invalid type(%d)", vctx, video_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ /*
+ * vb2 release can call stop callback
+ * not if video node is not stream off
+ */
+ vctx->device = NULL;
+
+ return ret;
+}
+
+u32 fimc_is_video_poll(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct poll_table_struct *wait)
+{
+ u32 ret = 0;
+ u32 video_type = vctx->type;
+
+ switch (video_type) {
+ case FIMC_IS_VIDEO_TYPE_OUTPUT:
+ ret = vb2_poll(vctx->q_src->vbq, file, wait);
+ break;
+ case FIMC_IS_VIDEO_TYPE_CAPTURE:
+ ret = vb2_poll(vctx->q_dst->vbq, file, wait);
+ break;
+ case FIMC_IS_VIDEO_TYPE_M2M:
+ merr("video poll is not supported", vctx);
+ ret = -EINVAL;
+ break;
+ default:
+ merr("invalid type(%d)", vctx, video_type);
+ break;
+ }
+
+ return ret;
+}
+
+int fimc_is_video_mmap(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct vm_area_struct *vma)
+{
+ u32 ret = 0;
+ u32 video_type = vctx->type;
+
+ switch (video_type) {
+ case FIMC_IS_VIDEO_TYPE_OUTPUT:
+ ret = vb2_mmap(vctx->q_src->vbq, vma);
+ break;
+ case FIMC_IS_VIDEO_TYPE_CAPTURE:
+ ret = vb2_mmap(vctx->q_dst->vbq, vma);
+ break;
+ case FIMC_IS_VIDEO_TYPE_M2M:
+ merr("video mmap is not supported", vctx);
+ ret = -EINVAL;
+ break;
+ default:
+ merr("invalid type(%d)", vctx, video_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int fimc_is_video_reqbufs(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_requestbuffers *request)
+{
+ int ret = 0;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!request);
+
+ queue = GET_VCTX_QUEUE(vctx, request);
+
+ if (test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ err("video is stream on, not applied");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = vb2_reqbufs(queue->vbq, request);
+ if (ret) {
+ err("vb2_reqbufs is fail(%d)", ret);
+ goto p_err;
+ }
+
+ framemgr = &queue->framemgr;
+ queue->buf_maxcount = request->count;
+ if (queue->buf_maxcount == 0) {
+ queue->buf_refcount = 0;
+ clear_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+ clear_bit(FIMC_IS_QUEUE_BUFFER_PREPARED, &queue->state);
+ fimc_is_frame_close(framemgr);
+ } else {
+ if (queue->buf_maxcount < queue->buf_rdycount) {
+ err("buffer count is not invalid(%d < %d)",
+ queue->buf_maxcount, queue->buf_rdycount);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!queue->buf_rdycount)
+ set_bit(FIMC_IS_QUEUE_BUFFER_READY, &queue->state);
+
+ fimc_is_frame_open(framemgr, queue->buf_maxcount);
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_video_querybuf(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+
+ queue = GET_VCTX_QUEUE(vctx, buf);
+
+ ret = vb2_querybuf(queue->vbq, buf);
+
+ return ret;
+}
+
+int fimc_is_video_set_format_mplane(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!format);
+
+ queue = GET_VCTX_QUEUE(vctx, format);
+
+ ret = fimc_is_queue_set_format_mplane(queue, format);
+
+ mdbgv_vid("set_format(%d x %d)\n", queue->framecfg.width,
+ queue->framecfg.height);
+
+ return ret;
+}
+
+int fimc_is_video_qbuf(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+ struct vb2_queue *vbq;
+ struct vb2_buffer *vb;
+
+ BUG_ON(!file);
+ BUG_ON(!vctx);
+ BUG_ON(!buf);
+
+ buf->flags &= ~V4L2_BUF_FLAG_USE_SYNC;
+ queue = GET_VCTX_QUEUE(vctx, buf);
+ vbq = queue->vbq;
+
+ if (!vbq) {
+ merr("vbq is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (vbq->fileio) {
+ merr("file io in progress", vctx);
+ ret = -EBUSY;
+ goto p_err;
+ }
+
+ if (buf->type != queue->vbq->type) {
+ merr("buf type is invalid(%d != %d)", vctx,
+ buf->type, queue->vbq->type);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (buf->index >= vbq->num_buffers) {
+ merr("buffer index%d out of range", vctx, buf->index);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (buf->memory != vbq->memory) {
+ merr("invalid memory type%d", vctx, buf->memory);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ vb = vbq->bufs[buf->index];
+ if (!vb) {
+ merr("vb is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = vb2_qbuf(queue->vbq, buf);
+ if (ret) {
+ merr("vb2_qbuf is fail(index : %d, %d)", vctx, buf->index, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_video_dqbuf(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ u32 qcount;
+ bool blocking;
+ struct fimc_is_queue *queue;
+ struct fimc_is_framemgr *framemgr;
+
+ BUG_ON(!file);
+ BUG_ON(!vctx);
+ BUG_ON(!buf);
+
+ blocking = file->f_flags & O_NONBLOCK;
+ queue = GET_VCTX_QUEUE(vctx, buf);
+ framemgr = &queue->framemgr;
+
+ if (!queue->vbq) {
+ merr("vbq is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (buf->type != queue->vbq->type) {
+ merr("buf type is invalid(%d != %d)", vctx,
+ buf->type, queue->vbq->type);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ merr("queue is not streamon(%ld)", vctx, queue->state);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr_e_barrier_irq(framemgr, 0);
+ qcount = framemgr->frame_req_cnt +
+ framemgr->frame_pro_cnt +
+ framemgr->frame_com_cnt;
+ framemgr_x_barrier_irq(framemgr, 0);
+
+ if (qcount <= 0) {
+ /* HACK : this log is commented until timeout issue fixed */
+ /* merr("dqbuf can not be executed without qbuf(%d)", vctx, qcount); */
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = vb2_dqbuf(queue->vbq, buf, blocking);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_video_streamon(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+ struct vb2_queue *vbq;
+
+ BUG_ON(!file);
+ BUG_ON(!vctx);
+
+ queue = GET_QUEUE(vctx, type);
+ vbq = queue->vbq;
+ if (!vbq) {
+ merr("vbq is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (vbq->type != type) {
+ merr("invalid stream type(%d != %d)", vctx, vbq->type, type);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (vbq->streaming) {
+ merr("streamon: already streaming", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = vb2_streamon(vbq, type);
+
+p_err:
+ return ret;
+}
+
+int fimc_is_video_streamoff(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ u32 qcount;
+ struct fimc_is_queue *queue;
+ struct vb2_queue *vbq;
+ struct fimc_is_framemgr *framemgr;
+
+ BUG_ON(!file);
+ BUG_ON(!vctx);
+
+ queue = GET_QUEUE(vctx, type);
+ framemgr = &queue->framemgr;
+ vbq = queue->vbq;
+ if (!vbq) {
+ merr("vbq is NULL", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framemgr_e_barrier_irq(framemgr, 0);
+ qcount = framemgr->frame_req_cnt +
+ framemgr->frame_pro_cnt +
+ framemgr->frame_com_cnt;
+ framemgr_x_barrier_irq(framemgr, 0);
+
+ if (qcount > 0)
+ mwarn("video%d stream off : queued buffer is not empty(%d)", vctx,
+ vctx->video->id, qcount);
+
+ if (vbq->type != type) {
+ merr("invalid stream type(%d != %d)", vctx, vbq->type, type);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!vbq->streaming) {
+ merr("streamoff: not streaming", vctx);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = vb2_streamoff(vbq, type);
+
+p_err:
+ return ret;
+}
+
+int queue_done(struct fimc_is_video_ctx *vctx,
+ struct fimc_is_queue *queue,
+ u32 index, u32 state)
+{
+ int ret = 0;
+ struct vb2_buffer *vb;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+ BUG_ON(!queue);
+ BUG_ON(!queue->vbq);
+ BUG_ON(index >= FRAMEMGR_MAX_REQUEST);
+
+ vb = queue->vbq->bufs[index];
+
+ if (!test_bit(FIMC_IS_QUEUE_STREAM_ON, &queue->state)) {
+ warn("%d video queue is not stream on", vctx->video->id);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (vb->state != VB2_BUF_STATE_ACTIVE) {
+ err("vb buffer[%d] state is not active(%d)", index, vb->state);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ vb2_buffer_done(vb, state);
+
+p_err:
+ return ret;
+}
+
+int buffer_done(struct fimc_is_video_ctx *vctx, u32 index)
+{
+ int ret = 0;
+ struct fimc_is_queue *queue;
+
+ BUG_ON(!vctx);
+ BUG_ON(!vctx->video);
+ BUG_ON(index >= FRAMEMGR_MAX_REQUEST);
+ BUG_ON(vctx->type == FIMC_IS_VIDEO_TYPE_M2M);
+
+ switch (vctx->type) {
+ case FIMC_IS_VIDEO_TYPE_OUTPUT:
+ queue = GET_SRC_QUEUE(vctx);
+ queue_done(vctx, queue, index, VB2_BUF_STATE_DONE);
+ break;
+ case FIMC_IS_VIDEO_TYPE_CAPTURE:
+ queue = GET_DST_QUEUE(vctx);
+ queue_done(vctx, queue, index, VB2_BUF_STATE_DONE);
+ break;
+ default:
+ merr("invalid type(%d)", vctx, vctx->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
--- /dev/null
+#ifndef FIMC_IS_VIDEO_H
+#define FIMC_IS_VIDEO_H
+
+#include <linux/version.h>
+#include <media/v4l2-ioctl.h>
+#include "fimc-is-type.h"
+#include "fimc-is-mem.h"
+#include "fimc-is-framemgr.h"
+#include "fimc-is-metadata.h"
+#include "fimc-is-config.h"
+
+/* configuration by linux kernel version */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
+#define VFL_DIR_RX 0
+#define VFL_DIR_TX 1
+#define VFL_DIR_M2M 2
+#endif
+
+#define FIMC_IS_MAX_NODES (3)
+#define FIMC_IS_INVALID_BUF_INDEX (0xFF)
+
+#define VIDEO_SENSOR_READY_BUFFERS 0
+#define VIDEO_3AA_READY_BUFFERS 0
+#define VIDEO_3AAC_READY_BUFFERS 0
+#define VIDEO_3AAP_READY_BUFFERS 0
+#define VIDEO_ISP_READY_BUFFERS 0
+#define VIDEO_SCC_READY_BUFFERS 0
+#define VIDEO_SCP_READY_BUFFERS 0
+#define VIDEO_VDISC_READY_BUFFERS 1
+#define VIDEO_VDISO_READY_BUFFERS 0
+
+#define FIMC_IS_VIDEO_NAME(name) ("exynos-fimc-is-"name)
+#define FIMC_IS_VIDEO_SENSOR_NAME FIMC_IS_VIDEO_NAME("sensor")
+#define FIMC_IS_VIDEO_3AA_NAME(id) FIMC_IS_VIDEO_NAME("3aa."#id)
+#define FIMC_IS_VIDEO_3AAC_NAME(id) FIMC_IS_VIDEO_NAME("3aa."#id"c")
+#define FIMC_IS_VIDEO_3AAP_NAME(id) FIMC_IS_VIDEO_NAME("3aa."#id"p")
+#define FIMC_IS_VIDEO_ISP_NAME FIMC_IS_VIDEO_NAME("isp")
+#define FIMC_IS_VIDEO_SCC_NAME FIMC_IS_VIDEO_NAME("scalerc")
+#define FIMC_IS_VIDEO_SCP_NAME FIMC_IS_VIDEO_NAME("scalerp")
+#define FIMC_IS_VIDEO_VDC_NAME FIMC_IS_VIDEO_NAME("vdisc")
+#define FIMC_IS_VIDEO_VDO_NAME FIMC_IS_VIDEO_NAME("vdiso")
+
+struct fimc_is_device_ischain;
+struct fimc_is_subdev;
+struct fimc_is_queue;
+
+enum fimc_is_video_dev_num {
+ FIMC_IS_VIDEO_SS0_NUM = 0,
+ FIMC_IS_VIDEO_SS1_NUM = 1,
+ FIMC_IS_VIDEO_SS2_NUM = 2,
+ FIMC_IS_VIDEO_SS3_NUM = 3,
+ FIMC_IS_VIDEO_3A0_NUM = 10,
+ FIMC_IS_VIDEO_3A0C_NUM = 11,
+ FIMC_IS_VIDEO_3A0P_NUM = 12,
+ FIMC_IS_VIDEO_3A1_NUM = 14,
+ FIMC_IS_VIDEO_3A1C_NUM = 15,
+ FIMC_IS_VIDEO_3A1P_NUM = 16,
+ FIMC_IS_VIDEO_ISP_NUM = 30,
+ FIMC_IS_VIDEO_SCC_NUM = 34,
+ FIMC_IS_VIDEO_SCP_NUM = 37,
+ FIMC_IS_VIDEO_VDC_NUM = 40,
+ FIMC_IS_VIDEO_VDO_NUM = 41,
+ FIMC_IS_VIDEO_FD_NUM = 46,
+ FIMC_IS_VIDEO_MAX_NUM = 49
+};
+
+enum fimc_is_video_type {
+ FIMC_IS_VIDEO_TYPE_CAPTURE,
+ FIMC_IS_VIDEO_TYPE_OUTPUT,
+ FIMC_IS_VIDEO_TYPE_M2M,
+};
+
+enum fimc_is_queue_state {
+ FIMC_IS_QUEUE_BUFFER_PREPARED,
+ FIMC_IS_QUEUE_BUFFER_READY,
+ FIMC_IS_QUEUE_STREAM_ON
+};
+
+struct fimc_is_frame_cfg {
+ struct fimc_is_fmt format;
+ u32 width;
+ u32 height;
+ u32 width_stride[FIMC_IS_MAX_PLANES];
+ u32 size[FIMC_IS_MAX_PLANES];
+ u32 bytesperline[FIMC_IS_MAX_PLANES];
+};
+
+struct fimc_is_queue_ops {
+ int (*start_streaming)(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+ int (*stop_streaming)(struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_queue *queue);
+};
+
+struct fimc_is_queue {
+ struct vb2_queue *vbq;
+ const struct fimc_is_queue_ops *qops;
+ struct fimc_is_framemgr framemgr;
+ struct fimc_is_frame_cfg framecfg;
+
+ u32 buf_maxcount;
+ u32 buf_rdycount;
+ u32 buf_refcount;
+ u32 buf_dva[FIMC_IS_MAX_BUFS][FIMC_IS_MAX_PLANES];
+ u32 buf_kva[FIMC_IS_MAX_BUFS][FIMC_IS_MAX_PLANES];
+
+ u32 id;
+ unsigned long state;
+};
+
+struct fimc_is_video_ctx {
+ struct fimc_is_queue *q_src;
+ struct fimc_is_queue *q_dst;
+ struct mutex lock;
+ u32 type;
+ u32 instance;
+
+ void *device;
+ struct fimc_is_video *video;
+
+ const struct vb2_ops *vb2_ops;
+ const struct vb2_mem_ops *mem_ops;
+};
+
+struct fimc_is_video {
+ u32 id;
+ atomic_t refcount;
+ struct mutex lock;
+
+ struct video_device vd;
+ struct media_pad pads;
+ const struct fimc_is_vb2 *vb2;
+ void *alloc_ctx;
+};
+
+struct fimc_is_core *fimc_is_video_ctx_2_core(struct fimc_is_video_ctx *vctx);
+
+/* video context operation */
+int open_vctx(struct file *file,
+ struct fimc_is_video *video,
+ struct fimc_is_video_ctx **vctx,
+ u32 id_src, u32 id_dst);
+int close_vctx(struct file *file,
+ struct fimc_is_video *video,
+ struct fimc_is_video_ctx *vctx);
+
+/* queue operation */
+int fimc_is_queue_setup(struct fimc_is_queue *queue,
+ void *alloc_ctx,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[]);
+int fimc_is_queue_buffer_queue(struct fimc_is_queue *queue,
+ const struct fimc_is_vb2 *vb2,
+ struct vb2_buffer *vb);
+void fimc_is_queue_wait_prepare(struct vb2_queue *vbq);
+void fimc_is_queue_wait_finish(struct vb2_queue *vbq);
+int fimc_is_queue_start_streaming(struct fimc_is_queue *queue,
+ struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_video_ctx *vctx);
+int fimc_is_queue_stop_streaming(struct fimc_is_queue *queue,
+ struct fimc_is_device_ischain *device,
+ struct fimc_is_subdev *subdev,
+ struct fimc_is_video_ctx *vctx);
+
+/* video operation */
+int fimc_is_video_probe(struct fimc_is_video *video,
+ char *video_name,
+ u32 video_number,
+ u32 vfl_dir,
+ struct fimc_is_mem *mem,
+ struct v4l2_device *v4l2_dev,
+ struct mutex *lock,
+ const struct v4l2_file_operations *fops,
+ const struct v4l2_ioctl_ops *ioctl_ops);
+int fimc_is_video_open(struct fimc_is_video_ctx *vctx,
+ void *device,
+ u32 buf_rdycount,
+ struct fimc_is_video *video,
+ u32 video_type,
+ const struct vb2_ops *vb2_ops,
+ const struct fimc_is_queue_ops *src_qops,
+ const struct fimc_is_queue_ops *dst_qops);
+int fimc_is_video_close(struct fimc_is_video_ctx *vctx);
+u32 fimc_is_video_poll(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct poll_table_struct *wait);
+int fimc_is_video_mmap(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct vm_area_struct *vma);
+int fimc_is_video_reqbufs(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_requestbuffers *request);
+int fimc_is_video_querybuf(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_buffer *buf);
+int fimc_is_video_set_format_mplane(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_format *format);
+int fimc_is_video_qbuf(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_buffer *buf);
+int fimc_is_video_dqbuf(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ struct v4l2_buffer *buf);
+int fimc_is_video_streamon(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ enum v4l2_buf_type type);
+int fimc_is_video_streamoff(struct file *file,
+ struct fimc_is_video_ctx *vctx,
+ enum v4l2_buf_type type);
+
+int queue_done(struct fimc_is_video_ctx *vctx,
+ struct fimc_is_queue *queue,
+ u32 index, u32 state);
+int buffer_done(struct fimc_is_video_ctx *vctx, u32 index);
+long video_ioctl3(struct file *file, unsigned int cmd, unsigned long arg);
+
+#define GET_QUEUE(vctx, type) \
+ (V4L2_TYPE_IS_OUTPUT((type)) ? vctx->q_src : vctx->q_dst)
+#define GET_VCTX_QUEUE(vctx, vbq) (GET_QUEUE(vctx, vbq->type))
+
+#define GET_SRC_QUEUE(vctx) (vctx->q_src)
+#define GET_DST_QUEUE(vctx) (vctx->q_dst)
+
+#define GET_SRC_FRAMEMGR(vctx) (&vctx->q_src->framemgr)
+#define GET_DST_FRAMEMGR(vctx) (&vctx->q_dst->framemgr)
+
+#define CALL_QOPS(q, op, args...) (((q)->qops->op) ? ((q)->qops->op(args)) : 0)
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-2p2.h"
+
+#define SENSOR_NAME "S5K2P2"
+
+static struct fimc_is_sensor_cfg config_2p2[] = {
+ /* 5328x3000@30fps */
+ FIMC_IS_SENSOR_CFG(5328, 3000, 30, 30, 0),
+ /* 5328x3000@24fps */
+ FIMC_IS_SENSOR_CFG(5328, 3000, 24, 30, 1),
+ /* 4000X3000@30fps */
+ FIMC_IS_SENSOR_CFG(4000, 3000, 30, 23, 2),
+ /* 4000X3000@24fps */
+ FIMC_IS_SENSOR_CFG(4000, 3000, 24, 23, 3),
+ /* 3008X3000@30fps */
+ FIMC_IS_SENSOR_CFG(3008, 3000, 30, 19, 4),
+ /* 3008X3000@30fps */
+ FIMC_IS_SENSOR_CFG(3008, 3000, 24, 19, 5),
+ /* 2664X1500@60fps */
+ FIMC_IS_SENSOR_CFG(2664, 1500, 60, 19, 6),
+ /* 1328X748@120fps */
+ FIMC_IS_SENSOR_CFG(1328, 748, 120, 13, 7),
+ /* 824X496@300fps */
+ FIMC_IS_SENSOR_CFG(824, 496, 300, 13, 8),
+};
+
+static int sensor_2p2_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_2p2_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+#ifdef CONFIG_OF
+#ifdef CONFIG_COMPANION_USE
+static int sensor_2p2_power_setpin(struct device *dev)
+{
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ int gpio_comp_en = 0, gpio_comp_rst = 0;
+ int gpio_none = 0;
+ int gpio_reset = 0;
+ int gpios_cam_en = -EINVAL;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_comp_en = of_get_named_gpio(dnode, "gpios_comp_en", 0);
+ if (!gpio_is_valid(gpio_comp_en)) {
+ dev_err(dev, "failed to get main comp en gpio\n");
+ } else {
+ gpio_request_one(gpio_comp_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_comp_en);
+ }
+
+ gpio_comp_rst = of_get_named_gpio(dnode, "gpios_comp_reset", 0);
+ if (!gpio_is_valid(gpio_comp_rst)) {
+ dev_err(dev, "failed to get main comp reset gpio\n");
+ } else {
+ gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_comp_rst);
+ }
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ dev_err(dev, "failed to get PIN_RESET\n");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ gpios_cam_en = of_get_named_gpio(dnode, "gpios_cam_en", 0);
+ if (!gpio_is_valid(gpios_cam_en)) {
+ dev_err(dev, "failed to get main/front cam en gpio\n");
+ } else {
+ gpio_request_one(gpios_cam_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_cam_en);
+ }
+
+ /* COMPANION - POWER ON */
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_none, 0, "VDDA_1.8V_COMP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_comp_en, 0, NULL, 150, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_comp_rst, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 7, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 8, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 9, gpio_none, 0, "af", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 10, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* COMPANION - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_comp_rst, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_comp_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VDDA_1.8V_COMP", 0, PIN_REGULATOR_OFF);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 7, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 8, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 9, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+#else
+static int sensor_2p2_power_setpin(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_COMPANION_USE */
+#endif /* CONFIG_OF */
+
+int sensor_2p2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_2P2_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K2P2;
+ module->subdev = subdev_module;
+ module->device = SENSOR_2P2_INSTANCE;
+ module->client = client;
+ module->active_width = 5312;
+ module->active_height = 2990;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 300;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K2P2";
+ module->setfile_name = "setfile_2p2.bin";
+ module->cfgs = ARRAY_SIZE(config_2p2);
+ module->cfg = config_2p2;
+ module->ops = NULL;
+ module->private_data = NULL;
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_2p2_power_setpin;
+#endif
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = SENSOR_NAME_S5K2P2;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x5A;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7345;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x5A;
+ ext->actuator_con.peri_setting.i2c.speed = 400000;
+
+#ifdef CONFIG_LEDS_MAX77804
+ ext->flash_con.product_name = FLADRV_NAME_MAX77693;
+#endif
+#if defined(CONFIG_LEDS_LM3560) || !defined(CONFIG_USE_VENDER_FEATURE)
+ ext->flash_con.product_name = FLADRV_NAME_LM3560;
+#endif
+#ifdef CONFIG_LEDS_SKY81296
+ ext->flash_con.product_name = FLADRV_NAME_SKY81296;
+#endif
+ ext->flash_con.peri_type = SE_GPIO;
+#ifdef CONFIG_USE_VENDER_FEATURE
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 1;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 2;
+#else
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 2;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 3;
+#endif
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+#ifdef CONFIG_COMPANION_USE
+ ext->companion_con.product_name = COMPANION_NAME_73C1;
+ ext->companion_con.peri_info0.valid = true;
+ ext->companion_con.peri_info0.peri_type = SE_SPI;
+ ext->companion_con.peri_info0.peri_setting.spi.channel = (int) core->companion_spi_channel;
+ ext->companion_con.peri_info1.valid = true;
+ ext->companion_con.peri_info1.peri_type = SE_I2C;
+ ext->companion_con.peri_info1.peri_setting.i2c.channel = 0;
+ ext->companion_con.peri_info1.peri_setting.i2c.slave_address = 0x7A;
+ ext->companion_con.peri_info1.peri_setting.i2c.speed = 400000;
+ ext->companion_con.peri_info2.valid = true;
+ ext->companion_con.peri_info2.peri_type = SE_FIMC_LITE;
+ ext->companion_con.peri_info2.peri_setting.fimc_lite.channel = FLITE_ID_D;
+#else
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+#endif
+
+#if defined(CONFIG_OIS_USE)
+ ext->ois_con.product_name = OIS_NAME_IDG2030;
+ ext->ois_con.peri_type = SE_I2C;
+ ext->ois_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->ois_con.peri_setting.i2c.slave_address = 0x48;
+ ext->ois_con.peri_setting.i2c.speed = 400000;
+#else
+ ext->ois_con.product_name = OIS_NAME_NOTHING;
+ ext->ois_con.peri_type = SE_NULL;
+#endif
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_2P2_H
+#define FIMC_IS_DEVICE_2P2_H
+
+#define SENSOR_2P2_INSTANCE 0
+#define SENSOR_2P2_NAME SENSOR_NAME_S5K2P2
+
+int sensor_2p2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-2p2_12m.h"
+
+#define SENSOR_NAME "S5K2P2_12M"
+
+static struct fimc_is_sensor_cfg config_2p2_12m[] = {
+ /* 4624x2604@30fps */
+ FIMC_IS_SENSOR_CFG(4624, 2604, 30, 22, 0),
+ /* 4624x2604@24fps */
+ FIMC_IS_SENSOR_CFG(4624, 2604, 24, 21, 1),
+ /* 3472X2604@30fps */
+ FIMC_IS_SENSOR_CFG(3472, 2604, 30, 17, 2),
+ /* 3472X2604@24fps */
+ FIMC_IS_SENSOR_CFG(3472, 2604, 24, 17, 3),
+ /* 2608X2604@30fps */
+ FIMC_IS_SENSOR_CFG(2608, 2604, 30, 17, 4),
+ /* 2608X2604@24fps */
+ FIMC_IS_SENSOR_CFG(2608, 2604, 24, 17, 5),
+ /* 2312X1300@60fps */
+ FIMC_IS_SENSOR_CFG(2312, 1300, 60, 13, 6),
+ /* 2312X1300@30fps */
+ FIMC_IS_SENSOR_CFG(2312, 1300, 30, 13, 7),
+ /* 1156X650@120fps */
+ FIMC_IS_SENSOR_CFG(1156, 650, 120, 13, 8),
+};
+
+static int sensor_2p2_12m_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_2p2_12m_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+#ifdef CONFIG_OF
+#ifdef CONFIG_COMPANION_USE
+static int sensor_2p2_12m_power_setpin(struct device *dev)
+{
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ int gpio_comp_en = 0, gpio_comp_rst = 0;
+ int gpio_none = 0;
+ int gpio_reset = 0;
+ int gpios_cam_en = -EINVAL;
+#ifdef CONFIG_OIS_USE
+ int gpios_ois_en = 0;
+#endif
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_comp_en = of_get_named_gpio(dnode, "gpios_comp_en", 0);
+ if (!gpio_is_valid(gpio_comp_en)) {
+ dev_err(dev, "failed to get main comp en gpio\n");
+ } else {
+ gpio_request_one(gpio_comp_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_comp_en);
+ }
+
+ gpio_comp_rst = of_get_named_gpio(dnode, "gpios_comp_reset", 0);
+ if (!gpio_is_valid(gpio_comp_rst)) {
+ dev_err(dev, "failed to get main comp reset gpio\n");
+ } else {
+ gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_comp_rst);
+ }
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ dev_err(dev, "failed to get PIN_RESET\n");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ if (of_get_property(dnode, "gpios_cam_en", NULL)) {
+ gpios_cam_en = of_get_named_gpio(dnode, "gpios_cam_en", 0);
+ if (!gpio_is_valid(gpios_cam_en)) {
+ dev_err(dev, "failed to get main cam en gpio\n");
+ } else {
+ gpio_request_one(gpios_cam_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_cam_en);
+ }
+ }
+
+#ifdef CONFIG_OIS_USE
+ gpios_ois_en = of_get_named_gpio(dnode, "gpios_ois_en", 0);
+ pdata->pin_ois_en = gpios_ois_en;
+ if (!gpio_is_valid(gpios_ois_en)) {
+ dev_err(dev, "failed to get ois en gpio\n");
+ } else {
+ gpio_request_one(gpios_ois_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_ois_en);
+ }
+#endif
+
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_ON);
+#ifdef CONFIG_OIS_USE
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_ON);
+#endif
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_none, 0, "VDDA_1.8V_COMP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 7, gpio_comp_en, 0, NULL, 150, PIN_OUTPUT_HIGH);
+ if (pdata->companion_use_pmic) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 8, gpio_none, 0, "VDD_MIPI_1.0V_COMP", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 9, gpio_comp_rst, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 10, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 11, gpio_none, 0, "af", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 12, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 13, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* BACK CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_comp_rst, 0, NULL, 0, PIN_OUTPUT_LOW);
+ if (pdata->companion_use_pmic) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VDD_MIPI_1.0V_COMP", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_comp_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, "VDDA_1.8V_COMP", 0, PIN_REGULATOR_OFF);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 7, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 7, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 8, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 9, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_OFF);
+#ifdef CONFIG_OIS_USE
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 10, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 11, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_OFF);
+#endif
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 12, gpio_none, 0, NULL, 0, PIN_END);
+
+#ifdef CONFIG_OIS_USE
+ /* OIS_FACTORY - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 1, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 2, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 3, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 4, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 5, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* OIS_FACTORY - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 1, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 2, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 3, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 5, gpio_none, 0, NULL, 0, PIN_END);
+#endif
+
+ return 0;
+}
+#else
+static int sensor_2p2_12m_power_setpin(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_COMPANION_USE */
+#endif /* CONFIG_OF */
+
+
+int sensor_2p2_12m_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_2P2_12M_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K2P2_12M;
+ module->subdev = subdev_module;
+ module->device = SENSOR_2P2_12M_INSTANCE;
+ module->client = client;
+ module->active_width = 4608;
+ module->active_height = 2594;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 300;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K2P2";
+ module->setfile_name = "setfile_2p2_12m.bin";
+ module->cfgs = ARRAY_SIZE(config_2p2_12m);
+ module->cfg = config_2p2_12m;
+ module->ops = NULL;
+ module->private_data = NULL;
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_2p2_12m_power_setpin;
+#endif
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = SENSOR_NAME_S5K2P2_12M;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x5A;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7345;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x5A;
+ ext->actuator_con.peri_setting.i2c.speed = 400000;
+
+#ifdef CONFIG_LEDS_MAX77804
+ ext->flash_con.product_name = FLADRV_NAME_MAX77693;
+#endif
+#if defined(CONFIG_LEDS_LM3560) || !defined(CONFIG_USE_VENDER_FEATURE)
+ ext->flash_con.product_name = FLADRV_NAME_LM3560;
+#endif
+#ifdef CONFIG_LEDS_SKY81296
+ ext->flash_con.product_name = FLADRV_NAME_SKY81296;
+#endif
+ ext->flash_con.peri_type = SE_GPIO;
+#ifdef CONFIG_USE_VENDER_FEATURE
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 1;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 2;
+#else
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 2;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 3;
+#endif
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+#ifdef CONFIG_COMPANION_USE
+ ext->companion_con.product_name = COMPANION_NAME_73C1;
+ ext->companion_con.peri_info0.valid = true;
+ ext->companion_con.peri_info0.peri_type = SE_SPI;
+ ext->companion_con.peri_info0.peri_setting.spi.channel = (int) core->companion_spi_channel;
+ ext->companion_con.peri_info1.valid = true;
+ ext->companion_con.peri_info1.peri_type = SE_I2C;
+ ext->companion_con.peri_info1.peri_setting.i2c.channel = 0;
+ ext->companion_con.peri_info1.peri_setting.i2c.slave_address = 0x7A;
+ ext->companion_con.peri_info1.peri_setting.i2c.speed = 400000;
+ ext->companion_con.peri_info2.valid = true;
+ ext->companion_con.peri_info2.peri_type = SE_FIMC_LITE;
+ ext->companion_con.peri_info2.peri_setting.fimc_lite.channel = FLITE_ID_D;
+#else
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+#endif
+
+ if (client) {
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ } else {
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+ }
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_2P2_12M_H
+#define FIMC_IS_DEVICE_2P2_12M_H
+
+#define SENSOR_2P2_12M_INSTANCE 0
+#define SENSOR_2P2_12M_NAME SENSOR_NAME_S5K2P2_12M
+
+int sensor_2p2_12m_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-2p3.h"
+
+#define SENSOR_NAME "S5K2P3"
+
+static struct fimc_is_sensor_cfg config_2p3[] = {
+ /* 5328x3000@30fps */
+ FIMC_IS_SENSOR_CFG(5328, 3000, 30, 30, 0),
+ /* 5328x3000@24fps */
+ FIMC_IS_SENSOR_CFG(5328, 3000, 24, 24, 1),
+ /* 4000X3000@30fps */
+ FIMC_IS_SENSOR_CFG(4000, 3000, 30, 23, 2),
+ /* 4000X3000@24fps */
+ FIMC_IS_SENSOR_CFG(4000, 3000, 24, 19, 3),
+ /* 3008X3000@30fps */
+ FIMC_IS_SENSOR_CFG(3008, 3000, 30, 19, 4),
+ /* 3008X3000@30fps */
+ FIMC_IS_SENSOR_CFG(3008, 3000, 24, 14, 5),
+ /* 2664X1500@60fps */
+ FIMC_IS_SENSOR_CFG(2664, 1500, 60, 19, 6),
+ /* 1328X748@120fps */
+ FIMC_IS_SENSOR_CFG(1328, 748, 120, 13, 7),
+ /* 824X496@300fps */
+/* FIMC_IS_SENSOR_CFG(824, 496, 300, 13, 8), TODO: Temporary Disabled. */
+};
+
+static int sensor_2p3_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_2p3_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+#ifdef CONFIG_OF
+static int sensor_2p3_power_setpin(struct device *dev)
+{
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ int gpio_none = 0;
+ int gpio_reset = 0;
+ int gpios_cam_en = -EINVAL;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ dev_err(dev, "failed to get PIN_RESET\n");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ gpios_cam_en = of_get_named_gpio(dnode, "gpios_cam_en", 0);
+ if (!gpio_is_valid(gpios_cam_en)) {
+ dev_err(dev, "failed to get main/front cam en gpio\n");
+ } else {
+ gpio_request_one(gpios_cam_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_cam_en);
+ }
+
+ /* POWER ON */
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 7, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 8, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 9, gpio_none, 0, "af", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 10, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 7, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 8, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 9, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+int sensor_2p3_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_2P3_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K2P3;
+ module->subdev = subdev_module;
+ module->device = SENSOR_2P3_INSTANCE;
+ module->client = client;
+ module->active_width = 5312;
+ module->active_height = 2990;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 300;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K2P3";
+ module->setfile_name = "setfile_2p3.bin";
+ module->cfgs = ARRAY_SIZE(config_2p3);
+ module->cfg = config_2p3;
+ module->ops = NULL;
+ module->private_data = NULL;
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_2p3_power_setpin;
+#endif
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = SENSOR_NAME_S5K2P3;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x20;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7345;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x20;
+ ext->actuator_con.peri_setting.i2c.speed = 400000;
+
+#ifdef CONFIG_LEDS_MAX77804
+ ext->flash_con.product_name = FLADRV_NAME_MAX77693;
+#endif
+#if defined(CONFIG_LEDS_LM3560) || !defined(CONFIG_USE_VENDER_FEATURE)
+ ext->flash_con.product_name = FLADRV_NAME_LM3560;
+#endif
+#ifdef CONFIG_LEDS_SKY81296
+ ext->flash_con.product_name = FLADRV_NAME_SKY81296;
+#endif
+ ext->flash_con.peri_type = SE_GPIO;
+#ifdef CONFIG_USE_VENDER_FEATURE
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 1;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 2;
+#else
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 2;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 3;
+#endif
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+#ifdef CONFIG_COMPANION_USE
+ ext->companion_con.product_name = COMPANION_NAME_73C1;
+ ext->companion_con.peri_info0.valid = true;
+ ext->companion_con.peri_info0.peri_type = SE_SPI;
+ ext->companion_con.peri_info0.peri_setting.spi.channel = (int) core->companion_spi_channel;
+ ext->companion_con.peri_info1.valid = true;
+ ext->companion_con.peri_info1.peri_type = SE_I2C;
+ ext->companion_con.peri_info1.peri_setting.i2c.channel = 0;
+ ext->companion_con.peri_info1.peri_setting.i2c.slave_address = 0x7A;
+ ext->companion_con.peri_info1.peri_setting.i2c.speed = 400000;
+ ext->companion_con.peri_info2.valid = true;
+ ext->companion_con.peri_info2.peri_type = SE_FIMC_LITE;
+ ext->companion_con.peri_info2.peri_setting.fimc_lite.channel = FLITE_ID_D;
+#else
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+#endif
+
+#if defined(CONFIG_OIS_USE)
+ ext->ois_con.product_name = OIS_NAME_IDG2030;
+ ext->ois_con.peri_type = SE_I2C;
+ ext->ois_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->ois_con.peri_setting.i2c.slave_address = 0x48;
+ ext->ois_con.peri_setting.i2c.speed = 400000;
+#else
+ ext->ois_con.product_name = OIS_NAME_NOTHING;
+ ext->ois_con.peri_type = SE_NULL;
+#endif
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_2P3_H
+#define FIMC_IS_DEVICE_2P3_H
+
+#define SENSOR_2P3_INSTANCE 0
+#define SENSOR_2P3_NAME SENSOR_NAME_S5K2P3
+
+int sensor_2p3_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-3h5.h"
+
+#define SENSOR_NAME "S5K3H5"
+
+static struct fimc_is_sensor_cfg config_3h5[] = {
+ /* 3264x2448@30fps */
+ FIMC_IS_SENSOR_CFG(3264, 2448, 30, 15, 0),
+};
+
+static int sensor_3h5_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_3h5_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_3h5_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K3H5_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K3H5;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K3H5_INSTANCE;
+ module->client = client;
+ module->active_width = 3248;
+ module->active_height = 2438;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K3H5";
+ module->setfile_name = "setfile_3h5.bin";
+ module->cfgs = ARRAY_SIZE(config_3h5);
+ module->cfg = config_3h5;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = 0;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x5A;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_HYBRIDVCA;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+
+ ext->flash_con.product_name = FLADRV_NAME_AAT1290A; /* == FLADRV_NAME_AAT1274 */
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 6;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 8;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_3H5_H
+#define FIMC_IS_DEVICE_3H5_H
+
+#define SENSOR_S5K3H5_INSTANCE 0
+#define SENSOR_S5K3H5_NAME SENSOR_NAME_S5K3H5
+
+int sensor_3h5_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-3h7.h"
+
+#define SENSOR_NAME "S5K3H7"
+
+static struct fimc_is_sensor_cfg config_3h7[] = {
+ /* 3280x2458@30fps */
+ FIMC_IS_SENSOR_CFG(3280, 2458, 30, 15, 0),
+};
+
+static int sensor_3h7_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_3h7_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_3h7_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K3H7_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K3H7;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K3H7_INSTANCE;
+ module->client = client;
+ module->active_width = 3248;
+ module->active_height = 2438;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K3H7";
+ module->setfile_name = "setfile_3h7.bin";
+ module->cfgs = ARRAY_SIZE(config_3h7);
+ module->cfg = config_3h7;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = 0;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x20;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7343;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+
+ ext->flash_con.product_name = FLADRV_NAME_KTD267;
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 17;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 16;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_3H7_H
+#define FIMC_IS_DEVICE_3H7_H
+
+#define SENSOR_S5K3H7_INSTANCE 0
+#define SENSOR_S5K3H7_NAME SENSOR_NAME_S5K3H7
+
+int sensor_3h7_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-3h7_sunny.h"
+
+#define SENSOR_NAME "S5K3H7_SUNNY"
+
+static struct fimc_is_sensor_cfg config_3h7_sunny[] = {
+ /* 3264x2448@30fps */
+ FIMC_IS_SENSOR_CFG(3264, 2448, 30, 15, 0),
+};
+
+static int sensor_3h7_sunny_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_3h7_sunny_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_3h7_sunny_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K3H7_SUNNY_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K3H7_SUNNY;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K3H7_SUNNY_INSTANCE;
+ module->client = client;
+ module->active_width = 3248;
+ module->active_height = 2438;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K3H7";
+ module->setfile_name = "setfile_3h7_sunny.bin";
+ module->cfgs = ARRAY_SIZE(config_3h7_sunny);
+ module->cfg = config_3h7_sunny;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = 0;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x20;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_DWXXXX;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x20;
+ ext->actuator_con.peri_setting.i2c.speed = 400000;
+
+#if defined(CONFIG_EXYNOS5260_XYREF_REV0)
+ ext->flash_con.product_name = FLADRV_NAME_NOTHING;
+#else
+ ext->flash_con.product_name = FLADRV_NAME_AS3643;
+#endif
+ ext->flash_con.peri_type = SE_I2C;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 5;
+#if defined(CONFIG_MACH_XYREF4415)
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 6;
+#else
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 8;
+#endif
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_3H7_SUNNY_H
+#define FIMC_IS_DEVICE_3H7_SYNNY_H
+
+#define SENSOR_S5K3H7_SUNNY_INSTANCE 0
+#define SENSOR_S5K3H7_SUNNY_NAME SENSOR_NAME_S5K3H7_SUNNY
+
+int sensor_3h7_sunny_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-3l2.h"
+
+#define SENSOR_NAME "S5K3L2"
+
+static struct fimc_is_sensor_cfg config_3l2[] = {
+ /* 4144x3106@30fps */
+ FIMC_IS_SENSOR_CFG(4144, 3106, 30, 25, 0),
+ /* 4144x2332@30fps */
+ FIMC_IS_SENSOR_CFG(4144, 2332, 30, 25, 1),
+ /* 2072x1554@24fps */
+ FIMC_IS_SENSOR_CFG(2072, 1554, 24, 25, 2),
+ /* 2072x1166@24fps */
+ FIMC_IS_SENSOR_CFG(2072, 1166, 24, 25, 3),
+ /* 1040x584@120fps */
+ FIMC_IS_SENSOR_CFG(1040, 584, 120, 17, 4),
+ /* 2072x1166@60fps */
+ FIMC_IS_SENSOR_CFG(2072, 1166, 60, 19, 5),
+};
+
+static int sensor_3l2_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_3l2_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_3l2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K3L2_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K3L2;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K3L2_INSTANCE;
+ module->client = client;
+ module->active_width = 4128;
+ module->active_height = 3096;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 120;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K3L2";
+ module->setfile_name = "setfile_3l2.bin";
+ module->cfgs = ARRAY_SIZE(config_3l2);
+ module->cfg = config_3l2;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = SENSOR_NAME_S5K3L2;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x20;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_DWXXXX;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x20;
+ ext->actuator_con.peri_setting.i2c.speed = 400000;
+
+ ext->flash_con.product_name = FLADRV_NAME_AS3643;
+ ext->flash_con.peri_type = SE_I2C;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 2;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 3;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_3L2_H
+#define FIMC_IS_DEVICE_3L2_H
+
+#define SENSOR_S5K3L2_INSTANCE 0
+#define SENSOR_S5K3L2_NAME SENSOR_NAME_S5K3L2
+
+int sensor_3l2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-4e5.h"
+
+#define SENSOR_NAME "S5K4E5"
+
+static int sensor_4e5_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_4e5_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_4e5_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K4E5_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K4E5;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K4E5_INSTANCE;
+ module->client = client;
+ module->pixel_width = 2560 + 16;
+ module->pixel_height = 1920 + 10;
+ module->active_width = 2560;
+ module->active_height = 1920;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K4E5";
+ module->setfile_name = "setfile_4e5.bin";
+ module->cfgs = 0;
+ module->cfg = NULL;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = 0;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_DWXXXX;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+
+ ext->flash_con.product_name = FLADRV_NAME_KTD267;
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 17;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 16;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_4E5_H
+#define FIMC_IS_DEVICE_4E5_H
+
+#define SENSOR_S5K4E5_INSTANCE 0
+#define SENSOR_S5K4E5_NAME SENSOR_NAME_S5K4E5
+
+int sensor_4e5_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-4h5.h"
+
+#define SENSOR_NAME "S5K4H5"
+
+static struct fimc_is_sensor_cfg config_4h5[] = {
+ /* 3280x2458@30fps */
+ FIMC_IS_SENSOR_CFG(3280, 2458, 30, 14, 0),
+ /* 3280x1846@30fps */
+ FIMC_IS_SENSOR_CFG(3280, 1846, 30, 11, 1),
+ /* 1640x924@60fps */
+ FIMC_IS_SENSOR_CFG(1640, 924, 60, 14, 2),
+ /* 816x460@120fps */
+ FIMC_IS_SENSOR_CFG(816, 460, 120, 14, 3),
+};
+
+static int sensor_4h5_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_4h5_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_4h5_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K4H5_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_S5K4H5;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K4H5_INSTANCE;
+ module->ops = NULL;
+ module->client = client;
+ module->active_width = 3264;
+ module->active_height = 2448;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 120;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K4H5";
+ module->setfile_name = "setfile_4h5.bin";
+ module->cfgs = ARRAY_SIZE(config_4h5);
+ module->cfg = config_4h5;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = 0;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x6E;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_DW9804;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel
+ = SENSOR_CONTROL_I2C0;
+
+ ext->flash_con.product_name = FLADRV_NAME_RT5033;
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 8;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 6;
+
+ /* ext->from_con.product_name = FROMDRV_NAME_W25Q80BW; */
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+ ext->mclk = 0;
+ ext->mipi_lane_num = 0;
+ ext->mipi_speed = 0;
+ ext->fast_open_sensor = 0;
+ ext->self_calibration_mode = 0;
+ ext->I2CSclk = I2C_L0;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_S5K4H5_H
+#define FIMC_IS_DEVICE_S5K4H5_H
+
+#define SENSOR_S5K4H5_INSTANCE 0
+#define SENSOR_S5K4H5_NAME SENSOR_NAME_S5K4H5
+
+int sensor_4h5_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-6a3.h"
+
+#define SENSOR_NAME "S5K6A3"
+
+static struct fimc_is_sensor_cfg config_6a3[] = {
+ /* 1412x796@30fps */
+ FIMC_IS_SENSOR_CFG(1412, 796, 30, 16, 0),
+};
+
+static int sensor_6a3_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_6a3_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_6a3_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ int enum_idx = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K6A3_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ enum_idx = atomic_read(&core->resourcemgr.rsccount_module);
+ module = &device->module_enum[enum_idx];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_S5K6A3_NAME;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K6A3_INSTANCE;
+ module->client = client;
+ module->active_width = 1392;
+ module->active_height = 1402;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_FRONT;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_1;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K6A3";
+ module->setfile_name = "setfile_6a3.bin";
+ module->cfgs = ARRAY_SIZE(config_6a3);
+ module->cfg = config_6a3;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+ ext->mipi_settle_line = 18;
+
+ ext->sensor_con.product_name = SENSOR_S5K6A3_NAME;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x20;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_6A3_H
+#define FIMC_IS_DEVICE_6A3_H
+
+#define SENSOR_S5K6A3_INSTANCE 1
+#define SENSOR_S5K6A3_NAME SENSOR_NAME_S5K6A3
+
+int sensor_6a3_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-6b2.h"
+
+#define SENSOR_NAME "S5K6B2"
+#define DEFAULT_SENSOR_WIDTH 184
+#define DEFAULT_SENSOR_HEIGHT 104
+#define SENSOR_MEMSIZE DEFAULT_SENSOR_WIDTH * DEFAULT_SENSOR_HEIGHT
+
+#define SENSOR_REG_VIS_DURATION_MSB (0x6026)
+#define SENSOR_REG_VIS_DURATION_LSB (0x6027)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_MSB (0x4340)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_LSB (0x4341)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_MSB (0x4342)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_LSB (0x4343)
+#define SENSOR_REG_VIS_GAIN_RED (0x6029)
+#define SENSOR_REG_VIS_GAIN_GREEN (0x602A)
+#define SENSOR_REG_VIS_AE_TARGET (0x600A)
+#define SENSOR_REG_VIS_AE_SPEED (0x5034)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_MSB (0x5030)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_LSB (0x5031)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x1_2 (0x6000)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x3_4 (0x6001)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x1_2 (0x6002)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x3_4 (0x6003)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x1_2 (0x6004)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x3_4 (0x6005)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x1_2 (0x6006)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x3_4 (0x6007)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_MSB (0x5039)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_LSB (0x503A)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_MSB (0x503B)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_LSB (0x503C)
+#define SENSOR_REG_VIS_BIT_CONVERTING_MSB (0x602B)
+#define SENSOR_REG_VIS_BIT_CONVERTING_LSB (0x7203)
+#define SENSOR_REG_VIS_AE_OFF (0x5000)
+
+static struct fimc_is_sensor_cfg config_6b2[] = {
+ /* 1936x1090@30fps */
+ FIMC_IS_SENSOR_CFG(1936, 1090, 30, 16, 0),
+ /* 1936x1090@24fps */
+ FIMC_IS_SENSOR_CFG(1936, 1090, 24, 13, 1),
+ /* 1296x730@30fps */
+ FIMC_IS_SENSOR_CFG(1296, 730, 30, 13, 2),
+};
+
+static int sensor_6b2_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_6b2_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_6b2_registered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static void sensor_6b2_unregistered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops internal_ops = {
+ .open = sensor_6b2_open,
+ .close = sensor_6b2_close,
+ .registered = sensor_6b2_registered,
+ .unregistered = sensor_6b2_unregistered,
+};
+
+static int sensor_6b2_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_module_6b2 *module_6b2;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ module_6b2 = module->private_data;
+ client = module->client;
+
+ module_6b2->system_clock = 146 * 1000 * 1000;
+ module_6b2->line_length_pck = 146 * 1000 * 1000;
+
+ pr_info("%s\n", __func__);
+ /* sensor init */
+ /* 8 bit mode */
+ fimc_is_sensor_write8(client, 0x7203, 0x40);
+ fimc_is_sensor_write8(client, 0x602B, 0x02);
+ fimc_is_sensor_write8(client, 0x702A, 0x3D);
+ fimc_is_sensor_write8(client, 0x702B, 0xB0);
+ fimc_is_sensor_write8(client, 0x7030, 0x0E);
+ fimc_is_sensor_write8(client, 0x7031, 0x2F);
+
+ /* Analog Tuning */
+ fimc_is_sensor_write8(client, 0x7067, 0x00);
+ fimc_is_sensor_write8(client, 0x7073, 0xFF);
+ fimc_is_sensor_write8(client, 0x7074, 0x22);
+
+ /* Dark Tuning */
+ fimc_is_sensor_write8(client, 0x7042, 0x1F);
+ fimc_is_sensor_write8(client, 0x7403, 0xC0);
+ fimc_is_sensor_write8(client, 0x7245, 0x04);
+ fimc_is_sensor_write8(client, 0x7205, 0xA1);
+
+ /* Remove Dark Band */
+ fimc_is_sensor_write8(client, 0x7430, 0x07);
+ fimc_is_sensor_write8(client, 0x705C, 0x7E);
+
+ /* Remove Sun spot */
+ fimc_is_sensor_write8(client, 0x702C, 0x3C);
+ fimc_is_sensor_write8(client, 0x7075, 0x3D);
+
+ /* Remove CFPN */
+ fimc_is_sensor_write8(client, 0x7066, 0x0C);
+
+ /* AE setting */
+ fimc_is_sensor_write8(client, 0x6000, 0x44);
+ fimc_is_sensor_write8(client, 0x6001, 0x44);
+ fimc_is_sensor_write8(client, 0x6002, 0x44);
+ fimc_is_sensor_write8(client, 0x6003, 0x44);
+ fimc_is_sensor_write8(client, 0x6004, 0x44);
+ fimc_is_sensor_write8(client, 0x6005, 0x44);
+ fimc_is_sensor_write8(client, 0x6006, 0x44);
+ fimc_is_sensor_write8(client, 0x6007, 0x44);
+
+ /* AE target */
+ fimc_is_sensor_write8(client, 0x600A, 0xB4);
+
+ /* speed */
+ fimc_is_sensor_write8(client, 0x5034, 0x00);
+
+ /* Cintc_min */
+ fimc_is_sensor_write8(client, 0x5017, 0x01);
+
+ /* Number of pixel */
+ fimc_is_sensor_write8(client, 0x5030, 0x4A);
+ fimc_is_sensor_write8(client, 0x5031, 0xC0);
+
+ /* G + R Setting */
+ /* Vision Senser Data = 0.5*Gr + 0.5*R */
+ fimc_is_sensor_write8(client, 0x6029, 0x02);
+ fimc_is_sensor_write8(client, 0x602A, 0x02);
+
+ /* For Analog Gain 16x */
+ fimc_is_sensor_write8(client, 0x7018, 0xCF);
+ fimc_is_sensor_write8(client, 0x7019, 0xDB);
+ fimc_is_sensor_write8(client, 0x702A, 0x8D);
+ fimc_is_sensor_write8(client, 0x702B, 0x60);
+ fimc_is_sensor_write8(client, 0x5035, 0x02);
+
+ /* BIT_RATE_MBPS_alv */
+ fimc_is_sensor_write8(client, 0x7351, 0x02);
+ fimc_is_sensor_write8(client, 0x7352, 0x48);
+ fimc_is_sensor_write8(client, 0x7353, 0x00);
+ fimc_is_sensor_write8(client, 0x7354, 0x00);
+
+ fimc_is_sensor_write8(client, 0x7339, 0x03);
+
+ /* Analog gain */
+ fimc_is_sensor_write8(client, 0x4204, 0x00);
+ fimc_is_sensor_write8(client, 0x4205, 0x32);
+
+ /* frame rate - default 10fps*/
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_MSB, 0x00);
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_LSB, 0x6A);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_6b2_init
+};
+
+static int sensor_6b2_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (enable) {
+ ret = CALL_MOPS(sensor, stream_on, subdev);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ ret = CALL_MOPS(sensor, stream_off, subdev);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ return 0;
+}
+
+static int sensor_6b2_s_param(struct v4l2_subdev *subdev, struct v4l2_streamparm *param)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct v4l2_captureparm *cp;
+ struct v4l2_fract *tpf;
+ u64 duration;
+
+ BUG_ON(!subdev);
+ BUG_ON(!param);
+
+ pr_info("%s\n", __func__);
+
+ cp = ¶m->parm.capture;
+ tpf = &cp->timeperframe;
+
+ if (!tpf->denominator) {
+ err("denominator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!tpf->numerator) {
+ err("numerator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ duration = (u64)(tpf->numerator * 1000 * 1000 * 1000) /
+ (u64)(tpf->denominator);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = CALL_MOPS(sensor, s_duration, subdev, duration);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int sensor_6b2_s_format(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *fmt)
+{
+ /* TODO */
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops video_ops = {
+ .s_stream = sensor_6b2_s_stream,
+ .s_parm = sensor_6b2_s_param,
+ .s_mbus_fmt = sensor_6b2_s_format
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops,
+ .video = &video_ops
+};
+
+int sensor_6b2_stream_on(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 1);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int sensor_6b2_stream_off(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 0);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+/*
+ * @ brief
+ * frame duration time
+ * @ unit
+ * nano second
+ * @ remarks
+ */
+int sensor_6b2_s_duration(struct v4l2_subdev *subdev, u64 duration)
+{
+ int ret = 0;
+ u8 value[2];
+ u32 framerate, result;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ framerate = 1000 * 1000 * 1000 / (u32)duration;
+ result = 1060 / framerate;
+ value[0] = result & 0xFF;
+ value[1] = (result >> 8) & 0xFF;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_MSB, value[1]);
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_LSB, value[0]);
+
+p_err:
+ return ret;
+}
+
+int sensor_6b2_g_min_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_g_max_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_s_exposure(struct v4l2_subdev *subdev, u64 exposure)
+{
+ int ret = 0;
+ u8 value;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s(%d)\n", __func__, (u32)exposure);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ value = exposure & 0xFF;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_AE_TARGET, value);
+
+p_err:
+ return ret;
+}
+
+int sensor_6b2_g_min_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_g_max_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_s_again(struct v4l2_subdev *subdev, u64 sensitivity)
+{
+ int ret = 0;
+
+ pr_info("%s\n", __func__);
+
+ return ret;
+}
+
+int sensor_6b2_g_min_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_g_max_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_s_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_g_min_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6b2_g_max_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+struct fimc_is_sensor_ops module_6b2_ops = {
+ .stream_on = sensor_6b2_stream_on,
+ .stream_off = sensor_6b2_stream_off,
+ .s_duration = sensor_6b2_s_duration,
+ .g_min_duration = sensor_6b2_g_min_duration,
+ .g_max_duration = sensor_6b2_g_max_duration,
+ .s_exposure = sensor_6b2_s_exposure,
+ .g_min_exposure = sensor_6b2_g_min_exposure,
+ .g_max_exposure = sensor_6b2_g_max_exposure,
+ .s_again = sensor_6b2_s_again,
+ .g_min_again = sensor_6b2_g_min_again,
+ .g_max_again = sensor_6b2_g_max_again,
+ .s_dgain = sensor_6b2_s_dgain,
+ .g_min_dgain = sensor_6b2_g_min_dgain,
+ .g_max_dgain = sensor_6b2_g_max_dgain
+};
+
+#ifdef CONFIG_OF
+static int sensor_6b2_power_setpin(struct device *dev)
+{
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ int gpio_none = 0;
+ int gpio_reset = 0, gpio_standby = 0;
+ int gpios_cam_en = 0;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ err("failed to get PIN_RESET");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ gpios_cam_en = of_get_named_gpio(dnode, "gpios_cam_en", 0);
+ if (!gpio_is_valid(gpios_cam_en)) {
+ err("failed to get front cam en gpio");
+ } else {
+ gpio_request_one(gpios_cam_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_cam_en);
+ }
+
+ gpio_standby = of_get_named_gpio(dnode, "gpio_standby", 0);
+ if (!gpio_is_valid(gpio_standby)) {
+ err("failed to get gpio_standby");
+ } else {
+ gpio_request_one(gpio_standby, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_standby);
+ }
+
+ /* FRONT CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* FRONT CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 1, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 4, gpio_standby, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 2, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 5, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+#endif
+
+int sensor_6b2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+ static bool probe_retried = false;
+
+ if (!fimc_is_dev)
+ goto probe_defer;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K6B2_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ /* S5K6B2 */
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_S5K6B2_NAME;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K6B2_INSTANCE;
+ module->ops = &module_6b2_ops;
+ module->client = client;
+ module->active_width = 1920;
+ module->active_height = 1080;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_FRONT;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_1;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K6B2";
+ module->setfile_name = "setfile_6b2.bin";
+ module->cfgs = ARRAY_SIZE(config_6b2);
+ module->cfg = config_6b2;
+ module->private_data = kzalloc(sizeof(struct fimc_is_module_6b2), GFP_KERNEL);
+ if (!module->private_data) {
+ err("private_data is NULL");
+ ret = -ENOMEM;
+ kfree(subdev_module);
+ goto p_err;
+ }
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_6b2_power_setpin;
+#endif
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+ ext->sensor_con.product_name = SENSOR_NAME_S5K6B2;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client) {
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ subdev_module->internal_ops = &internal_ops;
+ } else {
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+ }
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+
+probe_defer:
+ if (probe_retried) {
+ err("probe has already been retried!!");
+ BUG();
+ }
+
+ probe_retried = true;
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+}
+
+static int sensor_6b2_remove(struct i2c_client *client)
+{
+ int ret = 0;
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_fimc_is_sensor_6b2_match[] = {
+ {
+ .compatible = "samsung,exynos5-fimc-is-sensor-6b2",
+ },
+ {},
+};
+#endif
+
+static const struct i2c_device_id sensor_6b2_idt[] = {
+ { SENSOR_NAME, 0 },
+};
+
+static struct i2c_driver sensor_6b2_driver = {
+ .driver = {
+ .name = SENSOR_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = exynos_fimc_is_sensor_6b2_match
+#endif
+ },
+ .probe = sensor_6b2_probe,
+ .remove = sensor_6b2_remove,
+ .id_table = sensor_6b2_idt
+};
+
+static int __init sensor_6b2_load(void)
+{
+ return i2c_add_driver(&sensor_6b2_driver);
+}
+
+static void __exit sensor_6b2_unload(void)
+{
+ i2c_del_driver(&sensor_6b2_driver);
+}
+
+module_init(sensor_6b2_load);
+module_exit(sensor_6b2_unload);
+
+MODULE_AUTHOR("Gilyeon lim");
+MODULE_DESCRIPTION("Sensor 6B2 driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_6B2_H
+#define FIMC_IS_DEVICE_6B2_H
+
+#define SENSOR_S5K6B2_INSTANCE 1
+#define SENSOR_S5K6B2_NAME SENSOR_NAME_S5K6B2
+
+struct fimc_is_module_6b2 {
+ u16 vis_duration;
+ u16 frame_length_line;
+ u32 line_length_pck;
+ u32 system_clock;
+};
+
+int sensor_6b2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-6d1.h"
+
+#define SENSOR_NAME "S5K6D1"
+#define DEFAULT_SENSOR_WIDTH 184
+#define DEFAULT_SENSOR_HEIGHT 104
+#define SENSOR_MEMSIZE DEFAULT_SENSOR_WIDTH * DEFAULT_SENSOR_HEIGHT
+
+#define SENSOR_REG_VIS_DURATION_MSB (0x6026)
+#define SENSOR_REG_VIS_DURATION_LSB (0x6027)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_MSB (0x4340)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_LSB (0x4341)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_MSB (0x4342)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_LSB (0x4343)
+#define SENSOR_REG_VIS_GAIN_RED (0x6029)
+#define SENSOR_REG_VIS_GAIN_GREEN (0x602A)
+#define SENSOR_REG_VIS_AE_TARGET (0x600A)
+#define SENSOR_REG_VIS_AE_SPEED (0x5034)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_MSB (0x5030)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_LSB (0x5031)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x1_2 (0x6000)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x3_4 (0x6001)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x1_2 (0x6002)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x3_4 (0x6003)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x1_2 (0x6004)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x3_4 (0x6005)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x1_2 (0x6006)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x3_4 (0x6007)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_MSB (0x5039)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_LSB (0x503A)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_MSB (0x503B)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_LSB (0x503C)
+#define SENSOR_REG_VIS_BIT_CONVERTING_MSB (0x602B)
+#define SENSOR_REG_VIS_BIT_CONVERTING_LSB (0x7203)
+#define SENSOR_REG_VIS_AE_OFF (0x5000)
+
+static u16 setfile_vision_6d1[][2] = {
+ {0x4200, 0x02},
+ {0x4201, 0xAE},
+ {0x4301, 0x04},
+ {0x4309, 0x04},
+ {0x4345, 0x08},
+ {0x4347, 0x08},
+ {0x4348, 0x0A},
+ {0x4349, 0x01},
+ {0x434A, 0x05},
+ {0x434B, 0xA0},
+ {0x434C, 0x01},
+ {0x434D, 0x40},
+ {0x434E, 0x00},
+ {0x434F, 0xB4},
+ {0x4381, 0x01},
+ {0x4383, 0x07},
+ {0x4385, 0x08},
+ {0x4387, 0x08},
+ {0x5004, 0x01},
+ {0x5005, 0x1E},
+ {0x5014, 0x11},
+ {0x5015, 0x9E},
+ {0x5016, 0x00},
+ {0x5017, 0x02},
+ {0x5030, 0x1C},
+ {0x5031, 0x20},
+ {0x5034, 0x00},
+ {0x5035, 0x02},
+ {0x5036, 0x00},
+ {0x5037, 0x06},
+ {0x5038, 0xC0},
+ {0x5039, 0x00},
+ {0x503A, 0x00},
+ {0x503B, 0x00},
+ {0x503C, 0x00},
+ {0x503D, 0x20},
+ {0x503E, 0x70},
+ {0x503F, 0x02},
+ {0x600A, 0x2A},
+ {0x600E, 0x05},
+ {0x6014, 0x27},
+ {0x6015, 0x1D},
+ {0x6018, 0x01},
+ {0x6026, 0x00},
+ {0x6027, 0x68},
+ {0x6029, 0x08},
+ {0x602A, 0x08},
+ {0x602B, 0x00},
+ {0x602C, 0x00},
+ {0x7008, 0x00},
+ {0x7009, 0x10},
+ {0x700A, 0x00},
+ {0x700B, 0x10},
+ {0x7014, 0x2B},
+ {0x7015, 0x91},
+ {0x7016, 0x82},
+ {0x701B, 0x16},
+ {0x701D, 0x0B},
+ {0x701F, 0x0B},
+ {0x7026, 0x1A},
+ {0x7027, 0x46},
+ {0x7029, 0x14},
+ {0x702A, 0x02},
+ {0x7038, 0x01},
+ {0x7039, 0x14},
+ {0x703A, 0x32},
+ {0x703B, 0x22},
+ {0x7040, 0x01},
+ {0x7041, 0x14},
+ {0x7042, 0x32},
+ {0x7043, 0x22},
+ {0x7050, 0x0A},
+ {0x7051, 0xA8},
+ {0x7052, 0x35},
+ {0x7053, 0x54},
+ {0x7054, 0x00},
+ {0x7055, 0x00},
+ {0x7056, 0x00},
+ {0x7057, 0x00},
+ {0x705E, 0x0E},
+ {0x705F, 0x10},
+ {0x7060, 0x01},
+ {0x7064, 0x05},
+ {0x7065, 0x3C},
+ {0x7066, 0x00},
+ {0x7067, 0x00},
+ {0x7068, 0x4A},
+ {0x706C, 0x01},
+ {0x7077, 0x88},
+ {0x7078, 0x88},
+ {0x7082, 0x90},
+ {0x7091, 0x05},
+ {0x7098, 0x00},
+ {0x7112, 0x01},
+ {0x720A, 0x06},
+ {0x720B, 0x80},
+ {0x7245, 0xC1},
+ {0x7301, 0x01},
+ {0x7305, 0x13},
+ {0x7306, 0x01},
+ {0x7323, 0x01},
+ {0x7339, 0x07},
+ {0x7351, 0x01},
+ {0x7352, 0x24},
+ {0x7405, 0x28},
+ {0x7406, 0x28},
+ {0x7407, 0xC0},
+ {0x7454, 0x01},
+ {0x7460, 0x01},
+ {0x7461, 0x20},
+ {0x7462, 0xC0},
+ {0x7463, 0x1E},
+ {0x7464, 0x02},
+ {0x7465, 0x4B},
+ {0x7467, 0x20},
+ {0x7468, 0x20},
+ {0x7469, 0x20},
+ {0x746A, 0x20},
+ {0x746B, 0x20},
+ {0x746C, 0x20},
+ {0x746D, 0x09},
+ {0x746E, 0xFF},
+ {0x746F, 0x01},
+ {0x7472, 0x00},
+ {0x7473, 0x02},
+ {0x7474, 0xC1},
+ {0x7475, 0x00},
+ {0x7476, 0x00},
+ {0x7477, 0x00},
+ {0x7478, 0x00},
+ {0x4100, 0x01},
+};
+
+static struct fimc_is_sensor_cfg config_6d1[] = {
+ /* 2576x1456@30fps */
+ FIMC_IS_SENSOR_CFG(2576, 1456, 30, 14, 0),
+ /* 2576x1456@24fps */
+ FIMC_IS_SENSOR_CFG(2576, 1456, 24, 14, 1),
+#if 0
+ /* 1924x1082@30fps */
+ FIMC_IS_SENSOR_CFG(1924, 1082, 30, 16, 1),
+ /* 1444x1082@30fps */
+ FIMC_IS_SENSOR_CFG(1444, 1082, 30, 16, 2),
+ /* 1084x1082@30fps */
+ FIMC_IS_SENSOR_CFG(1084, 1082, 30, 16, 3),
+ /* 964x542@30fps */
+ FIMC_IS_SENSOR_CFG(964, 542, 30, 16, 4),
+ /* 724x542@30fps */
+ FIMC_IS_SENSOR_CFG(724, 542, 30, 16, 5),
+ /* 544x542@30fps */
+ FIMC_IS_SENSOR_CFG(544, 542, 30, 16, 6),
+ /* 320x180@10fps : only for vision(settle) */
+ FIMC_IS_SENSOR_CFG(320, 180, 10, 4, 6),
+ /* 1936x1090@24fps */
+ FIMC_IS_SENSOR_CFG(1936, 1090, 24, 13, 7),
+#endif
+};
+
+static int sensor_6d1_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_6d1_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_6d1_registered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static void sensor_6d1_unregistered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops internal_ops = {
+ .open = sensor_6d1_open,
+ .close = sensor_6d1_close,
+ .registered = sensor_6d1_registered,
+ .unregistered = sensor_6d1_unregistered,
+};
+
+static int sensor_6d1_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int i, ret = 0;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_module_6d1 *module_6d1;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ module_6d1 = module->private_data;
+ client = module->client;
+
+ module_6d1->system_clock = 146 * 1000 * 1000;
+ module_6d1->line_length_pck = 146 * 1000 * 1000;
+
+ pr_info("%s\n", __func__);
+
+ /* sensor init */
+ for (i = 0; i < ARRAY_SIZE(setfile_vision_6d1); i++) {
+ fimc_is_sensor_write8(client, setfile_vision_6d1[i][0],
+ (u8)setfile_vision_6d1[i][1]);
+ }
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_6d1_init
+};
+
+static int sensor_6d1_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (enable) {
+ ret = CALL_MOPS(sensor, stream_on, subdev);
+ if (ret < 0) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ ret = CALL_MOPS(sensor, stream_off, subdev);
+ if (ret < 0) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ return 0;
+}
+
+static int sensor_6d1_s_param(struct v4l2_subdev *subdev, struct v4l2_streamparm *param)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct v4l2_captureparm *cp;
+ struct v4l2_fract *tpf;
+ u64 duration;
+
+ BUG_ON(!subdev);
+ BUG_ON(!param);
+
+ pr_info("%s\n", __func__);
+
+ cp = ¶m->parm.capture;
+ tpf = &cp->timeperframe;
+
+ if (!tpf->denominator) {
+ err("denominator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!tpf->numerator) {
+ err("numerator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ duration = (u64)(tpf->numerator * 1000 * 1000 * 1000) /
+ (u64)(tpf->denominator);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = CALL_MOPS(sensor, s_duration, subdev, duration);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int sensor_6d1_s_format(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *fmt)
+{
+ /* TODO */
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops video_ops = {
+ .s_stream = sensor_6d1_s_stream,
+ .s_parm = sensor_6d1_s_param,
+ .s_mbus_fmt = sensor_6d1_s_format
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops,
+ .video = &video_ops
+};
+
+int sensor_6d1_stream_on(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 1);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int sensor_6d1_stream_off(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 0);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+/*
+ * @ brief
+ * frame duration time
+ * @ unit
+ * nano second
+ * @ remarks
+ */
+int sensor_6d1_s_duration(struct v4l2_subdev *subdev, u64 duration)
+{
+ int ret = 0;
+ u8 value[2];
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /*
+ * forcely set 10fps for 6d1,
+ */
+ value[0] = 0x52;
+ value[1] = 0x0;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_MSB, value[1]);
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_LSB, value[0]);
+
+p_err:
+ return ret;
+}
+
+int sensor_6d1_g_min_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_g_max_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_s_exposure(struct v4l2_subdev *subdev, u64 exposure)
+{
+ int ret = 0;
+ u8 value;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s(%d)\n", __func__, (u32)exposure);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ value = exposure & 0xFF;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_AE_TARGET, value);
+
+p_err:
+ return ret;
+}
+
+int sensor_6d1_g_min_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_g_max_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_s_again(struct v4l2_subdev *subdev, u64 sensitivity)
+{
+ int ret = 0;
+
+ pr_info("%s\n", __func__);
+
+ return ret;
+}
+
+int sensor_6d1_g_min_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_g_max_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_s_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_g_min_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_6d1_g_max_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+struct fimc_is_sensor_ops module_6d1_ops = {
+ .stream_on = sensor_6d1_stream_on,
+ .stream_off = sensor_6d1_stream_off,
+ .s_duration = sensor_6d1_s_duration,
+ .g_min_duration = sensor_6d1_g_min_duration,
+ .g_max_duration = sensor_6d1_g_max_duration,
+ .s_exposure = sensor_6d1_s_exposure,
+ .g_min_exposure = sensor_6d1_g_min_exposure,
+ .g_max_exposure = sensor_6d1_g_max_exposure,
+ .s_again = sensor_6d1_s_again,
+ .g_min_again = sensor_6d1_g_min_again,
+ .g_max_again = sensor_6d1_g_max_again,
+ .s_dgain = sensor_6d1_s_dgain,
+ .g_min_dgain = sensor_6d1_g_min_dgain,
+ .g_max_dgain = sensor_6d1_g_max_dgain
+};
+
+#ifdef CONFIG_OF
+static int sensor_6d1_power_setpin(struct device *dev)
+{
+ int gpio_none = 0, gpio_reset = 0, gpio_standby = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ struct pinctrl *pinctrl_ch = NULL;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ dev_err(dev, "failed to get PIN_RESET\n");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ gpio_standby = of_get_named_gpio(dnode, "gpio_standby", 0);
+ if (!gpio_is_valid(gpio_standby)) {
+ dev_err(dev, "failed to get gpio_standby\n");
+ } else {
+ gpio_request_one(gpio_standby, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_standby);
+ }
+
+ /* initial - i2c off */
+ pinctrl_ch = devm_pinctrl_get_select(dev, "off1");
+ if (IS_ERR_OR_NULL(pinctrl_ch)) {
+ pr_err("%s: cam %s pins are not configured\n", __func__, "off1");
+ } else {
+ devm_pinctrl_put(pinctrl_ch);
+ }
+
+ /* FRONT CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* FRONT CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 4, gpio_standby, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 2, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+#endif
+
+int sensor_6d1_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+ static bool probe_retried = false;
+
+ if (!fimc_is_dev)
+ goto probe_defer;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K6D1_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ /* S5K6D1 */
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_S5K6D1_NAME;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K6D1_INSTANCE;
+ module->ops = &module_6d1_ops;
+ module->client = client;
+ module->active_width = 2560;
+ module->active_height = 1446;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_FRONT;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_2;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K6D1";
+ module->setfile_name = "setfile_6d1.bin";
+ module->cfgs = ARRAY_SIZE(config_6d1);
+ module->cfg = config_6d1;
+ module->private_data = kzalloc(sizeof(struct fimc_is_module_6d1), GFP_KERNEL);
+ if (!module->private_data) {
+ err("private_data is NULL");
+ ret = -ENOMEM;
+ kfree(subdev_module);
+ goto p_err;
+ }
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_6d1_power_setpin;
+#endif
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+ ext->sensor_con.product_name = SENSOR_NAME_S5K6D1;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client) {
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ subdev_module->internal_ops = &internal_ops;
+ } else {
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+ }
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+
+probe_defer:
+ if (probe_retried) {
+ err("probe has already been retried!!");
+ BUG();
+ }
+
+ probe_retried = true;
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+}
+
+static int sensor_6d1_remove(struct i2c_client *client)
+{
+ int ret = 0;
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_fimc_is_sensor_6d1_match[] = {
+ {
+ .compatible = "samsung,exynos5-fimc-is-sensor-6d1",
+ },
+ {},
+};
+#endif
+
+static const struct i2c_device_id sensor_6d1_idt[] = {
+ { SENSOR_NAME, 0 },
+};
+
+static struct i2c_driver sensor_6d1_driver = {
+ .driver = {
+ .name = SENSOR_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = exynos_fimc_is_sensor_6d1_match
+#endif
+ },
+ .probe = sensor_6d1_probe,
+ .remove = sensor_6d1_remove,
+ .id_table = sensor_6d1_idt
+};
+
+static int __init sensor_6d1_load(void)
+{
+ return i2c_add_driver(&sensor_6d1_driver);
+}
+
+static void __exit sensor_6d1_unload(void)
+{
+ i2c_del_driver(&sensor_6d1_driver);
+}
+
+module_init(sensor_6d1_load);
+module_exit(sensor_6d1_unload);
+
+MODULE_AUTHOR("Gilyeon lim");
+MODULE_DESCRIPTION("Sensor 6D1 driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_6D1_H
+#define FIMC_IS_DEVICE_6D1_H
+
+#define SENSOR_S5K6D1_INSTANCE 1
+#define SENSOR_S5K6D1_NAME SENSOR_NAME_S5K6D1
+
+struct fimc_is_module_6d1 {
+ u16 vis_duration;
+ u16 frame_length_line;
+ u32 line_length_pck;
+ u32 system_clock;
+};
+
+int sensor_6d1_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-8b1.h"
+
+#define SENSOR_NAME "S5K8B1"
+#define DEFAULT_SENSOR_WIDTH 184
+#define DEFAULT_SENSOR_HEIGHT 104
+#define SENSOR_MEMSIZE DEFAULT_SENSOR_WIDTH * DEFAULT_SENSOR_HEIGHT
+
+#define SENSOR_REG_VIS_DURATION_MSB (0x6026)
+#define SENSOR_REG_VIS_DURATION_LSB (0x6027)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_MSB (0x4340)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_LSB (0x4341)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_MSB (0x4342)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_LSB (0x4343)
+#define SENSOR_REG_VIS_GAIN_RED (0x6029)
+#define SENSOR_REG_VIS_GAIN_GREEN (0x602A)
+#define SENSOR_REG_VIS_AE_TARGET (0x600A)
+#define SENSOR_REG_VIS_AE_SPEED (0x5034)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_MSB (0x5030)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_LSB (0x5031)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x1_2 (0x6000)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x3_4 (0x6001)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x1_2 (0x6002)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x3_4 (0x6003)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x1_2 (0x6004)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x3_4 (0x6005)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x1_2 (0x6006)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x3_4 (0x6007)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_MSB (0x5039)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_LSB (0x503A)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_MSB (0x503B)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_LSB (0x503C)
+#define SENSOR_REG_VIS_BIT_CONVERTING_MSB (0x602B)
+#define SENSOR_REG_VIS_BIT_CONVERTING_LSB (0x7203)
+#define SENSOR_REG_VIS_AE_OFF (0x5000)
+
+static struct fimc_is_sensor_cfg config_8b1[] = {
+ /* 1936x1090@30fps */
+ FIMC_IS_SENSOR_CFG(1936, 1090, 30, 16, 0),
+ /* 1924x1082@30fps */
+ FIMC_IS_SENSOR_CFG(1924, 1082, 30, 16, 1),
+ /* 1444x1082@30fps */
+ FIMC_IS_SENSOR_CFG(1444, 1082, 30, 16, 2),
+ /* 1084x1082@30fps */
+ FIMC_IS_SENSOR_CFG(1084, 1082, 30, 16, 3),
+ /* 964x542@30fps */
+ FIMC_IS_SENSOR_CFG(964, 542, 30, 16, 4),
+ /* 724x542@30fps */
+ FIMC_IS_SENSOR_CFG(724, 542, 30, 16, 5),
+ /* 544x542@30fps */
+ FIMC_IS_SENSOR_CFG(544, 542, 30, 16, 6),
+ /* 320x180@10fps : only for vision(settle) */
+ FIMC_IS_SENSOR_CFG(320, 180, 10, 4, 6),
+ /* 1936x1090@24fps */
+ FIMC_IS_SENSOR_CFG(1936, 1090, 24, 13, 7),
+};
+
+static int sensor_8b1_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_8b1_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_8b1_registered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static void sensor_8b1_unregistered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops internal_ops = {
+ .open = sensor_8b1_open,
+ .close = sensor_8b1_close,
+ .registered = sensor_8b1_registered,
+ .unregistered = sensor_8b1_unregistered,
+};
+
+static int sensor_8b1_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_module_8b1 *module_8b1;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ module_8b1 = module->private_data;
+ client = module->client;
+
+ module_8b1->system_clock = 146 * 1000 * 1000;
+ module_8b1->line_length_pck = 146 * 1000 * 1000;
+
+ pr_info("%s\n", __func__);
+ /* sensor init */
+ fimc_is_sensor_write8(client, 0x4200, 0x01);
+ fimc_is_sensor_write8(client, 0x4201, 0x24);
+ fimc_is_sensor_write8(client, 0x4305, 0x06);
+ fimc_is_sensor_write8(client, 0x4307, 0xC0);
+ fimc_is_sensor_write8(client, 0x4342, 0x03);
+
+ fimc_is_sensor_write8(client, 0x4343, 0x90);
+ fimc_is_sensor_write8(client, 0x4345, 0x08);
+ fimc_is_sensor_write8(client, 0x4347, 0x08);
+ fimc_is_sensor_write8(client, 0x4348, 0x07);
+ fimc_is_sensor_write8(client, 0x4349, 0x83); /* 10 */
+
+ fimc_is_sensor_write8(client, 0x434A, 0x04);
+ fimc_is_sensor_write8(client, 0x434B, 0x3A);
+ fimc_is_sensor_write8(client, 0x434C, 0x01);
+ fimc_is_sensor_write8(client, 0x434D, 0x40);
+ fimc_is_sensor_write8(client, 0x434E, 0x00);
+
+ fimc_is_sensor_write8(client, 0x434F, 0xB4);
+ fimc_is_sensor_write8(client, 0x4381, 0x01);
+ fimc_is_sensor_write8(client, 0x4383, 0x05);
+ fimc_is_sensor_write8(client, 0x4385, 0x06);
+ fimc_is_sensor_write8(client, 0x4387, 0x06); /* 20 */
+
+ fimc_is_sensor_write8(client, 0x5004, 0x01);
+ fimc_is_sensor_write8(client, 0x5005, 0x1E);
+#ifdef VISION_30FPS
+ fimc_is_sensor_write8(client, 0x5014, 0x05);
+ fimc_is_sensor_write8(client, 0x5015, 0x73);
+#else
+ fimc_is_sensor_write8(client, 0x5014, 0x13);
+ fimc_is_sensor_write8(client, 0x5015, 0x33);
+#endif
+ fimc_is_sensor_write8(client, 0x5016, 0x00);
+
+ fimc_is_sensor_write8(client, 0x5017, 0x02);
+ fimc_is_sensor_write8(client, 0x5030, 0x0E);
+ fimc_is_sensor_write8(client, 0x5031, 0x10);
+ fimc_is_sensor_write8(client, 0x5034, 0x00);
+ fimc_is_sensor_write8(client, 0x5035, 0x02); /* 30 */
+
+ fimc_is_sensor_write8(client, 0x5036, 0x00);
+ fimc_is_sensor_write8(client, 0x5037, 0x04);
+ fimc_is_sensor_write8(client, 0x5038, 0xC0);
+ fimc_is_sensor_write8(client, 0x503D, 0x20);
+ fimc_is_sensor_write8(client, 0x503E, 0x70);
+
+ fimc_is_sensor_write8(client, 0x503F, 0x02);
+ fimc_is_sensor_write8(client, 0x600A, 0x3A);
+ fimc_is_sensor_write8(client, 0x600E, 0x05);
+ fimc_is_sensor_write8(client, 0x6014, 0x27);
+ fimc_is_sensor_write8(client, 0x6015, 0x1D); /* 40 */
+
+ fimc_is_sensor_write8(client, 0x6018, 0x01);
+ fimc_is_sensor_write8(client, 0x6026, 0x00);
+#ifdef VISION_30FPS
+ fimc_is_sensor_write8(client, 0x6027, 0x1B);
+#else
+ fimc_is_sensor_write8(client, 0x6027, 0x52);
+#endif
+ fimc_is_sensor_write8(client, 0x6029, 0x08);
+ fimc_is_sensor_write8(client, 0x602A, 0x08);
+
+ fimc_is_sensor_write8(client, 0x602B, 0x00);
+ fimc_is_sensor_write8(client, 0x602c, 0x00);
+ fimc_is_sensor_write8(client, 0x6032, 0x63);
+ fimc_is_sensor_write8(client, 0x6033, 0x94);
+ fimc_is_sensor_write8(client, 0x7007, 0x18); /* 50 */
+
+ fimc_is_sensor_write8(client, 0x7015, 0x28);
+ fimc_is_sensor_write8(client, 0x7016, 0x2C);
+ fimc_is_sensor_write8(client, 0x7027, 0x14);
+ fimc_is_sensor_write8(client, 0x7028, 0x3C);
+ fimc_is_sensor_write8(client, 0x7029, 0x02);
+
+ fimc_is_sensor_write8(client, 0x702A, 0x02);
+ fimc_is_sensor_write8(client, 0x703A, 0x04);
+ fimc_is_sensor_write8(client, 0x703B, 0x36);
+ fimc_is_sensor_write8(client, 0x7042, 0x04);
+ fimc_is_sensor_write8(client, 0x7043, 0x36); /* 60 */
+
+ fimc_is_sensor_write8(client, 0x7058, 0x6F);
+ fimc_is_sensor_write8(client, 0x705A, 0x01);
+ fimc_is_sensor_write8(client, 0x705C, 0x40);
+ fimc_is_sensor_write8(client, 0x7060, 0x07);
+ fimc_is_sensor_write8(client, 0x7061, 0x40);
+
+ fimc_is_sensor_write8(client, 0x7064, 0x43);
+ fimc_is_sensor_write8(client, 0x706D, 0x77);
+ fimc_is_sensor_write8(client, 0x706E, 0xFA);
+ fimc_is_sensor_write8(client, 0x7070, 0x0A);
+ fimc_is_sensor_write8(client, 0x7073, 0x04); /* 70 */
+
+ fimc_is_sensor_write8(client, 0x7087, 0x00);
+ fimc_is_sensor_write8(client, 0x7090, 0x01);
+ fimc_is_sensor_write8(client, 0x7115, 0x01);
+ fimc_is_sensor_write8(client, 0x7209, 0xF5);
+ fimc_is_sensor_write8(client, 0x720B, 0xF5);
+
+ fimc_is_sensor_write8(client, 0x7245, 0xC4);
+ fimc_is_sensor_write8(client, 0x7301, 0x02);
+ fimc_is_sensor_write8(client, 0x7306, 0x02);
+ fimc_is_sensor_write8(client, 0x7339, 0x03);
+ fimc_is_sensor_write8(client, 0x7351, 0x00); /* 80 */
+
+ fimc_is_sensor_write8(client, 0x7352, 0xC0);
+ fimc_is_sensor_write8(client, 0x7405, 0x28);
+ fimc_is_sensor_write8(client, 0x7406, 0x28);
+ fimc_is_sensor_write8(client, 0x7407, 0xC0);
+ fimc_is_sensor_write8(client, 0x740C, 0x60);
+
+ fimc_is_sensor_write8(client, 0x740D, 0x00);
+ fimc_is_sensor_write8(client, 0x7436, 0x03);
+ fimc_is_sensor_write8(client, 0x7437, 0x03);
+ fimc_is_sensor_write8(client, 0x7454, 0x01);
+ fimc_is_sensor_write8(client, 0x7460, 0x00); /* 90 */
+
+ fimc_is_sensor_write8(client, 0x7461, 0x01);
+ fimc_is_sensor_write8(client, 0x7462, 0x68);
+ fimc_is_sensor_write8(client, 0x7463, 0x1E);
+ fimc_is_sensor_write8(client, 0x7464, 0x03);
+ fimc_is_sensor_write8(client, 0x7465, 0x4B);
+
+ fimc_is_sensor_write8(client, 0x7467, 0x20);
+ fimc_is_sensor_write8(client, 0x7468, 0x20);
+ fimc_is_sensor_write8(client, 0x7469, 0x20);
+ fimc_is_sensor_write8(client, 0x746A, 0x20);
+ fimc_is_sensor_write8(client, 0x746B, 0x20); /* 100 */
+
+ fimc_is_sensor_write8(client, 0x746C, 0x20);
+ fimc_is_sensor_write8(client, 0x746D, 0x02);
+ fimc_is_sensor_write8(client, 0x746E, 0x80);
+ fimc_is_sensor_write8(client, 0x746F, 0x01);
+ fimc_is_sensor_write8(client, 0x4100, 0x01);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_8b1_init
+};
+
+static int sensor_8b1_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (enable) {
+ ret = CALL_MOPS(sensor, stream_on, subdev);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ ret = CALL_MOPS(sensor, stream_off, subdev);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ return 0;
+}
+
+static int sensor_8b1_s_param(struct v4l2_subdev *subdev, struct v4l2_streamparm *param)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct v4l2_captureparm *cp;
+ struct v4l2_fract *tpf;
+ u64 duration;
+
+ BUG_ON(!subdev);
+ BUG_ON(!param);
+
+ pr_info("%s\n", __func__);
+
+ cp = ¶m->parm.capture;
+ tpf = &cp->timeperframe;
+
+ if (!tpf->denominator) {
+ err("denominator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!tpf->numerator) {
+ err("numerator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ duration = (u64)(tpf->numerator * 1000 * 1000 * 1000) /
+ (u64)(tpf->denominator);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = CALL_MOPS(sensor, s_duration, subdev, duration);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int sensor_8b1_s_format(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *fmt)
+{
+ /* TODO */
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops video_ops = {
+ .s_stream = sensor_8b1_s_stream,
+ .s_parm = sensor_8b1_s_param,
+ .s_mbus_fmt = sensor_8b1_s_format
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops,
+ .video = &video_ops
+};
+
+int sensor_8b1_stream_on(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 1);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int sensor_8b1_stream_off(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 0);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+/*
+ * @ brief
+ * frame duration time
+ * @ unit
+ * nano second
+ * @ remarks
+ */
+int sensor_8b1_s_duration(struct v4l2_subdev *subdev, u64 duration)
+{
+ int ret = 0;
+ u8 value[2];
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /*
+ * forcely set 10fps for 8b1,
+ */
+ value[0] = 0x52;
+ value[1] = 0x0;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_MSB, value[1]);
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_LSB, value[0]);
+
+p_err:
+ return ret;
+}
+
+int sensor_8b1_g_min_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_g_max_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_s_exposure(struct v4l2_subdev *subdev, u64 exposure)
+{
+ int ret = 0;
+ u8 value;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s(%d)\n", __func__, (u32)exposure);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ value = exposure & 0xFF;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_AE_TARGET, value);
+
+p_err:
+ return ret;
+}
+
+int sensor_8b1_g_min_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_g_max_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_s_again(struct v4l2_subdev *subdev, u64 sensitivity)
+{
+ int ret = 0;
+
+ pr_info("%s\n", __func__);
+
+ return ret;
+}
+
+int sensor_8b1_g_min_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_g_max_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_s_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_g_min_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_8b1_g_max_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+struct fimc_is_sensor_ops module_8b1_ops = {
+ .stream_on = sensor_8b1_stream_on,
+ .stream_off = sensor_8b1_stream_off,
+ .s_duration = sensor_8b1_s_duration,
+ .g_min_duration = sensor_8b1_g_min_duration,
+ .g_max_duration = sensor_8b1_g_max_duration,
+ .s_exposure = sensor_8b1_s_exposure,
+ .g_min_exposure = sensor_8b1_g_min_exposure,
+ .g_max_exposure = sensor_8b1_g_max_exposure,
+ .s_again = sensor_8b1_s_again,
+ .g_min_again = sensor_8b1_g_min_again,
+ .g_max_again = sensor_8b1_g_max_again,
+ .s_dgain = sensor_8b1_s_dgain,
+ .g_min_dgain = sensor_8b1_g_min_dgain,
+ .g_max_dgain = sensor_8b1_g_max_dgain
+};
+
+#ifdef CONFIG_OF
+static int sensor_8b1_power_setpin(struct device *dev)
+{
+ int gpio_none = 0, gpio_reset = 0, gpio_standby = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ int gpios_cam_en = 0;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ dev_err(dev, "failed to get PIN_RESET\n");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ gpios_cam_en = of_get_named_gpio(dnode, "gpios_cam_en", 0);
+ if (!gpio_is_valid(gpios_cam_en)) {
+ dev_err(dev, "failed to get main/front cam en gpio\n");
+ } else {
+ gpio_request_one(gpios_cam_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_cam_en);
+ }
+
+ gpio_standby = of_get_named_gpio(dnode, "gpio_standby", 0);
+ if (!gpio_is_valid(gpio_standby)) {
+ dev_err(dev, "failed to get gpio_standby\n");
+ } else {
+ gpio_request_one(gpio_standby, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_standby);
+ }
+
+ /* FRONT CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpios_cam_en, 0, NULL, 1000, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* FRONT CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 3, gpios_cam_en, 0, NULL, 1000, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 4, gpio_standby, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 2, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 3, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+int sensor_8b1_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+ static bool probe_retried = false;
+
+ if (!fimc_is_dev)
+ goto probe_defer;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_S5K8B1_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ /* S5K8B1 */
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_S5K8B1_NAME;
+ module->subdev = subdev_module;
+ module->device = SENSOR_S5K8B1_INSTANCE;
+ module->ops = &module_8b1_ops;
+ module->client = client;
+ module->active_width = 1920;
+ module->active_height = 1080;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 30;
+ module->position = SENSOR_POSITION_FRONT;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_1;
+ module->sensor_maker = "SLSI";
+ module->sensor_name = "S5K8B1";
+ module->setfile_name = "setfile_8b1.bin";
+ module->cfgs = ARRAY_SIZE(config_8b1);
+ module->cfg = config_8b1;
+ module->private_data = kzalloc(sizeof(struct fimc_is_module_8b1), GFP_KERNEL);
+ if (!module->private_data) {
+ err("private_data is NULL");
+ ret = -ENOMEM;
+ kfree(subdev_module);
+ goto p_err;
+ }
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_8b1_power_setpin;
+#endif
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+ ext->sensor_con.product_name = SENSOR_NAME_S5K8B1;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client) {
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ subdev_module->internal_ops = &internal_ops;
+ } else {
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+ }
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+
+probe_defer:
+ if (probe_retried) {
+ err("probe has already been retried!!");
+ BUG();
+ }
+
+ probe_retried = true;
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+}
+
+static int sensor_8b1_remove(struct i2c_client *client)
+{
+ int ret = 0;
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_fimc_is_sensor_8b1_match[] = {
+ {
+ .compatible = "samsung,exynos5-fimc-is-sensor-8b1",
+ },
+ {},
+};
+#endif
+
+static const struct i2c_device_id sensor_8b1_idt[] = {
+ { SENSOR_NAME, 0 },
+};
+
+static struct i2c_driver sensor_8b1_driver = {
+ .driver = {
+ .name = SENSOR_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = exynos_fimc_is_sensor_8b1_match
+#endif
+ },
+ .probe = sensor_8b1_probe,
+ .remove = sensor_8b1_remove,
+ .id_table = sensor_8b1_idt
+};
+
+static int __init sensor_8b1_load(void)
+{
+ return i2c_add_driver(&sensor_8b1_driver);
+}
+
+static void __exit sensor_8b1_unload(void)
+{
+ i2c_del_driver(&sensor_8b1_driver);
+}
+
+module_init(sensor_8b1_load);
+module_exit(sensor_8b1_unload);
+
+MODULE_AUTHOR("Gilyeon lim");
+MODULE_DESCRIPTION("Sensor 8B1 driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_8B1_H
+#define FIMC_IS_DEVICE_8B1_H
+
+#define SENSOR_S5K8B1_INSTANCE 1
+#define SENSOR_S5K8B1_NAME SENSOR_NAME_S5K8B1
+
+struct fimc_is_module_8b1 {
+ u16 vis_duration;
+ u16 frame_length_line;
+ u32 line_length_pck;
+ u32 system_clock;
+};
+
+int sensor_8b1_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "fimc-is-device-imx134.h"
+
+
+#include <mach/exynos-fimc-is-sensor.h>
+#include "../fimc-is-hw.h"
+
+
+
+#define SENSOR_NAME "IMX134"
+
+static struct fimc_is_sensor_cfg config_imx134[] = {
+ /* 3280X2458@30fps */
+ FIMC_IS_SENSOR_CFG(3280, 2458, 30, 15, 0),
+ /* 3280X1846@30fps */
+ FIMC_IS_SENSOR_CFG(3280, 1846, 30, 11, 1),
+ /* 3280X2458@24fps */
+ FIMC_IS_SENSOR_CFG(3280, 2458, 24, 12, 2),
+ /* 3280X1846@24fps */
+ FIMC_IS_SENSOR_CFG(3280, 1846, 24, 9, 3),
+ /* 1936X1450@24fps */
+ FIMC_IS_SENSOR_CFG(1936, 1450, 24, 12, 4),
+ /* 1936X1090@24fps */
+ FIMC_IS_SENSOR_CFG(1936, 1090, 24, 9, 5),
+ /* 816X460@120fps */
+ FIMC_IS_SENSOR_CFG(816, 460, 120, 7, 6),
+ /* 1640X924@60fps */
+ FIMC_IS_SENSOR_CFG(1640, 924, 60, 6, 7),
+};
+
+
+static int sensor_imx134_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_imx134_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+#ifdef CONFIG_OF
+#ifdef CONFIG_COMPANION_USE
+static int sensor_imx134_power_setpin(struct device *dev)
+{
+ return 0;
+}
+#else
+static int sensor_imx134_power_setpin(struct device *dev)
+{
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ int gpio_none = 0;
+ int gpio_reset = 0, gpios_cam_en = 0;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ err("failed to get PIN_RESET");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ gpios_cam_en = of_get_named_gpio(dnode, "gpios_cam_en", 0);
+ if (!gpio_is_valid(gpios_cam_en)) {
+ err("failed to get main cam en gpio");
+ } else {
+ gpio_request_one(gpios_cam_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_cam_en);
+ }
+
+ /* BACK CAMERA - POWER ON */
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpio_none, 0, "CAM_IO_1.8V_AP", 2000, PIN_REGULATOR_ON);
+
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_none, 0, "af", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 7, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* BACK CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_OFF);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+#endif /* CONFIG_COMPANION_USE */
+#endif /* CONFIG_OF */
+
+int sensor_imx134_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ info("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_IMX134_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ info("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_IMX134;
+ module->subdev = subdev_module;
+ module->device = SENSOR_IMX134_INSTANCE;
+ module->ops = NULL;
+ module->client = client;
+ module->active_width = 3264;
+ module->active_height = 2448;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 300;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SONY";
+ module->sensor_name = "IMX134";
+ module->setfile_name = "setfile_imx134.bin";
+ module->cfgs = ARRAY_SIZE(config_imx134);
+ module->cfg = config_imx134;
+ module->ops = NULL;
+ module->private_data = NULL;
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_imx134_power_setpin;
+#endif
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = SENSOR_NAME_IMX134;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x34;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7345;//ACTUATOR_NAME_NOTHING;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x34;
+ ext->actuator_con.peri_setting.i2c.speed = 400000;
+
+#ifdef CONFIG_LEDS_MAX77804
+ ext->flash_con.product_name = FLADRV_NAME_MAX77693;
+#endif
+#ifdef CONFIG_LEDS_LM3560
+ ext->flash_con.product_name = FLADRV_NAME_LM3560;
+#endif
+#ifdef CONFIG_LEDS_SKY81296
+ ext->flash_con.product_name = FLADRV_NAME_SKY81296;
+#endif
+#ifdef CONFIG_LEDS_KTD2692
+ ext->flash_con.product_name = FLADRV_NAME_KTD2692;
+#endif
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 1;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 2;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_IMX134_H
+#define FIMC_IS_DEVICE_IMX134_H
+
+#define SENSOR_IMX134_INSTANCE 0
+#define SENSOR_IMX134_NAME SENSOR_NAME_IMX134
+
+int sensor_imx134_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
+
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-imx135.h"
+
+#define SENSOR_NAME "IMX135"
+
+static struct fimc_is_sensor_cfg config_imx135[] = {
+ /* 4144x3106@30fps */
+ FIMC_IS_SENSOR_CFG(4144, 3106, 30, 23, 0),
+ /* 4144x2332@30fps */
+ FIMC_IS_SENSOR_CFG(4144, 2332, 30, 18, 1),
+ /* 1936x1450@24fps */
+ FIMC_IS_SENSOR_CFG(1936, 1450, 24, 9, 2),
+ /* 1936x1090@24fps */
+ FIMC_IS_SENSOR_CFG(1936, 1090, 24, 7, 3),
+ /* 1024x576@120fps */
+ FIMC_IS_SENSOR_CFG(1024, 576, 120, 9, 4),
+ /* 2072x1166@60fps */
+ FIMC_IS_SENSOR_CFG(2072, 1166, 60, 18, 5),
+};
+
+static int sensor_imx135_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_imx135_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_imx135_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_IMX135_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_IMX135;
+ module->subdev = subdev_module;
+ module->device = SENSOR_IMX135_INSTANCE;
+ module->ops = NULL;
+ module->client = client;
+ module->active_width = 4128;
+ module->active_height = 3096;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 120;
+ module->sensor_maker = "SONY";
+ module->sensor_name = "IMX135";
+ module->setfile_name = "setfile_imx135.bin";
+ module->cfgs = ARRAY_SIZE(config_imx135);
+ module->cfg = config_imx135;
+ module->private_data = NULL;
+ module->lanes = CSI_DATA_LANES_4;
+
+ ext = &module->ext;
+ memset(ext, 0x0, sizeof(struct sensor_open_extended));
+ ext->mipi_lane_num = 4;
+ ext->sensor_con.product_name = 0;
+ ext->sensor_con.peri_type = SE_I2C;
+ //ext->sensor_con.peri_setting.i2c.channel = sensor_info->i2c_channel;
+ //ext->sensor_con.peri_setting.i2c.slave_address = sensor_info->sensor_slave_address;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7345;
+ ext->actuator_con.peri_type = SE_I2C;
+ //ext->actuator_con.peri_setting.i2c.channel = sensor_info->actuator_i2c;
+
+ //ext->flash_con.product_name = sensor_info->flash_id;
+ ext->flash_con.peri_type = SE_GPIO;
+ //ext->flash_con.peri_setting.gpio.first_gpio_port_no = sensor_info->flash_first_gpio;
+ //ext->flash_con.peri_setting.gpio.second_gpio_port_no = sensor_info->flash_second_gpio;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+ ext->mclk = 0;
+ ext->mipi_lane_num = 0;
+ ext->mipi_speed = 0;
+ ext->fast_open_sensor = 0;
+ ext->self_calibration_mode = 0;
+ ext->I2CSclk = I2C_L0;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_IMX135_H
+#define FIMC_IS_DEVICE_IMX135_H
+
+#define SENSOR_IMX135_INSTANCE 0
+#define SENSOR_IMX135_NAME SENSOR_NAME_IMX135
+
+int sensor_imx135_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-imx175.h"
+
+#define SENSOR_NAME "IMX175"
+
+static struct fimc_is_sensor_cfg config_imx175[] = {
+ /* 3280X2458@30fps */
+ FIMC_IS_SENSOR_CFG(3280, 2458, 30, 14, 0),
+ /* 3280X1846@30fps */
+ FIMC_IS_SENSOR_CFG(3280, 1846, 30, 11, 1),
+ /* 3280X2458@24fps */
+ FIMC_IS_SENSOR_CFG(3280, 2458, 24, 11, 2),
+ /* 3280X1846@24fps */
+ FIMC_IS_SENSOR_CFG(3280, 1846, 24, 8, 3),
+ /* 1640X924@60fps */
+ FIMC_IS_SENSOR_CFG(1640, 924, 60, 11, 4),
+ /* 816X460@120fps */
+ FIMC_IS_SENSOR_CFG(816, 460, 120, 11, 5),
+};
+
+static int sensor_imx175_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_imx175_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+int sensor_imx175_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_IMX175_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_IMX175;
+ module->subdev = subdev_module;
+ module->device = SENSOR_IMX175_INSTANCE;
+ module->ops = NULL;
+ module->client = client;
+ module->active_width = 3264;
+ module->active_height = 2448;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 120;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SONY";
+ module->sensor_name = "IMX175";
+ module->setfile_name = "setfile_imx175.bin";
+ module->cfgs = ARRAY_SIZE(config_imx175);
+ module->cfg = config_imx175;
+ module->ops = NULL;
+ module->private_data = NULL;
+
+ ext = &module->ext;
+ ext->mipi_lane_num = 4;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = 0;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x18;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7343;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel
+ = SENSOR_CONTROL_I2C0;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x18;
+
+ ext->flash_con.product_name = FLADRV_NAME_MAX77693;
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 0;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 1;
+
+ /* ext->from_con.product_name = FROMDRV_NAME_W25Q80BW; */
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+ ext->mclk = 0;
+ ext->mipi_lane_num = 0;
+ ext->mipi_speed = 0;
+ ext->fast_open_sensor = 0;
+ ext->self_calibration_mode = 0;
+ ext->I2CSclk = I2C_L0;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_IMX175_H
+#define FIMC_IS_DEVICE_IMX175_H
+
+#define SENSOR_IMX175_INSTANCE 0
+#define SENSOR_IMX175_NAME SENSOR_NAME_IMX175
+
+int sensor_imx175_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-imx219.h"
+
+#define SENSOR_NAME "IMX219"
+#define DEFAULT_SENSOR_WIDTH 184
+#define DEFAULT_SENSOR_HEIGHT 104
+#define SENSOR_MEMSIZE DEFAULT_SENSOR_WIDTH * DEFAULT_SENSOR_HEIGHT
+
+#define SENSOR_REG_VIS_DURATION_MSB (0x6026)
+#define SENSOR_REG_VIS_DURATION_LSB (0x6027)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_MSB (0x4340)
+#define SENSOR_REG_VIS_FRAME_LENGTH_LINE_ALV_LSB (0x4341)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_MSB (0x4342)
+#define SENSOR_REG_VIS_LINE_LENGTH_PCLK_ALV_LSB (0x4343)
+#define SENSOR_REG_VIS_GAIN_RED (0x6029)
+#define SENSOR_REG_VIS_GAIN_GREEN (0x602A)
+#define SENSOR_REG_VIS_AE_TARGET (0x600A)
+#define SENSOR_REG_VIS_AE_SPEED (0x5034)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_MSB (0x5030)
+#define SENSOR_REG_VIS_AE_NUMBER_OF_PIXEL_LSB (0x5031)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x1_2 (0x6000)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_1x3_4 (0x6001)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x1_2 (0x6002)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_2x3_4 (0x6003)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x1_2 (0x6004)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_3x3_4 (0x6005)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x1_2 (0x6006)
+#define SENSOR_REG_VIS_AE_WINDOW_WEIGHT_4x3_4 (0x6007)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_MSB (0x5039)
+#define SENSOR_REG_VIS_AE_MANUAL_EXP_LSB (0x503A)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_MSB (0x503B)
+#define SENSOR_REG_VIS_AE_MANUAL_ANG_LSB (0x503C)
+#define SENSOR_REG_VIS_BIT_CONVERTING_MSB (0x602B)
+#define SENSOR_REG_VIS_BIT_CONVERTING_LSB (0x7203)
+#define SENSOR_REG_VIS_AE_OFF (0x5000)
+
+static u16 setfile_vision_imx219[][2] = {
+ {0x4200, 0x02},
+ {0x4201, 0xAE},
+ {0x4301, 0x04},
+ {0x4309, 0x04},
+ {0x4345, 0x08},
+ {0x4347, 0x08},
+ {0x4348, 0x0A},
+ {0x4349, 0x01},
+ {0x434A, 0x05},
+ {0x434B, 0xA0},
+ {0x434C, 0x01},
+ {0x434D, 0x40},
+ {0x434E, 0x00},
+ {0x434F, 0xB4},
+ {0x4381, 0x01},
+ {0x4383, 0x07},
+ {0x4385, 0x08},
+ {0x4387, 0x08},
+ {0x5004, 0x01},
+ {0x5005, 0x1E},
+ {0x5014, 0x11},
+ {0x5015, 0x9E},
+ {0x5016, 0x00},
+ {0x5017, 0x02},
+ {0x5030, 0x1C},
+ {0x5031, 0x20},
+ {0x5034, 0x00},
+ {0x5035, 0x02},
+ {0x5036, 0x00},
+ {0x5037, 0x06},
+ {0x5038, 0xC0},
+ {0x5039, 0x00},
+ {0x503A, 0x00},
+ {0x503B, 0x00},
+ {0x503C, 0x00},
+ {0x503D, 0x20},
+ {0x503E, 0x70},
+ {0x503F, 0x02},
+ {0x600A, 0x2A},
+ {0x600E, 0x05},
+ {0x6014, 0x27},
+ {0x6015, 0x1D},
+ {0x6018, 0x01},
+ {0x6026, 0x00},
+ {0x6027, 0x68},
+ {0x6029, 0x08},
+ {0x602A, 0x08},
+ {0x602B, 0x00},
+ {0x602C, 0x00},
+ {0x7008, 0x00},
+ {0x7009, 0x10},
+ {0x700A, 0x00},
+ {0x700B, 0x10},
+ {0x7014, 0x2B},
+ {0x7015, 0x91},
+ {0x7016, 0x82},
+ {0x701B, 0x16},
+ {0x701D, 0x0B},
+ {0x701F, 0x0B},
+ {0x7026, 0x1A},
+ {0x7027, 0x46},
+ {0x7029, 0x14},
+ {0x702A, 0x02},
+ {0x7038, 0x01},
+ {0x7039, 0x14},
+ {0x703A, 0x32},
+ {0x703B, 0x22},
+ {0x7040, 0x01},
+ {0x7041, 0x14},
+ {0x7042, 0x32},
+ {0x7043, 0x22},
+ {0x7050, 0x0A},
+ {0x7051, 0xA8},
+ {0x7052, 0x35},
+ {0x7053, 0x54},
+ {0x7054, 0x00},
+ {0x7055, 0x00},
+ {0x7056, 0x00},
+ {0x7057, 0x00},
+ {0x705E, 0x0E},
+ {0x705F, 0x10},
+ {0x7060, 0x01},
+ {0x7064, 0x05},
+ {0x7065, 0x3C},
+ {0x7066, 0x00},
+ {0x7067, 0x00},
+ {0x7068, 0x4A},
+ {0x706C, 0x01},
+ {0x7077, 0x88},
+ {0x7078, 0x88},
+ {0x7082, 0x90},
+ {0x7091, 0x05},
+ {0x7098, 0x00},
+ {0x7112, 0x01},
+ {0x720A, 0x06},
+ {0x720B, 0x80},
+ {0x7245, 0xC1},
+ {0x7301, 0x01},
+ {0x7305, 0x13},
+ {0x7306, 0x01},
+ {0x7323, 0x01},
+ {0x7339, 0x07},
+ {0x7351, 0x01},
+ {0x7352, 0x24},
+ {0x7405, 0x28},
+ {0x7406, 0x28},
+ {0x7407, 0xC0},
+ {0x7454, 0x01},
+ {0x7460, 0x01},
+ {0x7461, 0x20},
+ {0x7462, 0xC0},
+ {0x7463, 0x1E},
+ {0x7464, 0x02},
+ {0x7465, 0x4B},
+ {0x7467, 0x20},
+ {0x7468, 0x20},
+ {0x7469, 0x20},
+ {0x746A, 0x20},
+ {0x746B, 0x20},
+ {0x746C, 0x20},
+ {0x746D, 0x09},
+ {0x746E, 0xFF},
+ {0x746F, 0x01},
+ {0x7472, 0x00},
+ {0x7473, 0x02},
+ {0x7474, 0xC1},
+ {0x7475, 0x00},
+ {0x7476, 0x00},
+ {0x7477, 0x00},
+ {0x7478, 0x00},
+ {0x4100, 0x01},
+};
+
+static struct fimc_is_sensor_cfg config_imx219[] = {
+ /* 3280X2458@20fps */
+ FIMC_IS_SENSOR_CFG(3280, 2458, 20, 19, 0),
+ /* 3280X1846@20fps */
+ FIMC_IS_SENSOR_CFG(3280, 1846, 20, 15, 1),
+ /* 1640X1228@24fps */
+ FIMC_IS_SENSOR_CFG(1640, 1228, 24, 12, 2),
+ /* 3280X1846@24fps */
+ FIMC_IS_SENSOR_CFG(3280, 1846, 24, 17, 3),
+};
+
+static int sensor_imx219_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_imx219_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+static int sensor_imx219_registered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static void sensor_imx219_unregistered(struct v4l2_subdev *sd)
+{
+ pr_info("%s\n", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops internal_ops = {
+ .open = sensor_imx219_open,
+ .close = sensor_imx219_close,
+ .registered = sensor_imx219_registered,
+ .unregistered = sensor_imx219_unregistered,
+};
+
+static int sensor_imx219_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int i, ret = 0;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_module_imx219 *module_imx219;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ module_imx219 = module->private_data;
+ client = module->client;
+
+ module_imx219->system_clock = 146 * 1000 * 1000;
+ module_imx219->line_length_pck = 146 * 1000 * 1000;
+
+ pr_info("%s\n", __func__);
+
+ /* sensor init */
+ for (i = 0; i < ARRAY_SIZE(setfile_vision_imx219); i++) {
+ fimc_is_sensor_write8(client, setfile_vision_imx219[i][0],
+ (u8)setfile_vision_imx219[i][1]);
+ }
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_imx219_init
+};
+
+static int sensor_imx219_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (enable) {
+ ret = CALL_MOPS(sensor, stream_on, subdev);
+ if (ret < 0) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ } else {
+ ret = CALL_MOPS(sensor, stream_off, subdev);
+ if (ret < 0) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+ }
+
+p_err:
+ return 0;
+}
+
+static int sensor_imx219_s_param(struct v4l2_subdev *subdev, struct v4l2_streamparm *param)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct v4l2_captureparm *cp;
+ struct v4l2_fract *tpf;
+ u64 duration;
+
+ BUG_ON(!subdev);
+ BUG_ON(!param);
+
+ pr_info("%s\n", __func__);
+
+ cp = ¶m->parm.capture;
+ tpf = &cp->timeperframe;
+
+ if (!tpf->denominator) {
+ err("denominator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!tpf->numerator) {
+ err("numerator is 0");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ duration = (u64)(tpf->numerator * 1000 * 1000 * 1000) /
+ (u64)(tpf->denominator);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (!sensor) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = CALL_MOPS(sensor, s_duration, subdev, duration);
+ if (ret) {
+ err("s_duration is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+static int sensor_imx219_s_format(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *fmt)
+{
+ /* TODO */
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops video_ops = {
+ .s_stream = sensor_imx219_s_stream,
+ .s_parm = sensor_imx219_s_param,
+ .s_mbus_fmt = sensor_imx219_s_format
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops,
+ .video = &video_ops
+};
+
+int sensor_imx219_stream_on(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 1);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int sensor_imx219_stream_off(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ ret = fimc_is_sensor_write8(client, 0x4100, 0);
+ if (ret < 0) {
+ err("fimc_is_sensor_write8 is fail(%d)", ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+/*
+ * @ brief
+ * frame duration time
+ * @ unit
+ * nano second
+ * @ remarks
+ */
+int sensor_imx219_s_duration(struct v4l2_subdev *subdev, u64 duration)
+{
+ int ret = 0;
+ u8 value[2];
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s\n", __func__);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ /*
+ * forcely set 10fps for IMX219,
+ */
+ value[0] = 0x52;
+ value[1] = 0x0;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_MSB, value[1]);
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_DURATION_LSB, value[0]);
+
+p_err:
+ return ret;
+}
+
+int sensor_imx219_g_min_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_g_max_duration(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_s_exposure(struct v4l2_subdev *subdev, u64 exposure)
+{
+ int ret = 0;
+ u8 value;
+ struct fimc_is_module_enum *sensor;
+ struct i2c_client *client;
+
+ BUG_ON(!subdev);
+
+ pr_info("%s(%d)\n", __func__, (u32)exposure);
+
+ sensor = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+ if (unlikely(!sensor)) {
+ err("sensor is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ client = sensor->client;
+ if (unlikely(!client)) {
+ err("client is NULL");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ value = exposure & 0xFF;
+
+ fimc_is_sensor_write8(client, SENSOR_REG_VIS_AE_TARGET, value);
+
+p_err:
+ return ret;
+}
+
+int sensor_imx219_g_min_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_g_max_exposure(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_s_again(struct v4l2_subdev *subdev, u64 sensitivity)
+{
+ int ret = 0;
+
+ pr_info("%s\n", __func__);
+
+ return ret;
+}
+
+int sensor_imx219_g_min_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_g_max_again(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_s_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_g_min_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+int sensor_imx219_g_max_dgain(struct v4l2_subdev *subdev)
+{
+ int ret = 0;
+ return ret;
+}
+
+struct fimc_is_sensor_ops module_imx219_ops = {
+ .stream_on = sensor_imx219_stream_on,
+ .stream_off = sensor_imx219_stream_off,
+ .s_duration = sensor_imx219_s_duration,
+ .g_min_duration = sensor_imx219_g_min_duration,
+ .g_max_duration = sensor_imx219_g_max_duration,
+ .s_exposure = sensor_imx219_s_exposure,
+ .g_min_exposure = sensor_imx219_g_min_exposure,
+ .g_max_exposure = sensor_imx219_g_max_exposure,
+ .s_again = sensor_imx219_s_again,
+ .g_min_again = sensor_imx219_g_min_again,
+ .g_max_again = sensor_imx219_g_max_again,
+ .s_dgain = sensor_imx219_s_dgain,
+ .g_min_dgain = sensor_imx219_g_min_dgain,
+ .g_max_dgain = sensor_imx219_g_max_dgain
+};
+
+#ifdef CONFIG_OF
+static int sensor_imx219_power_setpin(struct device *dev)
+{
+ int gpio_none = 0, gpio_reset = 0, gpio_standby = 0;
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ struct pinctrl *pinctrl_ch = NULL;
+
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ dev_err(dev, "failed to get PIN_RESET\n");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ gpio_standby = of_get_named_gpio(dnode, "gpio_standby", 0);
+ if (!gpio_is_valid(gpio_standby)) {
+ dev_err(dev, "failed to get gpio_standby\n");
+ } else {
+ gpio_request_one(gpio_standby, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_standby);
+ }
+
+ /* initial - i2c off */
+ pinctrl_ch = devm_pinctrl_get_select(dev, "off1");
+ if (IS_ERR_OR_NULL(pinctrl_ch)) {
+ pr_err("%s: cam %s pins are not configured\n", __func__, "off1");
+ } else {
+ devm_pinctrl_put(pinctrl_ch);
+ }
+
+ /* FRONT CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* FRONT CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 1, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 2, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 3, gpio_none, 0, "VT_CAM_1.2V", 1000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 4, gpio_standby, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 5, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* VISION CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 0, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 2, gpio_standby, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 3, gpio_none, 0, "VT_CAM_1.2V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VT_CAM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 5, gpio_none, 0, "VT_CAM_1.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF, 6, gpio_none, 0, NULL, 0, PIN_END);
+
+ return 0;
+}
+#endif
+
+int sensor_imx219_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+ static bool probe_retried = false;
+
+ if (!fimc_is_dev)
+ goto probe_defer;
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_IMX219_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ /* IMX219 */
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_IMX219_NAME;
+ module->subdev = subdev_module;
+ module->device = SENSOR_IMX219_INSTANCE;
+ module->ops = &module_imx219_ops;
+ module->client = client;
+ module->active_width = 3264;
+ module->active_height = 2448;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 24;
+ module->position = SENSOR_POSITION_FRONT;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_2;
+ module->sensor_maker = "SONY";
+ module->sensor_name = "IMX219";
+ module->setfile_name = "setfile_imx219.bin";
+ module->cfgs = ARRAY_SIZE(config_imx219);
+ module->cfg = config_imx219;
+ module->private_data = kzalloc(sizeof(struct fimc_is_module_imx219), GFP_KERNEL);
+ if (!module->private_data) {
+ err("private_data is NULL");
+ ret = -ENOMEM;
+ kfree(subdev_module);
+ goto p_err;
+ }
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_imx219_power_setpin;
+#endif
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+ ext->sensor_con.product_name = SENSOR_NAME_IMX219;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x34;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+
+ if (client) {
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ subdev_module->internal_ops = &internal_ops;
+ } else {
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+ }
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+
+probe_defer:
+ if (probe_retried) {
+ err("probe has already been retried!!");
+ BUG();
+ }
+
+ probe_retried = true;
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+}
+
+static int sensor_imx219_remove(struct i2c_client *client)
+{
+ int ret = 0;
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id exynos_fimc_is_sensor_imx219_match[] = {
+ {
+ .compatible = "samsung,exynos5-fimc-is-sensor-imx219",
+ },
+ {},
+};
+#endif
+
+static const struct i2c_device_id sensor_imx219_idt[] = {
+ { SENSOR_NAME, 0 },
+};
+
+static struct i2c_driver sensor_imx219_driver = {
+ .driver = {
+ .name = SENSOR_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = exynos_fimc_is_sensor_imx219_match
+#endif
+ },
+ .probe = sensor_imx219_probe,
+ .remove = sensor_imx219_remove,
+ .id_table = sensor_imx219_idt
+};
+
+static int __init sensor_imx219_load(void)
+{
+ return i2c_add_driver(&sensor_imx219_driver);
+}
+
+static void __exit sensor_imx219_unload(void)
+{
+ i2c_del_driver(&sensor_imx219_driver);
+}
+
+module_init(sensor_imx219_load);
+module_exit(sensor_imx219_unload);
+
+MODULE_AUTHOR("Gilyeon lim");
+MODULE_DESCRIPTION("Sensor IMX219 driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_IMX219_H
+#define FIMC_IS_DEVICE_IMX219_H
+
+#define SENSOR_IMX219_INSTANCE 1
+#define SENSOR_IMX219_NAME SENSOR_NAME_IMX219
+
+struct fimc_is_module_imx219 {
+ u16 vis_duration;
+ u16 frame_length_line;
+ u32 line_length_pck;
+ u32 system_clock;
+};
+
+int sensor_imx219_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/exynos-fimc-is-sensor.h>
+
+#include "../fimc-is-core.h"
+#include "../fimc-is-device-sensor.h"
+#include "../fimc-is-resourcemgr.h"
+#include "../fimc-is-hw.h"
+#include "fimc-is-device-imx240.h"
+
+#define SENSOR_NAME "IMX240"
+
+static struct fimc_is_sensor_cfg config_imx240[] = {
+ /* 5328x3000@30fps */
+ FIMC_IS_SENSOR_CFG(5328, 3000, 30, 30, 0),
+ /* 5328x3000@24fps */
+ FIMC_IS_SENSOR_CFG(5328, 3000, 24, 29, 1),
+ /* 4000X3000@30fps */
+ FIMC_IS_SENSOR_CFG(4000, 3000, 30, 23, 2),
+ /* 4000X3000@24fps */
+ FIMC_IS_SENSOR_CFG(4000, 3000, 24, 19, 3),
+ /* 3008X3000@30fps */
+ FIMC_IS_SENSOR_CFG(3008, 3000, 30, 19, 4),
+ /* 3008X3000@30fps */
+ FIMC_IS_SENSOR_CFG(3008, 3000, 24, 14, 5),
+ /* 2664X1500@60fps */
+ FIMC_IS_SENSOR_CFG(2664, 1500, 60, 15, 6),
+ /* 2664X1500@30fps */
+ FIMC_IS_SENSOR_CFG(2664, 1500, 30, 15, 7),
+ /* 1328X748@120fps */
+ FIMC_IS_SENSOR_CFG(1328, 748, 120, 13, 8),
+ /* 824X496@300fps */
+ //FIMC_IS_SENSOR_CFG(824, 496, 300, 13, 8),
+};
+
+static int sensor_imx240_init(struct v4l2_subdev *subdev, u32 val)
+{
+ int ret = 0;
+ struct fimc_is_module_enum *module;
+
+ BUG_ON(!subdev);
+
+ module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev);
+
+ pr_info("[MOD:D:%d] %s(%d)\n", module->id, __func__, val);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops core_ops = {
+ .init = sensor_imx240_init
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &core_ops
+};
+
+#ifdef CONFIG_OF
+#ifdef CONFIG_COMPANION_USE
+static int sensor_imx240_power_setpin(struct device *dev)
+{
+ struct exynos_platform_fimc_is_sensor *pdata;
+ struct device_node *dnode;
+ int gpio_comp_en = 0, gpio_comp_rst = 0;
+ int gpio_none = 0;
+ int gpio_reset = 0;
+ int gpios_cam_en = -EINVAL;
+#ifdef CONFIG_OIS_USE
+ int gpios_ois_en = 0;
+#endif
+ BUG_ON(!dev);
+ BUG_ON(!dev->platform_data);
+
+ dnode = dev->of_node;
+ pdata = dev->platform_data;
+
+ gpio_comp_en = of_get_named_gpio(dnode, "gpios_comp_en", 0);
+ if (!gpio_is_valid(gpio_comp_en)) {
+ dev_err(dev, "failed to get main comp en gpio\n");
+ } else {
+ gpio_request_one(gpio_comp_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_comp_en);
+ }
+
+ gpio_comp_rst = of_get_named_gpio(dnode, "gpios_comp_reset", 0);
+ if (!gpio_is_valid(gpio_comp_rst)) {
+ dev_err(dev, "failed to get main comp reset gpio\n");
+ } else {
+ gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_comp_rst);
+ }
+
+ gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0);
+ if (!gpio_is_valid(gpio_reset)) {
+ dev_err(dev, "failed to get PIN_RESET\n");
+ return -EINVAL;
+ } else {
+ gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpio_reset);
+ }
+
+ if (of_get_property(dnode, "gpios_cam_en", NULL)) {
+ gpios_cam_en = of_get_named_gpio(dnode, "gpios_cam_en", 0);
+ if (!gpio_is_valid(gpios_cam_en)) {
+ dev_err(dev, "failed to get main cam en gpio\n");
+ } else {
+ gpio_request_one(gpios_cam_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_cam_en);
+ }
+ }
+
+#ifdef CONFIG_OIS_USE
+ gpios_ois_en = of_get_named_gpio(dnode, "gpios_ois_en", 0);
+ pdata->pin_ois_en = gpios_ois_en;
+ if (!gpio_is_valid(gpios_ois_en)) {
+ dev_err(dev, "failed to get ois en gpio\n");
+ } else {
+ gpio_request_one(gpios_ois_en, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW");
+ gpio_free(gpios_ois_en);
+ }
+#endif
+
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 0, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 1, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 2, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_ON);
+#ifdef CONFIG_OIS_USE
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 3, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 4, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_ON);
+#endif
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 5, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 6, gpio_none, 0, "VDDA_1.8V_COMP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 7, gpio_comp_en, 0, NULL, 150, PIN_OUTPUT_HIGH);
+ if (pdata->companion_use_pmic) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 8, gpio_none, 0, "VDD_MIPI_1.0V_COMP", 0, PIN_REGULATOR_ON);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 9, gpio_comp_rst, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 10, gpio_none, 0, "ch", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 11, gpio_none, 0, "af", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 12, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, 13, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* BACK CAMERA - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 1, gpio_none, 0, "off", 0, PIN_FUNCTION);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 2, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 3, gpio_comp_rst, 0, NULL, 0, PIN_OUTPUT_LOW);
+ if (pdata->companion_use_pmic) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "VDD_MIPI_1.0V_COMP", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 5, gpio_comp_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 6, gpio_none, 0, "VDDA_1.8V_COMP", 0, PIN_REGULATOR_OFF);
+ if (gpio_is_valid(gpios_cam_en)) {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 7, gpios_cam_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ } else {
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 7, gpio_none, 0, "CAM_SEN_A2.8V_AP", 0, PIN_REGULATOR_OFF);
+ }
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 8, gpio_none, 0, "CAM_SEN_CORE_1.2V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 9, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_OFF);
+#ifdef CONFIG_OIS_USE
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 10, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 11, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_OFF);
+#endif
+ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, 12, gpio_none, 0, NULL, 0, PIN_END);
+
+#ifdef CONFIG_OIS_USE
+ /* OIS_FACTORY - POWER ON */
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 1, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 2, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 3, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_ON);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 4, gpio_reset, 0, NULL, 0, PIN_OUTPUT_HIGH);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, 5, gpio_none, 0, NULL, 0, PIN_END);
+
+ /* OIS_FACTORY - POWER OFF */
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 0, gpio_none, 0, "CAM_AF_2.8V_AP", 2000, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 1, gpio_reset, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 2, gpio_none, 0, "CAM_IO_1.8V_AP", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 3, gpios_ois_en, 0, NULL, 0, PIN_OUTPUT_LOW);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 4, gpio_none, 0, "OIS_VM_2.8V", 0, PIN_REGULATOR_OFF);
+ SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, 5, gpio_none, 0, NULL, 0, PIN_END);
+#endif
+
+ return 0;
+}
+#else
+static int sensor_imx240_power_setpin(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_COMPANION_USE */
+#endif /* CONFIG_OF */
+
+int sensor_imx240_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct fimc_is_core *core;
+ struct v4l2_subdev *subdev_module;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_sensor *device;
+ struct sensor_open_extended *ext;
+
+ BUG_ON(!fimc_is_dev);
+
+ core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev);
+ if (!core) {
+ err("core device is not yet probed");
+ return -EPROBE_DEFER;
+ }
+
+ device = &core->sensor[SENSOR_IMX240_INSTANCE];
+
+ subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (!subdev_module) {
+ err("subdev_module is NULL");
+ ret = -ENOMEM;
+ goto p_err;
+ }
+
+ module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)];
+ atomic_inc(&core->resourcemgr.rsccount_module);
+ module->id = SENSOR_NAME_IMX240;
+ module->subdev = subdev_module;
+ module->device = SENSOR_IMX240_INSTANCE;
+ module->client = client;
+ module->active_width = 5312;
+ module->active_height = 2990;
+ module->pixel_width = module->active_width + 16;
+ module->pixel_height = module->active_height + 10;
+ module->max_framerate = 300;
+ module->position = SENSOR_POSITION_REAR;
+ module->mode = CSI_MODE_CH0_ONLY;
+ module->lanes = CSI_DATA_LANES_4;
+ module->sensor_maker = "SONY";
+ module->sensor_name = "IMX240";
+ module->setfile_name = "setfile_imx240.bin";
+ module->cfgs = ARRAY_SIZE(config_imx240);
+ module->cfg = config_imx240;
+ module->ops = NULL;
+ module->private_data = NULL;
+#ifdef CONFIG_OF
+ module->power_setpin = sensor_imx240_power_setpin;
+#endif
+
+ ext = &module->ext;
+ ext->mipi_lane_num = module->lanes;
+ ext->I2CSclk = I2C_L0;
+
+ ext->sensor_con.product_name = SENSOR_NAME_IMX240;
+ ext->sensor_con.peri_type = SE_I2C;
+ ext->sensor_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C0;
+ ext->sensor_con.peri_setting.i2c.slave_address = 0x34;
+ ext->sensor_con.peri_setting.i2c.speed = 400000;
+
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7345;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->actuator_con.peri_setting.i2c.slave_address = 0x34;
+ ext->actuator_con.peri_setting.i2c.speed = 400000;
+
+#ifdef CONFIG_LEDS_MAX77804
+ ext->flash_con.product_name = FLADRV_NAME_MAX77693;
+#endif
+#ifdef CONFIG_LEDS_LM3560
+ ext->flash_con.product_name = FLADRV_NAME_LM3560;
+#endif
+#ifdef CONFIG_LEDS_SKY81296
+ ext->flash_con.product_name = FLADRV_NAME_SKY81296;
+#endif
+#ifdef CONFIG_LEDS_KTD2692
+ ext->flash_con.product_name = FLADRV_NAME_KTD2692;
+#endif
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 1;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 2;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+
+#ifdef CONFIG_COMPANION_USE
+ ext->companion_con.product_name = COMPANION_NAME_73C1;
+ ext->companion_con.peri_info0.valid = true;
+ ext->companion_con.peri_info0.peri_type = SE_SPI;
+ ext->companion_con.peri_info0.peri_setting.spi.channel = (int) core->companion_spi_channel;
+ ext->companion_con.peri_info1.valid = true;
+ ext->companion_con.peri_info1.peri_type = SE_I2C;
+ ext->companion_con.peri_info1.peri_setting.i2c.channel = 0;
+ ext->companion_con.peri_info1.peri_setting.i2c.slave_address = 0x7A;
+ ext->companion_con.peri_info1.peri_setting.i2c.speed = 400000;
+ ext->companion_con.peri_info2.valid = true;
+ ext->companion_con.peri_info2.peri_type = SE_FIMC_LITE;
+ ext->companion_con.peri_info2.peri_setting.fimc_lite.channel = FLITE_ID_D;
+#else
+ ext->companion_con.product_name = COMPANION_NAME_NOTHING;
+#endif
+
+#if defined(CONFIG_OIS_USE)
+ ext->ois_con.product_name = OIS_NAME_IDG2030;
+ ext->ois_con.peri_type = SE_I2C;
+ ext->ois_con.peri_setting.i2c.channel = SENSOR_CONTROL_I2C1;
+ ext->ois_con.peri_setting.i2c.slave_address = 0x48;
+ ext->ois_con.peri_setting.i2c.speed = 400000;
+#else
+ ext->ois_con.product_name = OIS_NAME_NOTHING;
+ ext->ois_con.peri_type = SE_NULL;
+#endif
+
+ if (client)
+ v4l2_i2c_subdev_init(subdev_module, client, &subdev_ops);
+ else
+ v4l2_subdev_init(subdev_module, &subdev_ops);
+
+ v4l2_set_subdevdata(subdev_module, module);
+ v4l2_set_subdev_hostdata(subdev_module, device);
+ snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->id);
+
+p_err:
+ info("%s(%d)\n", __func__, ret);
+ return ret;
+}
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series Sensor driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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 FIMC_IS_DEVICE_IMX240_H
+#define FIMC_IS_DEVICE_IMX240_H
+
+#define SENSOR_IMX240_INSTANCE 0
+#define SENSOR_IMX240_NAME SENSOR_NAME_IMX240
+
+int sensor_imx240_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+
+#endif