diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index d01bc476283f427712362e743905413b2249d9d0..6c9739962a85cae31ade4d43dc1f9d57c3c96490 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -37,7 +37,10 @@ if MSMB_CAMERA if SEC_FORTUNA_PROJECT source "drivers/media/platform/msm/camera_v2_fortuna/Kconfig" endif # SEC_FORTUNA_PROJECT -if !(SEC_FORTUNA_PROJECT) +if MACH_J5LTE_CHN_CMCC +source "drivers/media/platform/msm/camera_v2_j5/Kconfig" +endif # SEC_J5_PROJECT +if !(SEC_FORTUNA_PROJECT || MACH_J5LTE_CHN_CMCC) source "drivers/media/platform/msm/camera_v2/Kconfig" endif # SEC_FORTUNA_PROJECT endif # MSMB_CAMERA diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile index 633502101bb34125d8c544ec63c25e8e2df8fd46..bb77a7559bd8af8c084b7e657d4340f78e89615a 100644 --- a/drivers/media/platform/msm/Makefile +++ b/drivers/media/platform/msm/Makefile @@ -7,7 +7,9 @@ obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/ obj-y += broadcast/ obj-$(CONFIG_DVB_MPQ) += dvb/ -ifeq ($(CONFIG_SEC_FORTUNA_PROJECT),y) +ifeq ($(CONFIG_MACH_J5LTE_CHN_CMCC),y) +obj-$(CONFIG_MSMB_CAMERA) += camera_v2_j5/ +else ifeq ($(CONFIG_SEC_FORTUNA_PROJECT),y) obj-$(CONFIG_MSMB_CAMERA) += camera_v2_fortuna/ else obj-$(CONFIG_MSMB_CAMERA) += camera_v2/ diff --git a/drivers/media/platform/msm/camera_v2_j5/Kconfig b/drivers/media/platform/msm/camera_v2_j5/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..cc8e01b44c9cf41ff74d41f68e6dba73dabcc486 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/Kconfig @@ -0,0 +1,341 @@ +config MSM_CAMERA_SENSOR + bool "Qualcomm MSM camera sensor support" + depends on MSMB_CAMERA + ---help--- + This flag enables support for Camera Sensor. + The sensor driver is capable of providing real time + data for camera support. The driver support V4L2 + subdev APIs. + +config MSM_CPP + bool "Qualcomm MSM Camera Post Processing Engine support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Post-processing Engine + The Post processing engine is capable of scaling + and cropping image. The driver support V4L2 subdev + APIs. + +config MSM_CCI + bool "Qualcomm MSM Camera Control Interface support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Control Interface driver only + for those platforms that have hardware support. This driver + is responsible for handling I2C read and write on the I2C + bus. It is also responsible for synchronization with + GPIO and data frames. + +config MSM_CSI20_HEADER + bool "Qualcomm MSM CSI 2.0 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 2.0 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required targets based on 8960, + 8930 and 8064 platforms. + +config MSM_CSI22_HEADER + bool "Qualcomm MSM CSI 2.2 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 2.2 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required targets based on 8610 + platform. + +config MSM_CSI30_HEADER + bool "Qualcomm MSM CSI 3.0 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 3.0 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required for targets based on + 8064 platforms. + +config MSM_CSI31_HEADER + bool "Qualcomm MSM CSI 3.1 Header" + depends on MSMB_CAMERA + ---help--- + Enable support for CSI drivers to include 3.0 + header. This header has register macros and its + values and bit mask for register configuration bits + This config macro is required for targets based on + APQ8084 platform. + +config MSM_CSIPHY + bool "Qualcomm MSM Camera Serial Interface Physical receiver support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Serial Interface + Physical receiver. It deserializes packets and + supports detection of packet start and stop + signalling. + +config MSM_CSID + bool "Qualcomm MSM Camera Serial Interface decoder support" + depends on MSMB_CAMERA + ---help--- + Enable support for Camera Serial Interface decoder. + It supports lane merging and decoding of packets + based on cid which is mapped to a virtual channel + and datatype. + +config MSM_EEPROM + bool "Qualcomm MSM Camera ROM Interface for Calibration support" + depends on MSMB_CAMERA + ---help--- + Enable support for ROM Interface for Calibration + Provides interface for reading the Claibration data. + and also provides support for writing data in case of FLASH ROM. + Currently supports I2C, CCI and SPI protocol + +config MSM_OTP + bool "Qualcomm MSM Camera ROM Interface for Calibration support" + depends on MSMB_CAMERA + ---help--- + Enable support for ROM Interface for Calibration + Provides interface for reading the Claibration data. + and also provides support for writing data + +config MSM_ISPIF + bool "Qualcomm MSM Image Signal Processing interface support" + depends on MSMB_CAMERA + ---help--- + Enable support for Image Signal Processing interface module. + This module acts as a crossbar between CSID and VFE. Output + of any CID of CSID can be routed to of of pixel or raw + data interface in VFE. + +config MSM_ISPIF_V1 + bool "Qualcomm MSM Image Signal Processing interface support" + depends on MSMB_CAMERA + ---help--- + Enable support for Image Signal Processing interface module. + This module acts as a crossbar between CSID and VFE. Output + of any CID of MSM_CSI22_HEADER can be routed to of pixel + or raw data interface in VFE. + +config IMX134 + bool "Sensor IMX134 (BAYER 8M)" + depends on MSMB_CAMERA + ---help--- + Sony 8 MP Bayer Sensor with auto focus, uses + 4 mipi lanes full resolution @30fps and + HFR @60fps and @120fps, + Video HDR support. + +config CAMERA_SYSFS_V2 + bool "CAMERA SYS" + depends on MSMB_CAMERA + ---help--- + CAMERA SYS. + +config IMX132 + bool "Sensor IMX132 (BAYER 2M)" + depends on MSMB_CAMERA + ---help--- + Sony 2 MP Bayer Sensor with auto focus, uses + 2 mipi lanes, preview config = 1920 x 1080 at 30 fps, + snapshot config = 1920 x 1080 at 30 fps, + Video HDR support. + +config IMX219 + bool "Sensor IMX219 (BAYER 8M)" + depends on MSMB_CAMERA + ---help--- + Sony 8 MP Bayer Sensor with auto focus, uses + 4 mipi lanes full resolution @30fps. + +config OV9724 + bool "Sensor OV9724 (BAYER 2M)" + depends on MSMB_CAMERA + ---help--- + OmniVision 2 MP Bayer Sensor, supports 2 mipi lanes, + preview and snapshot config at 1280*720 at 30 fps, + hfr video at 60, 90 and 120 fps. This sensor driver does + not support auto focus. + +config HI256 + bool "Hynix hi256 (YUV 2MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 8 MP Bayer Sensor with auto focus.uses + 2 mipi lanes, preview config = 1632*1224 30 fps, + snapshot config = 3264 * 2448 at 18 fps. + 2 lanes max fps is 18, 4 lanes max fps is 24. + +config OV5648 + bool "Sensor OV5648 (BAYER 5M)" + depends on MSMB_CAMERA + ---help--- + OmniVision 5 MP Bayer Sensor, only use 1 mipi lane, + preview set to 1296*972 at 30 fps, + snapshot set to 2592*1944 at 12 fps, + This sensor driver does not support auto focus. + +config MT9M114 + bool "Sensor MT9M114 (YUV 1.26MP)" + depends on MSMB_CAMERA + ---help--- + MT9M114 is Aptina YUV sensor. It supports 1.26 MP preview + and snapshot. The preview and snapshot resolution shall be + 1280 * 270. It does not support auto focus. It supports + few special effects like saturation. +config OV5645 + bool "Sensor OV5645 (YUV 5.0MP)" + depends on MSMB_CAMERA + ---help--- + OV5645 is Omnivision YUV sensor. It supports 5.0 MP preview + and snapshot. The preview and snapshot resolution shall be + 1280 * 270. It does not support auto focus. It supports + few special effects like saturation. + +config SR200PC20 + bool "Sensor for front camera" + depends on MSMB_CAMERA + default n + ---help--- + Siliconfile 2.0MP sensor, + Front sensor. +config SR544 + bool "Sensor for back camera" + depends on MSMB_CAMERA + default n + ---help--- + 5MP sensor + Rear sensor + +config SP1628 + bool "Sensor SP1628 (YUV 720P)" + depends on MSMB_CAMERA + ---help--- + SP1628 is SuperPix YUV sensor. It supports 720P preview + and snapshot. The preview and snapshot resolution shall be + 1280 * 270. It does not support auto focus. It supports + few special effects like mono. + +config GC0339 + bool "Sensor GC0339 (BAYER .3M)" + depends on MSMB_CAMERA + ---help--- + gc0339 is a Galaxycore .3 MP Bayer Sensor. + It supports 1 or 2 mipi lanes. + Preview and snapshot resolution shall be 640*480 at 30 fps, + It does not support auto focus. + +config OV8825 + bool "OmniVision OV8825 (BAYER 8MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 8 MP Bayer Sensor with auto focus.uses + 2 mipi lanes, preview config = 1632*1224 30 fps, + snapshot config = 3264 * 2448 at 18 fps. + 2 lanes max fps is 18, 4 lanes max fps is 24. + +config OV8865 + bool "OmniVision OV8865 (BAYER 8MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 8 MP Bayer Sensor with auto focus.uses + 4 mipi lanes, preview config = 1632*1224 30 fps, + snapshot config = 3264 * 2448 at 30 fps. + Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224 + +config s5k4e1 + bool "Sensor s5k4e1 (BAYER 5MP)" + depends on MSMB_CAMERA + ---help--- + Samsung 5 MP Bayer Sensor. It uses 2 mipi lanes, + supports 720P preview at 30 fps + and QSXGA snapshot at 15 fps. + This sensor driver does not support auto focus. + +config S5K8B1YX + bool "Sensor S5K8B1YX (BAYER 2M)" + depends on MSMB_CAMERA + ---help--- + LSI 2 MP Bayer Sensor, supports 2 mipi lanes, + preview and snapshot config at 1280*720 at 30 fps, + hfr video at 60, 90 and 120 fps. This sensor driver does + not support auto focus. + +config S5K6A3YX + bool "Sensor S5K6A3YX (BAYER 1.9M)" + depends on MSMB_CAMERA + ---help--- + S.LSI. 2 MP Bayer Sensor, supports 2 mipi lanes, + +config S5K4H5YB + bool "Sensor S5K4H5YB (BAYER 8M)" + depends on MSMB_CAMERA + ---help--- + S.LSI. 8 MP Bayer Sensor with auto focus, uses + 4 mipi lanes full resolution @30fps and + +config S5K3L2XX + bool "Sensor S5K3L2XX (BAYER 13M)" + depends on MSMB_CAMERA + ---help--- + S.LSI. 13MP Bayer Sensor with auto focus, uses + 4 mipi lanes full resolution @30fps + +config S5K5E3YX + bool "Sensor S5K5E3YX (BAYER 5M)" + depends on MSMB_CAMERA + ---help--- + S.LSI. 5MP Bayer Sensor with auto focus, uses + 2 mipi lanes full resolution @30fps + +config OV12830 + bool "OmniVision OV12830 (BAYER 12MP)" + depends on MSMB_CAMERA + ---help--- + OmniVision 12.8 MP Bayer Sensor with auto focus.uses + 4 mipi lanes, preview config = 2112 * 1500 at 30 fps, + snapshot config = 4224 * 3000 at 15 fps. + 2 lanes max fps is 18, 4 lanes max fps is 24. + +config MSM_V4L2_VIDEO_OVERLAY_DEVICE + tristate "Qualcomm MSM V4l2 video overlay device" + ---help--- + Enables support for the MSM V4L2 video + overlay driver. This allows video rendering + apps to render overlaid video using Video4Linux2 + APIs, by using /dev/videoX device + +config MSMB_JPEG + tristate "Qualcomm MSM Jpeg Encoder Engine support" + depends on MSMB_CAMERA && (ARCH_MSM8974 || ARCH_MSM8226 || ARCH_APQ8084 || ARCH_MSM8916 || ARCH_MSM) + ---help--- + Enable support for Jpeg Encoder/Decoder + Engine for 8974. + This module serves as the common driver + for the JPEG 1.0 encoder and decoder. + +config MSM_GEMINI + tristate "Qualcomm MSM Gemini JPEG engine support" + depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960) + ---help--- + Enables support for the Gemini JPEG encoder engine for 8x60. + +config SEC_CAMERA_TUNING + bool "Generic Tuning Concept" + ---help--- + Enable support for Tuning in eng Binary + +config CAM_USE_EXT_VANA_GPIO + bool "Samsung EXT_VANA_GPIO" + depends on MSMB_CAMERA + ---help--- + Board use external LDO controlled by GPIO. + +config CAM_USE_GPIO_I2C + bool "Samsung GPIO_I2C" + depends on MSMB_CAMERA + ---help--- + Board use controlled by GPIO. + diff --git a/drivers/media/platform/msm/camera_v2_j5/Makefile b/drivers/media/platform/msm/camera_v2_j5/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..732cb9a4613782ff4ebc756e319d38c337f80bc6 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/Makefile @@ -0,0 +1,19 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/codecs +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/isps +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/pproc +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/jpeg_10 + +obj-$(CONFIG_MSMB_CAMERA) += msm.o +obj-$(CONFIG_MSMB_CAMERA) += cam_dummy.o +obj-$(CONFIG_MSMB_CAMERA) += camera/ +obj-$(CONFIG_MSMB_CAMERA) += msm_vb2/ +obj-$(CONFIG_MSMB_CAMERA) += sensor/ +obj-$(CONFIG_MSMB_CAMERA) += pproc/ +obj-$(CONFIG_MSMB_CAMERA) += isp/ +obj-$(CONFIG_MSMB_CAMERA) += ispif/ +obj-$(CONFIG_MSMB_JPEG) += jpeg_10/ +obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/ diff --git a/drivers/media/platform/msm/camera_v2_j5/cam_dummy.c b/drivers/media/platform/msm/camera_v2_j5/cam_dummy.c new file mode 100755 index 0000000000000000000000000000000000000000..7c2a73a20f0b1e33c579fd22f10817699a69883f --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/cam_dummy.c @@ -0,0 +1,250 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm.h" +#include "msm_vb2.h" +#include "msm_sd.h" + +static struct v4l2_device *msm_v4l2_dev; +/* static struct msm_cam_dummy_queue cam_dummy_queue; */ + +#if defined CONFIG_SEC_CAMERA_TUNING +int rear_tune; +int front_tune; +#endif + +static int msm_open_cam_dummy(struct file *fp) +{ + int rc; + + pr_err("%s: E\n", __func__); + rc = msm_cam_get_module_init_status(); + pr_err("%s: X %d\n", __func__, rc); + return rc; +} + +#if !defined CONFIG_SEC_CAMERA_TUNING +static long msm_ioctl_cam_dummy(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + return 0; +} +#endif +static int msm_close_cam_dummy(struct file *f) +{ + return 0; +} + +static struct v4l2_file_operations msm_fops_config = { + .owner = THIS_MODULE, + .open = msm_open_cam_dummy, + .release = msm_close_cam_dummy, +#if defined CONFIG_SEC_CAMERA_TUNING + .ioctl = video_ioctl2, +#else + .unlocked_ioctl = msm_ioctl_cam_dummy, +#endif +}; + +static const struct of_device_id cam_dummy_dt_match[] = { + {.compatible = "qcom,cam_dummy",}, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_dummy_dt_match); + +static struct platform_driver cam_dummy_platform_driver = { + .driver = { + .name = "qcom,cam_dummy", + .owner = THIS_MODULE, + .of_match_table = cam_dummy_dt_match, + }, +}; + +#if defined CONFIG_SEC_CAMERA_TUNING +static int msm_v4l2_s_ctrl(struct file *filep, void *fh, + struct v4l2_control *ctrl) +{ + int rc = 0; + pr_err("%s TUNING CTRL : ctrl->value %d",__func__,ctrl->value); + if(ctrl->id >= V4L2_CID_PRIVATE_BASE) + { + switch (ctrl->value){ + case NORMAL_MODE : + rear_tune = 0; + front_tune = 0; + pr_err("%s TUNING CTRL : Setting Normal Binary",__func__); + break; + case REAR_TUNING : + rear_tune = 1; + pr_err("%s TUNING CTRL : Setting Rear Tuning Binary",__func__); + break; + case FRONT_TUNING : + front_tune = 1; + pr_err("%s TUNING CTRL : Setting Front Tuning Binary",__func__); + break; + case REAR_FRONT_TUNING : + rear_tune = 1; + front_tune = 1; + pr_err("%s TUNING CTRL : Setting Rear and Front Tuning Binary",__func__); + break; + } + } + return rc; +} + +static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = { + .vidioc_s_ctrl = msm_v4l2_s_ctrl, +}; +#endif + +static int32_t cam_dummy_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + struct msm_video_device *pvdev; + + /* init_waitqueue_head(&cam_dummy_queue.state_wait);*/ + pr_err("%s:%d\n", __func__, __LINE__); + match = of_match_device(cam_dummy_dt_match, &pdev->dev); + + msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev), + GFP_KERNEL); + if (WARN_ON(!msm_v4l2_dev)) { + rc = -ENOMEM; + goto probe_end; + } + + pvdev = kzalloc(sizeof(struct msm_video_device), + GFP_KERNEL); + if (WARN_ON(!pvdev)) { + rc = -ENOMEM; + goto pvdev_fail; + } + + pvdev->vdev = video_device_alloc(); + if (WARN_ON(!pvdev->vdev)) { + rc = -ENOMEM; + goto video_fail; + } + +#if defined(CONFIG_MEDIA_CONTROLLER) + msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device), + GFP_KERNEL); + if (!msm_v4l2_dev->mdev) { + rc = -ENOMEM; + goto mdev_fail; + } + strlcpy(msm_v4l2_dev->mdev->model, MSM_CAMERA_DUMMY_NAME, + sizeof(msm_v4l2_dev->mdev->model)); + msm_v4l2_dev->mdev->dev = &(pdev->dev); + + rc = media_device_register(msm_v4l2_dev->mdev); + if (WARN_ON(rc < 0)) + goto media_fail; + + if (WARN_ON((rc == media_entity_init(&pvdev->vdev->entity, + 0, NULL, 0)) < 0)) + goto entity_fail; + + pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; + pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; +#endif + + pvdev->vdev->v4l2_dev = msm_v4l2_dev; + + rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev); + if (WARN_ON(rc < 0)) + goto register_fail; + + strlcpy(pvdev->vdev->name, "msm-camdummy", sizeof(pvdev->vdev->name)); + pvdev->vdev->release = video_device_release; + pvdev->vdev->fops = &msm_fops_config; +#if defined CONFIG_SEC_CAMERA_TUNING + pvdev->vdev->ioctl_ops = &msm_v4l2_ioctl_ops; +#endif + pvdev->vdev->minor = -1; + pvdev->vdev->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(pvdev->vdev, + VFL_TYPE_GRABBER, -1); + if (WARN_ON(rc < 0)) + goto v4l2_fail; + +#if defined(CONFIG_MEDIA_CONTROLLER) + /* FIXME: How to get rid of this messy? */ + pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev); +#endif + + atomic_set(&pvdev->opened, 0); + video_set_drvdata(pvdev->vdev, pvdev); + + goto probe_end; + +v4l2_fail: + v4l2_device_unregister(pvdev->vdev->v4l2_dev); +register_fail: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&pvdev->vdev->entity); +entity_fail: + media_device_unregister(msm_v4l2_dev->mdev); +media_fail: + kzfree(msm_v4l2_dev->mdev); +mdev_fail: +#endif + video_device_release(pvdev->vdev); +video_fail: + kzfree(pvdev); +pvdev_fail: + kzfree(msm_v4l2_dev); +probe_end: + return rc; +} + +static int __init cam_dummy_init_module(void) +{ + int32_t rc = 0; + pr_err("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&cam_dummy_platform_driver, + cam_dummy_platform_probe); + pr_err("%s:%d rc = %d\n", __func__, __LINE__, rc); + return rc; +} + +static void __exit cam_dummy_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + platform_driver_unregister(&cam_dummy_platform_driver); + return; +} + +module_init(cam_dummy_init_module); +module_exit(cam_dummy_exit_module); +MODULE_DESCRIPTION("cam_dummy"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/media/platform/msm/camera_v2_j5/camera/Makefile b/drivers/media/platform/msm/camera_v2_j5/camera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..95d899eff42ef57acb27a2cec9755b68f7b11bf2 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/camera/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/msm_vb2 +obj-$(CONFIG_MSMB_CAMERA) += camera.o diff --git a/drivers/media/platform/msm/camera_v2_j5/camera/camera.c b/drivers/media/platform/msm/camera_v2_j5/camera/camera.c new file mode 100644 index 0000000000000000000000000000000000000000..742fab50359b3a09e5edf2522bc1a204695a3630 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/camera/camera.c @@ -0,0 +1,813 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "camera.h" +#include "msm.h" +#include "msm_vb2.h" + +#define fh_to_private(__fh) \ + container_of(__fh, struct camera_v4l2_private, fh) + +struct camera_v4l2_private { + struct v4l2_fh fh; + unsigned int stream_id; + unsigned int is_vb2_valid; /*0 if no vb2 buffers on stream, else 1*/ + struct vb2_queue vb2_q; +}; + +static void camera_pack_event(struct file *filep, int evt_id, + int command, int value, struct v4l2_event *event) +{ + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + struct msm_video_device *pvdev = video_drvdata(filep); + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + + /* always MSM_CAMERA_V4L2_EVENT_TYPE */ + event->type = MSM_CAMERA_V4L2_EVENT_TYPE; + event->id = evt_id; + event_data->command = command; + event_data->session_id = pvdev->vdev->num; + event_data->stream_id = sp->stream_id; + event_data->arg_value = value; +} + +static int camera_check_event_status(struct v4l2_event *event) +{ + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + + if (event_data->status > MSM_CAMERA_ERR_EVT_BASE) { + pr_err("%s : event_data status out of bounds\n", + __func__); + pr_err("%s : Line %d event_data->status 0X%x\n", + __func__, __LINE__, event_data->status); + return -EFAULT; + } + + return 0; +} + +static int camera_v4l2_querycap(struct file *filep, void *fh, + struct v4l2_capability *cap) +{ + int rc; + struct v4l2_event event; + + /* can use cap->driver to make differentiation */ + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + MSM_CAMERA_PRIV_QUERY_CAP, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + + return rc; +} + +static int camera_v4l2_s_crop(struct file *filep, void *fh, + const struct v4l2_crop *crop) +{ + int rc = 0; + struct v4l2_event event; + + if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_S_CROP, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_g_crop(struct file *filep, void *fh, + struct v4l2_crop *crop) +{ + int rc = 0; + struct v4l2_event event; + + if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + MSM_CAMERA_PRIV_G_CROP, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_queryctrl(struct file *filep, void *fh, + struct v4l2_queryctrl *ctrl) +{ + int rc = 0; + struct v4l2_event event; + + if (ctrl->type == V4L2_CTRL_TYPE_MENU) { + + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + ctrl->id, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_g_ctrl(struct file *filep, void *fh, + struct v4l2_control *ctrl) +{ + int rc = 0; + struct v4l2_event event; + + if (ctrl->id >= V4L2_CID_PRIVATE_BASE) { + camera_pack_event(filep, MSM_CAMERA_GET_PARM, ctrl->id, -1, + &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_s_ctrl(struct file *filep, void *fh, + struct v4l2_control *ctrl) +{ + int rc = 0; + struct v4l2_event event; + struct msm_v4l2_event_data *event_data; + if (ctrl->id >= V4L2_CID_PRIVATE_BASE) { + camera_pack_event(filep, MSM_CAMERA_SET_PARM, ctrl->id, + ctrl->value, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + event_data = (struct msm_v4l2_event_data *)event.u.data; + ctrl->value = event_data->ret_value; + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_reqbufs(struct file *filep, void *fh, + struct v4l2_requestbuffers *req) +{ + int ret; + struct msm_session *session; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int session_id = pvdev->vdev->num; + session = msm_session_find(session_id); + if (WARN_ON(!session)) + return -EIO; + mutex_lock(&session->lock_q); + ret = vb2_reqbufs(&sp->vb2_q, req); + mutex_unlock(&session->lock_q); + return ret; +} + +static int camera_v4l2_querybuf(struct file *filep, void *fh, + struct v4l2_buffer *pb) +{ + return 0; +} + +static int camera_v4l2_qbuf(struct file *filep, void *fh, + struct v4l2_buffer *pb) +{ + int ret; + struct msm_session *session; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int session_id = pvdev->vdev->num; + session = msm_session_find(session_id); + if (WARN_ON(!session)) + return -EIO; + mutex_lock(&session->lock_q); + ret = vb2_qbuf(&sp->vb2_q, pb); + mutex_unlock(&session->lock_q); + return ret; +} + +static int camera_v4l2_dqbuf(struct file *filep, void *fh, + struct v4l2_buffer *pb) +{ + int ret; + struct msm_session *session; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int session_id = pvdev->vdev->num; + session = msm_session_find(session_id); + if (WARN_ON(!session)) + return -EIO; + mutex_lock(&session->lock_q); + ret = vb2_dqbuf(&sp->vb2_q, pb, filep->f_flags & O_NONBLOCK); + mutex_unlock(&session->lock_q); + return ret; +} + +static int camera_v4l2_streamon(struct file *filep, void *fh, + enum v4l2_buf_type buf_type) +{ + struct v4l2_event event; + int rc; + struct camera_v4l2_private *sp = fh_to_private(fh); + + rc = vb2_streamon(&sp->vb2_q, buf_type); + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_STREAM_ON, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + return rc; +} + +static int camera_v4l2_streamoff(struct file *filep, void *fh, + enum v4l2_buf_type buf_type) +{ + struct v4l2_event event; + int rc; + struct camera_v4l2_private *sp = fh_to_private(fh); + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_STREAM_OFF, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + vb2_streamoff(&sp->vb2_q, buf_type); + return rc; +} + +static int camera_v4l2_g_fmt_vid_cap_mplane(struct file *filep, void *fh, + struct v4l2_format *pfmt) +{ + int rc = -EINVAL; + + if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + struct v4l2_event event; + + camera_pack_event(filep, MSM_CAMERA_GET_PARM, + MSM_CAMERA_PRIV_G_FMT, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + } + + return rc; +} + +static int camera_v4l2_s_fmt_vid_cap_mplane(struct file *filep, void *fh, + struct v4l2_format *pfmt) +{ + int rc = 0; + int i = 0; + struct v4l2_event event; + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_v4l2_format_data *user_fmt; + + if (pfmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + + if (WARN_ON(!sp->vb2_q.drv_priv)) + return -ENOMEM; + + memcpy(sp->vb2_q.drv_priv, pfmt->fmt.raw_data, + sizeof(struct msm_v4l2_format_data)); + user_fmt = (struct msm_v4l2_format_data *)sp->vb2_q.drv_priv; + + pr_debug("%s: num planes :%c\n", __func__, + user_fmt->num_planes); + /*num_planes need to bound checked, otherwise for loop + can execute forever */ + if (WARN_ON(user_fmt->num_planes > VIDEO_MAX_PLANES)) + return -EINVAL; + for (i = 0; i < user_fmt->num_planes; i++) + pr_debug("%s: plane size[%d]\n", __func__, + user_fmt->plane_sizes[i]); + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_S_FMT, -1, &event); + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + return rc; + + rc = camera_check_event_status(&event); + if (rc < 0) + return rc; + + sp->is_vb2_valid = 1; + } + + return rc; + +} + +static int camera_v4l2_try_fmt_vid_cap_mplane(struct file *filep, void *fh, + struct v4l2_format *pfmt) +{ + return 0; +} + + +static int camera_v4l2_g_parm(struct file *filep, void *fh, + struct v4l2_streamparm *a) +{ + /* TODO */ + return 0; +} + +static int camera_v4l2_s_parm(struct file *filep, void *fh, + struct v4l2_streamparm *parm) +{ + int rc = 0; + struct v4l2_event event; + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event.u.data[0]; + struct camera_v4l2_private *sp = fh_to_private(fh); + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_NEW_STREAM, -1, &event); + + rc = msm_create_stream(event_data->session_id, + event_data->stream_id, &sp->vb2_q); + if (rc < 0) + return rc; + + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) + goto error; + + rc = camera_check_event_status(&event); + if (rc < 0) + goto error; + + /* use stream_id as stream index */ + parm->parm.capture.extendedmode = sp->stream_id; + + return rc; + +error: + msm_delete_stream(event_data->session_id, + event_data->stream_id); + return rc; +} + +static int camera_v4l2_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct camera_v4l2_private *sp = fh_to_private(fh); + + rc = v4l2_event_subscribe(&sp->fh, sub, 5, NULL); + + return rc; +} + +static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct camera_v4l2_private *sp = fh_to_private(fh); + + rc = v4l2_event_unsubscribe(&sp->fh, sub); + + return rc; +} + +static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = { + .vidioc_querycap = camera_v4l2_querycap, + .vidioc_s_crop = camera_v4l2_s_crop, + .vidioc_g_crop = camera_v4l2_g_crop, + .vidioc_queryctrl = camera_v4l2_queryctrl, + .vidioc_g_ctrl = camera_v4l2_g_ctrl, + .vidioc_s_ctrl = camera_v4l2_s_ctrl, + .vidioc_reqbufs = camera_v4l2_reqbufs, + .vidioc_querybuf = camera_v4l2_querybuf, + .vidioc_qbuf = camera_v4l2_qbuf, + .vidioc_dqbuf = camera_v4l2_dqbuf, + .vidioc_streamon = camera_v4l2_streamon, + .vidioc_streamoff = camera_v4l2_streamoff, + .vidioc_g_fmt_vid_cap_mplane = camera_v4l2_g_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_cap_mplane = camera_v4l2_s_fmt_vid_cap_mplane, + .vidioc_try_fmt_vid_cap_mplane = camera_v4l2_try_fmt_vid_cap_mplane, + + /* Stream type-dependent parameter ioctls */ + .vidioc_g_parm = camera_v4l2_g_parm, + .vidioc_s_parm = camera_v4l2_s_parm, + + /* event subscribe/unsubscribe */ + .vidioc_subscribe_event = camera_v4l2_subscribe_event, + .vidioc_unsubscribe_event = camera_v4l2_unsubscribe_event, +}; + +static int camera_v4l2_fh_open(struct file *filep) +{ + struct msm_video_device *pvdev = video_drvdata(filep); + struct camera_v4l2_private *sp; + unsigned int stream_id; + + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (!sp) { + pr_err("%s : memory not available\n", __func__); + return -ENOMEM; + } + + filep->private_data = &sp->fh; + + /* stream_id = open id */ + stream_id = atomic_read(&pvdev->opened); + sp->stream_id = find_first_zero_bit( + &stream_id, MSM_CAMERA_STREAM_CNT_BITS); + pr_debug("%s: Found stream_id=%d\n", __func__, sp->stream_id); + + v4l2_fh_init(&sp->fh, pvdev->vdev); + v4l2_fh_add(&sp->fh); + + return 0; +} + +static int camera_v4l2_fh_release(struct file *filep) +{ + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + + if (sp) { + v4l2_fh_del(&sp->fh); + v4l2_fh_exit(&sp->fh); + } + + kzfree(sp); + return 0; +} + +static int camera_v4l2_vb2_q_init(struct file *filep) +{ + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + struct vb2_queue *q = &sp->vb2_q; + + memset(q, 0, sizeof(struct vb2_queue)); + + /* free up this buffer when stream is done */ + q->drv_priv = + kzalloc(sizeof(struct msm_v4l2_format_data), GFP_KERNEL); + if (!q->drv_priv) { + pr_err("%s : memory not available\n", __func__); + return -ENOMEM; + } + + q->mem_ops = msm_vb2_get_q_mem_ops(); + q->ops = msm_vb2_get_q_ops(); + + /* default queue type */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_USERPTR; + q->io_flags = 0; + q->buf_struct_size = sizeof(struct msm_vb2_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + return vb2_queue_init(q); +} + +static void camera_v4l2_vb2_q_release(struct file *filep) +{ + struct camera_v4l2_private *sp = filep->private_data; + + kzfree(sp->vb2_q.drv_priv); + vb2_queue_release(&sp->vb2_q); +} + +static int camera_v4l2_open(struct file *filep) +{ + int rc = 0; + struct v4l2_event event; + struct msm_video_device *pvdev = video_drvdata(filep); + unsigned int opn_idx, idx; + BUG_ON(!pvdev); + + rc = camera_v4l2_fh_open(filep); + if (rc < 0) { + pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n", + __func__, __LINE__, rc); + goto fh_open_fail; + } + + opn_idx = atomic_read(&pvdev->opened); + idx = opn_idx; + /* every stream has a vb2 queue */ + rc = camera_v4l2_vb2_q_init(filep); + if (rc < 0) { + pr_err("%s : vb2 queue init fails Line %d rc %d\n", + __func__, __LINE__, rc); + goto vb2_q_fail; + } + + if (!atomic_read(&pvdev->opened)) { + pm_stay_awake(&pvdev->vdev->dev); + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) + /* Disable power collapse latency */ + msm_pm_qos_update_request(CAMERA_DISABLE_PC_LATENCY); +#endif + + /* create a new session when first opened */ + rc = msm_create_session(pvdev->vdev->num, pvdev->vdev); + if (rc < 0) { + pr_err("%s : session creation failed Line %d rc %d\n", + __func__, __LINE__, rc); + goto session_fail; + } + + rc = msm_create_command_ack_q(pvdev->vdev->num, + find_first_zero_bit(&opn_idx, + MSM_CAMERA_STREAM_CNT_BITS)); + if (rc < 0) { + pr_err("%s : creation of command_ack queue failed\n", + __func__); + pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc); + goto command_ack_q_fail; + } + + camera_pack_event(filep, MSM_CAMERA_NEW_SESSION, 0, -1, &event); + rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + if (rc < 0) { + pr_err("%s : posting of NEW_SESSION event failed\n", + __func__); + pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc); + goto post_fail; + } + + rc = camera_check_event_status(&event); + if (rc < 0) { + pr_err("%s : checking event status fails Line %d rc %d\n", + __func__, __LINE__, rc); + goto post_fail; + } + } else { + rc = msm_create_command_ack_q(pvdev->vdev->num, + find_first_zero_bit(&opn_idx, + MSM_CAMERA_STREAM_CNT_BITS)); + if (rc < 0) { + pr_err("%s : creation of command_ack queue failed Line %d rc %d\n", + __func__, __LINE__, rc); + goto session_fail; + } + } + pr_debug("%s: Open stream_id=%d\n", __func__, + find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); + idx |= (1 << find_first_zero_bit(&opn_idx, MSM_CAMERA_STREAM_CNT_BITS)); + atomic_cmpxchg(&pvdev->opened, opn_idx, idx); + return rc; + +post_fail: + msm_delete_command_ack_q(pvdev->vdev->num, 0); +command_ack_q_fail: + msm_destroy_session(pvdev->vdev->num); +session_fail: + pm_relax(&pvdev->vdev->dev); + camera_v4l2_vb2_q_release(filep); +vb2_q_fail: + camera_v4l2_fh_release(filep); +fh_open_fail: + return rc; +} + +static unsigned int camera_v4l2_poll(struct file *filep, + struct poll_table_struct *wait) +{ + int rc = 0; + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + if (sp->is_vb2_valid == 1) + rc = vb2_poll(&sp->vb2_q, filep, wait); + + poll_wait(filep, &sp->fh.wait, wait); + if (v4l2_event_pending(&sp->fh)) + rc |= POLLPRI; + + return rc; +} + +static int camera_v4l2_close(struct file *filep) +{ + int rc = 0; + struct v4l2_event event; + struct msm_video_device *pvdev = video_drvdata(filep); + struct camera_v4l2_private *sp = fh_to_private(filep->private_data); + unsigned int opn_idx, mask; + BUG_ON(!pvdev); + + opn_idx = atomic_read(&pvdev->opened); + pr_debug("%s: close stream_id=%d\n", __func__, sp->stream_id); + mask = (1 << sp->stream_id); + opn_idx &= ~mask; + atomic_set(&pvdev->opened, opn_idx); + + if (atomic_read(&pvdev->opened) == 0) { + + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_DEL_STREAM, -1, &event); + + /* Donot wait, imaging server may have crashed */ + msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + + camera_pack_event(filep, MSM_CAMERA_DEL_SESSION, 0, -1, &event); + + /* Donot wait, imaging server may have crashed */ + msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + msm_delete_command_ack_q(pvdev->vdev->num, 0); + + /* This should take care of both normal close + * and application crashes */ + msm_destroy_session(pvdev->vdev->num); + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) + /* Enable power collapse latency */ + msm_pm_qos_update_request(CAMERA_ENABLE_PC_LATENCY); +#endif + + pm_relax(&pvdev->vdev->dev); + } else { + camera_pack_event(filep, MSM_CAMERA_SET_PARM, + MSM_CAMERA_PRIV_DEL_STREAM, -1, &event); + + /* Donot wait, imaging server may have crashed */ + msm_post_event(&event, MSM_POST_EVT_TIMEOUT); + msm_delete_command_ack_q(pvdev->vdev->num, + sp->stream_id); + + msm_delete_stream(pvdev->vdev->num, sp->stream_id); + } + + camera_v4l2_vb2_q_release(filep); + camera_v4l2_fh_release(filep); + + return rc; +} + +#ifdef CONFIG_COMPAT +long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return -ENOIOCTLCMD; +} +#endif +static struct v4l2_file_operations camera_v4l2_fops = { + .owner = THIS_MODULE, + .open = camera_v4l2_open, + .poll = camera_v4l2_poll, + .release = camera_v4l2_close, + .ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = camera_v4l2_compat_ioctl, +#endif +}; + +int camera_init_v4l2(struct device *dev, unsigned int *session) +{ + struct msm_video_device *pvdev; + struct v4l2_device *v4l2_dev; + int rc = 0; + + pvdev = kzalloc(sizeof(struct msm_video_device), + GFP_KERNEL); + if (WARN_ON(!pvdev)) { + rc = -ENOMEM; + goto init_end; + } + + pvdev->vdev = video_device_alloc(); + if (WARN_ON(!pvdev->vdev)) { + rc = -ENOMEM; + goto video_fail; + } + + v4l2_dev = kzalloc(sizeof(struct v4l2_device), GFP_KERNEL); + if (WARN_ON(!v4l2_dev)) { + rc = -ENOMEM; + goto v4l2_fail; + } + +#if defined(CONFIG_MEDIA_CONTROLLER) + v4l2_dev->mdev = kzalloc(sizeof(struct media_device), + GFP_KERNEL); + if (!v4l2_dev->mdev) { + rc = -ENOMEM; + goto mdev_fail; + } + strlcpy(v4l2_dev->mdev->model, MSM_CAMERA_NAME, + sizeof(v4l2_dev->mdev->model)); + + v4l2_dev->mdev->dev = dev; + + rc = media_device_register(v4l2_dev->mdev); + if (WARN_ON(rc < 0)) + goto media_fail; + + rc = media_entity_init(&pvdev->vdev->entity, 0, NULL, 0); + if (WARN_ON(rc < 0)) + goto entity_fail; + pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; + pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; +#endif + + v4l2_dev->notify = NULL; + pvdev->vdev->v4l2_dev = v4l2_dev; + + rc = v4l2_device_register(dev, pvdev->vdev->v4l2_dev); + if (WARN_ON(rc < 0)) + goto register_fail; + + strlcpy(pvdev->vdev->name, "msm-sensor", sizeof(pvdev->vdev->name)); + pvdev->vdev->release = video_device_release; + pvdev->vdev->fops = &camera_v4l2_fops; + pvdev->vdev->ioctl_ops = &camera_v4l2_ioctl_ops; + pvdev->vdev->minor = -1; + pvdev->vdev->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(pvdev->vdev, + VFL_TYPE_GRABBER, -1); + if (WARN_ON(rc < 0)) + goto video_register_fail; +#if defined(CONFIG_MEDIA_CONTROLLER) + /* FIXME: How to get rid of this messy? */ + pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev); +#endif + + *session = pvdev->vdev->num; + atomic_set(&pvdev->opened, 0); + video_set_drvdata(pvdev->vdev, pvdev); + device_init_wakeup(&pvdev->vdev->dev, 1); + goto init_end; + +video_register_fail: + v4l2_device_unregister(pvdev->vdev->v4l2_dev); +register_fail: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&pvdev->vdev->entity); +entity_fail: + media_device_unregister(v4l2_dev->mdev); +media_fail: + kzfree(v4l2_dev->mdev); +mdev_fail: +#endif + kzfree(v4l2_dev); +v4l2_fail: + video_device_release(pvdev->vdev); +video_fail: + kzfree(pvdev); +init_end: + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/camera/camera.h b/drivers/media/platform/msm/camera_v2_j5/camera/camera.h new file mode 100644 index 0000000000000000000000000000000000000000..ac860a4f87d6add2bbfaf8a781367dfea970ee6c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/camera/camera.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef _CAMERA_H +#define _CAMERA_H + +enum stream_state { + START_STREAM = 0, + STOP_STREAM, +}; + +int camera_init_v4l2(struct device *dev, unsigned int *session); + +#endif /*_CAMERA_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/media/msm_cam_sensor.h b/drivers/media/platform/msm/camera_v2_j5/include/media/msm_cam_sensor.h new file mode 100755 index 0000000000000000000000000000000000000000..209c2d7612c1b5c7fdb9688d8d4171a04dcc3ece --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/media/msm_cam_sensor.h @@ -0,0 +1,970 @@ +#ifndef __LINUX_MSM_CAM_SENSOR_H +#define __LINUX_MSM_CAM_SENSOR_H + +#ifdef MSM_CAMERA_BIONIC +#include +#endif +#include +#include +#include + +#define I2C_SEQ_REG_SETTING_MAX 5 +#define I2C_SEQ_REG_DATA_MAX 256 +#define MAX_CID 16 + +#define MSM_SENSOR_MCLK_8HZ 8000000 +#define MSM_SENSOR_MCLK_16HZ 16000000 +#define MSM_SENSOR_MCLK_24HZ 24000000 + +#define GPIO_OUT_LOW (0 << 1) +#define GPIO_OUT_HIGH (1 << 1) + +#define CSI_EMBED_DATA 0x12 +#define CSI_RESERVED_DATA_0 0x13 +#define CSI_YUV422_8 0x1E +#define CSI_RAW8 0x2A +#define CSI_RAW10 0x2B +#define CSI_RAW12 0x2C + +#define CSI_DECODE_6BIT 0 +#define CSI_DECODE_8BIT 1 +#define CSI_DECODE_10BIT 2 +#define CSI_DECODE_DPCM_10_8_10 5 + +#define MAX_SENSOR_NAME 32 + +#define MAX_ACT_MOD_NAME_SIZE 32 +#define MAX_ACT_NAME_SIZE 32 +#define NUM_ACTUATOR_DIR 2 +#define MAX_ACTUATOR_SCENARIO 8 +#define MAX_ACTUATOR_REGION 5 +#define MAX_ACTUATOR_INIT_SET 50 +#define MAX_ACTUATOR_REG_TBL_SIZE 50 +#define MAX_ACTUATOR_AF_TOTAL_STEPS 1024 + +#define MOVE_NEAR 0 +#define MOVE_FAR 1 + +#define MSM_ACTUATOR_MOVE_SIGNED_FAR -1 +#define MSM_ACTUATOR_MOVE_SIGNED_NEAR 1 + +#define MAX_EEPROM_NAME 32 + +#define MAX_AF_ITERATIONS 3 +#define MAX_NUMBER_OF_STEPS 47 + +#define MAX_LED_TRIGGERS 3 + +#define EXT_CAM_SENSOR_MODE 7 +#define EXT_CAM_EXIF 9 +//Focus related enums +#define EXT_CAM_AF 11 +#define EXT_CAM_FOCUS 12 +#define EXT_CAM_SET_TOUCHAF_POS 13 +#define EXT_CAM_SET_AF_STATUS 14 +#define EXT_CAM_GET_AF_STATUS 15 +#define EXT_CAM_GET_AF_RESULT 16 +#define EXT_CAM_SET_AF_STOP 17 +#define EXT_CAM_FLASH_MODE 18 +#define EXT_CAM_SET_FLASH 19 +#define EXT_CAM_VT_MODE 20 + + +//************************************* Native functionalities for YUV sensor added +#define EXT_CAM_EV 1 +#define EXT_CAM_WB 2 +#define EXT_CAM_METERING 3 +#define EXT_CAM_ISO 4 +#define EXT_CAM_EFFECT 5 +#define EXT_CAM_SCENE_MODE 6 +#define EXT_CAM_SENSOR_MODE 7 +#define EXT_CAM_CONTRAST 8 +#define EXT_CAM_EXIF 9 +#define EXT_CAM_SET_AE_AWB 10 + +//Exposure Compensation +#define CAMERA_EV_M4 0 +#define CAMERA_EV_M3 1 +#define CAMERA_EV_M2 2 +#define CAMERA_EV_M1 3 +#define CAMERA_EV_DEFAULT 4 +#define CAMERA_EV_P1 5 +#define CAMERA_EV_P2 6 +#define CAMERA_EV_P3 7 +#define CAMERA_EV_P4 8 + +//White Balance +#define CAMERA_WHITE_BALANCE_OFF 0 +#define CAMERA_WHITE_BALANCE_AUTO 1 +#define CAMERA_WHITE_BALANCE_INCANDESCENT 2 +#define CAMERA_WHITE_BALANCE_FLUORESCENT 3 +#define CAMERA_WHITE_BALANCE_DAYLIGHT 5 +#define CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT 6 + +//Metering +#define CAMERA_AVERAGE 0 +#define CAMERA_CENTER_WEIGHT 1 +#define CAMERA_SPOT 2 + +//ISO +#define CAMERA_ISO_MODE_AUTO 0 +#define CAMERA_ISO_MODE_50 1 +#define CAMERA_ISO_MODE_100 2 +#define CAMERA_ISO_MODE_200 3 +#define CAMERA_ISO_MODE_400 4 +#define CAMERA_ISO_MODE_800 5 + +//Effect +#define CAMERA_EFFECT_OFF 0 +#define CAMERA_EFFECT_MONO 1 +#define CAMERA_EFFECT_NEGATIVE 2 +#define CAMERA_EFFECT_SOLARIZE 3 +#define CAMERA_EFFECT_SEPIA 4 +#define CAMERA_EFFECT_POSTERIZE 5 +#define CAMERA_EFFECT_WHITEBOARD 6 +#define CAMERA_EFFECT_BLACKBOARD 7 +#define CAMERA_EFFECT_AQUA 8 +#define CAMERA_EFFECT_EMBOSS 9 +#define CAMERA_EFFECT_SKETCH 10 +#define CAMERA_EFFECT_NEON 11 +#define CAMERA_EFFECT_WASHED 12 +#define CAMERA_EFFECT_VINTAGE_WARM 13 +#define CAMERA_EFFECT_VINTAGE_COLD 14 +#define CAMERA_EFFECT_POINT_COLOR_1 15 +#define CAMERA_EFFECT_POINT_COLOR_2 16 +#define CAMERA_EFFECT_POINT_COLOR_3 17 +#define CAMERA_EFFECT_POINT_COLOR_4 18 +#define CAMERA_EFFECT_CARTOONIZE 19 +#define CAMERA_EFFECT_MAX 20 + +//scene mode +#define CAMERA_SCENE_AUTO 0 +#define CAMERA_SCENE_LANDSCAPE 3 +#define CAMERA_SCENE_NIGHT 6 +#define CAMERA_SCENE_BEACH 7 +#define CAMERA_SCENE_PORTRAIT 8 +#define CAMERA_SCENE_SPORT 9 +#define CAMERA_SCENE_FIRE 11 +#define CAMERA_SCENE_SUNSET 12 +#define CAMERA_SCENE_PARTY 13 +#define CAMERA_SCENE_CANDLE 14 +#define CAMERA_SCENE_AGAINST_LIGHT 16 +#define CAMERA_SCENE_FALL 17 +#define CAMERA_SCENE_TEXT 19 +#define CAMERA_SCENE_DAWN 21 //need to check + + +#define CAMERA_CONTRAST_LV0 0 +#define CAMERA_CONTRAST_LV1 1 +#define CAMERA_CONTRAST_LV2 2 +#define CAMERA_CONTRAST_LV3 3 +#define CAMERA_CONTRAST_LV4 4 +#define CAMERA_CONTRAST_LV5 5 +#define CAMERA_CONTRAST_LV6 6 +#define CAMERA_CONTRAST_LV7 7 +#define CAMERA_CONTRAST_LV8 8 +#define CAMERA_CONTRAST_LV9 9 + + +enum sensor_stats_type { + YRGB, + YYYY, +}; + +#define CAMERA_MODE_INIT 0 +#define CAMERA_MODE_PREVIEW 1 +#define CAMERA_MODE_CAPTURE 2 +#define CAMERA_MODE_RECORDING 3 + +//Flash modes +#define CAMERA_FLASH_OFF 0 +#define CAMERA_FLASH_ON 2 +#define CAMERA_FLASH_AUTO 1 +#define CAMERA_FLASH_TORCH 3 + +//AF modes +#define CAMERA_AF_AUTO 0 +#define CAMERA_AF_MACRO 2 +#define CAMERA_AF_OCR 3 + +enum flash_type { +#if !defined(CONFIG_FLED_SM5701) + LED_FLASH = 1, +#endif + STROBE_FLASH, + GPIO_FLASH +}; + +enum msm_camera_i2c_reg_addr_type { + MSM_CAMERA_I2C_BYTE_ADDR = 1, + MSM_CAMERA_I2C_WORD_ADDR, + MSM_CAMERA_I2C_3B_ADDR, + MSM_CAMERA_I2C_ADDR_TYPE_MAX, +}; + +enum msm_camera_i2c_data_type { + MSM_CAMERA_I2C_BYTE_DATA = 1, + MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_SET_BYTE_MASK, + MSM_CAMERA_I2C_UNSET_BYTE_MASK, + MSM_CAMERA_I2C_SET_WORD_MASK, + MSM_CAMERA_I2C_UNSET_WORD_MASK, + MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA, + MSM_CAMERA_I2C_BURST_DATA, + MSM_CAMERA_I2C_DATA_TYPE_MAX, +}; + +enum msm_sensor_power_seq_type_t { + SENSOR_CLK, + SENSOR_GPIO, + SENSOR_VREG, + SENSOR_I2C_MUX, +}; + +enum msm_sensor_clk_type_t { + SENSOR_CAM_MCLK, + SENSOR_CAM_CLK, + SENSOR_CAM_CLK_MAX, +}; + +enum msm_sensor_power_seq_gpio_t { + SENSOR_GPIO_RESET, + SENSOR_GPIO_STANDBY, + SENSOR_GPIO_AF_PWDM, + SENSOR_GPIO_VIO, + SENSOR_GPIO_VANA, + SENSOR_GPIO_VDIG, + SENSOR_GPIO_VAF, + SENSOR_GPIO_FL_EN, + SENSOR_GPIO_FL_NOW, + SENSOR_GPIO_FL_RESET, + SENSOR_GPIO_VT_RESET, + SENSOR_GPIO_VT_STANDBY, + SENSOR_GPIO_MAX, +}; + +enum msm_camera_vreg_name_t { + CAM_VDIG, + CAM_VIO, + CAM_VANA, + CAM_VANA_VT, + CAM_VIO_VT, + CAM_VAF, + CAM_VREG_MAX, +}; + +#if defined (CONFIG_CAMERA_SYSFS_V2) +enum msm_camera_cam_info_isp { + CAM_INFO_ISP_TYPE_INTERNAL = 0, + CAM_INFO_ISP_TYPE_EXTERNAL, + CAM_INFO_ISP_TYPE_SOC, +}; + +enum msm_camera_cam_info_cal_mem { + CAM_INFO_CAL_MEM_TYPE_NONE = 0, + CAM_INFO_CAL_MEM_TYPE_FROM, + CAM_INFO_CAL_MEM_TYPE_EEPROM, + CAM_INFO_CAL_MEM_TYPE_OTP, +}; + +enum msm_camera_cam_info_read_ver { + CAM_INFO_READ_VER_SYSFS = 0, + CAM_INFO_READ_VER_CAMON, +}; + +enum msm_camera_cam_info_core_voltage { + CAM_INFO_CORE_VOLT_NONE = 0, + CAM_INFO_CORE_VOLT_USE, +}; + +enum msm_camera_cam_info_upgrade { + CAM_INFO_FW_UPGRADE_NONE = 0, + CAM_INFO_FW_UPGRADE_SYSFS, + CAM_INFO_FW_UPGRADE_CAMON, +}; + +enum msm_camera_cam_info_companion { + CAM_INFO_COMPANION_NONE = 0, + CAM_INFO_COMPANION_USE, +}; + +enum msm_camera_cam_info_ois { + CAM_INFO_OIS_NONE = 0, + CAM_INFO_OIS_USE, +}; +#endif + +enum msm_sensor_resolution_t { + MSM_SENSOR_RES_FULL, + MSM_SENSOR_RES_QTR, + MSM_SENSOR_RES_2, + MSM_SENSOR_RES_3, + MSM_SENSOR_RES_4, + MSM_SENSOR_RES_5, + MSM_SENSOR_RES_6, + MSM_SENSOR_RES_7, + MSM_SENSOR_RES_8, + MSM_SENSOR_RES_9, + MSM_SENSOR_RES_10, + MSM_SENSOR_RES_11, + MSM_SENSOR_RES_12, + MSM_SENSOR_RES_13, + MSM_SENSOR_INVALID_RES, +}; + +enum msm_camera_stream_type_t { + MSM_CAMERA_STREAM_PREVIEW, + MSM_CAMERA_STREAM_SNAPSHOT, + MSM_CAMERA_STREAM_VIDEO, + MSM_CAMERA_STREAM_INVALID, +}; + +enum sensor_sub_module_t { + SUB_MODULE_SENSOR, + SUB_MODULE_CHROMATIX, + SUB_MODULE_ACTUATOR, + SUB_MODULE_EEPROM, + SUB_MODULE_LED_FLASH, + SUB_MODULE_STROBE_FLASH, + SUB_MODULE_CSID, + SUB_MODULE_CSID_3D, + SUB_MODULE_CSIPHY, + SUB_MODULE_CSIPHY_3D, + SUB_MODULE_MAX, +}; + +enum { + MSM_CAMERA_EFFECT_MODE_OFF, + MSM_CAMERA_EFFECT_MODE_MONO, + MSM_CAMERA_EFFECT_MODE_NEGATIVE, + MSM_CAMERA_EFFECT_MODE_SOLARIZE, + MSM_CAMERA_EFFECT_MODE_SEPIA, + MSM_CAMERA_EFFECT_MODE_POSTERIZE, + MSM_CAMERA_EFFECT_MODE_WHITEBOARD, + MSM_CAMERA_EFFECT_MODE_BLACKBOARD, + MSM_CAMERA_EFFECT_MODE_AQUA, + MSM_CAMERA_EFFECT_MODE_EMBOSS, + MSM_CAMERA_EFFECT_MODE_SKETCH, + MSM_CAMERA_EFFECT_MODE_NEON, + MSM_CAMERA_EFFECT_MODE_MAX +}; + +enum { + MSM_CAMERA_WB_MODE_AUTO, + MSM_CAMERA_WB_MODE_CUSTOM, + MSM_CAMERA_WB_MODE_INCANDESCENT, + MSM_CAMERA_WB_MODE_FLUORESCENT, + MSM_CAMERA_WB_MODE_WARM_FLUORESCENT, + MSM_CAMERA_WB_MODE_DAYLIGHT, + MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT, + MSM_CAMERA_WB_MODE_TWILIGHT, + MSM_CAMERA_WB_MODE_SHADE, + MSM_CAMERA_WB_MODE_OFF, + MSM_CAMERA_WB_MODE_MAX +}; + +enum { + MSM_CAMERA_SCENE_MODE_OFF, + MSM_CAMERA_SCENE_MODE_AUTO, + MSM_CAMERA_SCENE_MODE_LANDSCAPE, + MSM_CAMERA_SCENE_MODE_SNOW, + MSM_CAMERA_SCENE_MODE_BEACH, + MSM_CAMERA_SCENE_MODE_SUNSET, + MSM_CAMERA_SCENE_MODE_NIGHT, + MSM_CAMERA_SCENE_MODE_PORTRAIT, + MSM_CAMERA_SCENE_MODE_BACKLIGHT, + MSM_CAMERA_SCENE_MODE_SPORTS, + MSM_CAMERA_SCENE_MODE_ANTISHAKE, + MSM_CAMERA_SCENE_MODE_FLOWERS, + MSM_CAMERA_SCENE_MODE_CANDLELIGHT, + MSM_CAMERA_SCENE_MODE_FIREWORKS, + MSM_CAMERA_SCENE_MODE_PARTY, + MSM_CAMERA_SCENE_MODE_NIGHT_PORTRAIT, + MSM_CAMERA_SCENE_MODE_THEATRE, + MSM_CAMERA_SCENE_MODE_ACTION, + MSM_CAMERA_SCENE_MODE_AR, + MSM_CAMERA_SCENE_MODE_FACE_PRIORITY, + MSM_CAMERA_SCENE_MODE_BARCODE, + MSM_CAMERA_SCENE_MODE_HDR, + MSM_CAMERA_SCENE_MODE_MAX +}; + +enum csid_cfg_type_t { + CSID_INIT, + CSID_CFG, + CSID_RELEASE, +}; + +enum csiphy_cfg_type_t { + CSIPHY_INIT, + CSIPHY_CFG, + CSIPHY_RELEASE, +}; + +enum camera_vreg_type { + REG_LDO, + REG_VS, + REG_GPIO, +}; + +enum sensor_af_e { + SENSOR_AF_CANCEL = 1, + SENSOR_AF_START, + SENSOR_AF_PRE_FLASH_ON, + SENSOR_AF_PRE_FLASH_OFF, + SENSOR_AF_PRE_FLASH_AE_STABLE, +}; + +struct msm_sensor_gpio_config { +enum msm_sensor_power_seq_gpio_t gpio_name; +uint8_t config_val; +}; + +enum sensor_af_t { + SENSOR_AF_FOCUSSED, + SENSOR_AF_NOT_FOCUSSED, +}; + +struct msm_sensor_power_setting { + enum msm_sensor_power_seq_type_t seq_type; + uint16_t seq_val; + long config_val; + uint16_t delay; + void *data[10]; +}; + +struct msm_sensor_power_setting_array { + struct msm_sensor_power_setting *power_setting; + uint16_t size; + struct msm_sensor_power_setting *power_down_setting; + uint16_t size_down; +}; + +struct msm_sensor_id_info_t { + uint16_t sensor_id_reg_addr; + uint16_t sensor_id; +}; + +enum msm_sensor_camera_id_t { + CAMERA_0, + CAMERA_1, + CAMERA_2, + CAMERA_3, + MAX_CAMERAS, +}; + +enum cci_i2c_master_t { + MASTER_0, + MASTER_1, + MASTER_MAX, +}; + +enum camb_position_t { + BACK_CAMERA_B, + FRONT_CAMERA_B, + INVALID_CAMERA_B, +}; + +struct msm_sensor_info_t { + char sensor_name[MAX_SENSOR_NAME]; + uint32_t session_id; + int32_t subdev_id[SUB_MODULE_MAX]; + uint8_t is_mount_angle_valid; + uint32_t sensor_mount_angle; + int modes_supported; + enum camb_position_t position; +}; + +enum i2c_freq_mode_t { + I2C_STANDARD_MODE, + I2C_FAST_MODE, + I2C_CUSTOM_MODE, + I2C_MAX_MODES, +}; + +struct msm_camera_i2c_reg_array { + uint16_t reg_addr; + uint16_t reg_data; + uint8_t *reg_burst_data; + uint32_t delay; +}; + +struct msm_camera_i2c_reg_setting { + struct msm_camera_i2c_reg_array *reg_setting; + uint16_t size; + enum msm_camera_i2c_reg_addr_type addr_type; + enum msm_camera_i2c_data_type data_type; + uint16_t delay; +}; + +struct msm_camera_i2c_seq_reg_array { + uint16_t reg_addr; + uint8_t reg_data[I2C_SEQ_REG_DATA_MAX]; + uint16_t reg_data_size; +}; + +struct msm_camera_i2c_seq_reg_setting { + struct msm_camera_i2c_seq_reg_array *reg_setting; + uint16_t size; + enum msm_camera_i2c_reg_addr_type addr_type; + uint16_t delay; +}; + +struct msm_camera_i2c_array_write_config { + struct msm_camera_i2c_reg_setting conf_array; + uint16_t slave_addr; +}; + +struct msm_camera_i2c_read_config { + uint16_t slave_addr; + uint16_t reg_addr; + enum msm_camera_i2c_data_type data_type; + uint16_t *data; +}; + +struct msm_camera_csid_vc_cfg { + uint8_t cid; + uint8_t dt; + uint8_t decode_format; +}; + +struct msm_camera_csid_lut_params { + uint8_t num_cid; + struct msm_camera_csid_vc_cfg *vc_cfg[MAX_CID]; +}; + +struct msm_camera_csid_params { + uint8_t lane_cnt; + uint16_t lane_assign; + uint8_t phy_sel; + struct msm_camera_csid_lut_params lut_params; +}; + +struct msm_camera_csiphy_params { + uint8_t lane_cnt; + uint8_t settle_cnt; + uint16_t lane_mask; + uint8_t combo_mode; + uint8_t csid_core; +}; + +struct msm_camera_csi2_params { + struct msm_camera_csid_params csid_params; + struct msm_camera_csiphy_params csiphy_params; +}; + +struct msm_camera_csi_lane_params { + uint16_t csi_lane_assign; + uint16_t csi_lane_mask; +}; + +struct csi_lane_params_t { + uint16_t csi_lane_assign; + uint8_t csi_lane_mask; + uint8_t csi_if; + uint8_t csid_core[2]; + uint8_t csi_phy_sel; +}; + +struct camera_vreg_t { + const char *reg_name; + enum camera_vreg_type type; + int min_voltage; + int max_voltage; + int op_mode; + uint32_t delay; +#if defined(CONFIG_CAM_DUAL_POWER_SEQ) + void *regulator[1]; +#endif +}; + +enum camerab_mode_t { + CAMERA_MODE_2D_B = (1<<0), + CAMERA_MODE_3D_B = (1<<1), + CAMERA_MODE_INVALID = (1<<2), +}; + +struct msm_sensor_init_params { + /* mask of modes supported: 2D, 3D */ + int modes_supported; + /* sensor position: front, back */ + enum camb_position_t position; + /* sensor mount angle */ + uint32_t sensor_mount_angle; +}; + +struct msm_camera_sensor_slave_info { + char sensor_name[32]; + char eeprom_name[32]; + char actuator_name[32]; + enum msm_sensor_camera_id_t camera_id; + uint16_t slave_addr; + enum i2c_freq_mode_t i2c_freq_mode; + enum msm_camera_i2c_reg_addr_type addr_type; + enum msm_camera_i2c_data_type data_type; + struct msm_sensor_id_info_t sensor_id_info; + struct msm_sensor_power_setting_array power_setting_array; + uint8_t is_init_params_valid; + struct msm_sensor_init_params sensor_init_params; + uint8_t is_probe_succeed; + char subdev_name[32]; + struct msm_sensor_info_t sensor_info; +}; + +struct sensorb_cfg_data { + int cfgtype; + int flicker_type; + union { + struct msm_sensor_info_t sensor_info; + struct msm_sensor_init_params sensor_init_params; + void *setting; + } cfg; +}; + +struct csid_cfg_data { + enum csid_cfg_type_t cfgtype; + union { + uint32_t csid_version; + struct msm_camera_csid_params *csid_params; + } cfg; +}; + +struct csiphy_cfg_data { + enum csiphy_cfg_type_t cfgtype; + union { + struct msm_camera_csiphy_params *csiphy_params; + struct msm_camera_csi_lane_params *csi_lane_params; + } cfg; +}; + +enum eeprom_cfg_type_t { + CFG_EEPROM_GET_INFO, + CFG_EEPROM_GET_CAL_DATA, + CFG_EEPROM_READ_CAL_DATA, + CFG_EEPROM_READ_DATA, + CFG_EEPROM_READ_COMPRESSED_DATA, + CFG_EEPROM_WRITE_DATA, + CFG_EEPROM_GET_ERASESIZE, + CFG_EEPROM_ERASE, + CFG_EEPROM_POWER_ON, + CFG_EEPROM_POWER_OFF, + CFG_EEPROM_READ_DATA_FROM_HW, + CFG_EEPROM_GET_MM_INFO, + CFG_EEPROM_GET_FW_VERSION_INFO, +}; + +struct eeprom_get_t { + uint32_t num_bytes; +}; + +struct eeprom_read_t { + uint8_t *dbuffer; + uint32_t num_bytes; + uint32_t addr; + uint32_t comp_size; +}; + +struct eeprom_write_t { + uint8_t *dbuffer; + uint32_t num_bytes; + uint32_t addr; + uint32_t *write_size; + uint8_t compress; +}; + +struct eeprom_erase_t { + uint32_t num_bytes; + uint32_t addr; +}; + +struct eeprom_get_cmm_t { + uint32_t cmm_support; + uint32_t cmm_compression; + uint32_t cmm_size; +}; + +struct msm_eeprom_cfg_data { + enum eeprom_cfg_type_t cfgtype; + uint8_t is_supported; + union { + char eeprom_name[MAX_SENSOR_NAME]; + struct eeprom_get_t get_data; + struct eeprom_read_t read_data; + struct eeprom_write_t write_data; + struct eeprom_erase_t erase_data; + struct eeprom_get_cmm_t get_cmm_data; + } cfg; +}; + +enum msm_sensor_cfg_type_t { + CFG_SET_SLAVE_INFO, + CFG_SLAVE_READ_I2C, + CFG_WRITE_I2C_ARRAY, + CFG_SLAVE_WRITE_I2C_ARRAY, + CFG_WRITE_I2C_SEQ_ARRAY, + CFG_POWER_UP, + CFG_POWER_DOWN, + CFG_SET_STOP_STREAM_SETTING, + CFG_GET_SENSOR_INFO, + CFG_GET_SENSOR_INIT_PARAMS, + CFG_SET_INIT_SETTING, + CFG_SET_RESOLUTION, + CFG_SET_STOP_STREAM, + CFG_SET_START_STREAM, + CFG_SET_GPIO_STATE, + CFG_SET_SENSOR_OTP_CAL, // Randy 10.08 + CFG_SET_SATURATION, + CFG_SET_CONTRAST, + CFG_SET_SHARPNESS, + CFG_SET_ISO, + CFG_SET_EXPOSURE_COMPENSATION, + CFG_SET_ANTIBANDING, + CFG_SET_BESTSHOT_MODE, + CFG_SET_EFFECT, + CFG_SET_WHITE_BALANCE, + CFG_SET_AUTOFOCUS, + CFG_CANCEL_AUTOFOCUS, + CFG_SET_STREAM_TYPE, +}; + +enum msm_actuator_cfg_type_t { + CFG_GET_ACTUATOR_INFO, + CFG_SET_ACTUATOR_INFO, + CFG_SET_DEFAULT_FOCUS, + CFG_MOVE_FOCUS, + CFG_SET_POSITION, + CFG_ACTUATOR_POWERDOWN, + CFG_ACTUATOR_POWERUP, + CFG_SET_ACTUATOR_SW_LANDING, + CFG_ACTUATOR_INIT, +}; + +enum actuator_type { + ACTUATOR_VCM, + ACTUATOR_PIEZO, + ACTUATOR_HALL_EFFECT, + ACTUATOR_HVCM, + ACTUATOR_DW9804, +}; + +enum msm_actuator_data_type { + MSM_ACTUATOR_BYTE_DATA = 1, + MSM_ACTUATOR_WORD_DATA, +}; + +enum msm_actuator_addr_type { + MSM_ACTUATOR_BYTE_ADDR = 1, + MSM_ACTUATOR_WORD_ADDR, +}; + +enum msm_actuator_i2c_operation { + MSM_ACT_WRITE = 0, + MSM_ACT_POLL, +}; + +struct reg_settings_t { + uint16_t reg_addr; + enum msm_actuator_addr_type addr_type; + uint16_t reg_data; + enum msm_actuator_data_type data_type; + enum msm_actuator_i2c_operation i2c_operation; + uint32_t delay; +}; + +struct region_params_t { + /* [0] = ForwardDirection Macro boundary + [1] = ReverseDirection Inf boundary + */ + uint16_t step_bound[2]; + uint16_t code_per_step; +}; + +struct damping_params_t { + uint32_t damping_step; + uint32_t damping_delay; + uint32_t hw_params; +}; + +struct msm_actuator_move_params_t { + int8_t dir; + int8_t sign_dir; + int16_t dest_step_pos; + int32_t num_steps; + uint16_t curr_lens_pos; + struct damping_params_t *ringing_params; +}; + +struct msm_actuator_tuning_params_t { + int16_t initial_code; + uint16_t pwd_step; + uint16_t region_size; + uint32_t total_steps; + struct region_params_t *region_params; +}; + +struct msm_actuator_params_t { + enum actuator_type act_type; + uint8_t reg_tbl_size; + uint16_t data_size; + uint16_t init_setting_size; + uint32_t i2c_addr; + enum msm_actuator_addr_type i2c_addr_type; + enum msm_actuator_data_type i2c_data_type; + struct msm_actuator_reg_params_t *reg_tbl_params; + struct reg_settings_t *init_settings; +}; + +struct msm_actuator_set_info_t { + struct msm_actuator_params_t actuator_params; + struct msm_actuator_tuning_params_t af_tuning_params; +}; + +struct msm_actuator_get_info_t { + uint32_t focal_length_num; + uint32_t focal_length_den; + uint32_t f_number_num; + uint32_t f_number_den; + uint32_t f_pix_num; + uint32_t f_pix_den; + uint32_t total_f_dist_num; + uint32_t total_f_dist_den; + uint32_t hor_view_angle_num; + uint32_t hor_view_angle_den; + uint32_t ver_view_angle_num; + uint32_t ver_view_angle_den; +}; + +enum af_camera_name { + ACTUATOR_MAIN_CAM_0, + ACTUATOR_MAIN_CAM_1, + ACTUATOR_MAIN_CAM_2, + ACTUATOR_MAIN_CAM_3, + ACTUATOR_MAIN_CAM_4, + ACTUATOR_MAIN_CAM_5, + ACTUATOR_WEB_CAM_0, + ACTUATOR_WEB_CAM_1, + ACTUATOR_WEB_CAM_2, +}; + + +struct msm_actuator_set_position_t { + uint16_t number_of_steps; + uint16_t pos[MAX_NUMBER_OF_STEPS]; + uint16_t delay[MAX_NUMBER_OF_STEPS]; +}; + +struct msm_actuator_cfg_data { + int cfgtype; + uint8_t is_af_supported; + union { + struct msm_actuator_move_params_t move; + struct msm_actuator_set_info_t set_info; + struct msm_actuator_get_info_t get_info; + struct msm_actuator_set_position_t setpos; + enum af_camera_name cam_name; + } cfg; +}; + +enum msm_actuator_write_type { + MSM_ACTUATOR_WRITE_HW_DAMP, + MSM_ACTUATOR_WRITE_DAC, + MSM_ACTUATOR_WRITE_DAC_SEQ, +}; + +enum msm_actuator_init_focus_type{ + MSM_ACTUATOR_INIT_FOCUS_DELAY = 0xDD, + MSM_ACTUATOR_INIT_FOCUS_READ_STATUS = 0xDC, +}; + +struct msm_actuator_reg_params_t { + enum msm_actuator_write_type reg_write_type; + uint32_t hw_mask; + uint16_t reg_addr; + uint16_t hw_shift; + uint16_t data_shift; +}; + +enum msm_camera_led_config_t { + MSM_CAMERA_LED_OFF, + MSM_CAMERA_LED_LOW, + MSM_CAMERA_LED_HIGH, + MSM_CAMERA_LED_INIT, + MSM_CAMERA_LED_RELEASE, +}; + +struct msm_camera_led_cfg_t { + enum msm_camera_led_config_t cfgtype; + uint32_t torch_current; + uint32_t flash_current[MAX_LED_TRIGGERS]; +}; + +/* sensor init structures and enums */ +enum msm_sensor_init_cfg_type_t { + CFG_SINIT_PROBE, + CFG_SINIT_PROBE_DONE, + CFG_SINIT_PROBE_WAIT_DONE, +}; + +struct sensor_init_cfg_data { + enum msm_sensor_init_cfg_type_t cfgtype; + union { + void *setting; + } cfg; +}; + +struct ioctl_native_cmd { + unsigned short mode; + unsigned short address; + unsigned short value_1; + unsigned short value_2; + unsigned short value_3; +}; + +typedef struct +{ + unsigned short iso; + unsigned short shutterspeed; + unsigned short isFlashOn; +} exif_data_t; + +enum msm_cam_flicker_type { + MSM_CAM_FLICKER_50HZ, + MSM_CAM_FLICKER_60HZ, +}; + +#define VIDIOC_MSM_SENSOR_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data) + +#define VIDIOC_MSM_SENSOR_RELEASE \ + _IO('V', BASE_VIDIOC_PRIVATE + 2) + +#define VIDIOC_MSM_SENSOR_GET_SUBDEV_ID \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, uint32_t) + +#define VIDIOC_MSM_CSIPHY_IO_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csiphy_cfg_data) + +#define VIDIOC_MSM_CSID_IO_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct csid_cfg_data) + +#define VIDIOC_MSM_ACTUATOR_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_actuator_cfg_data) + +#define VIDIOC_MSM_FLASH_LED_DATA_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_led_cfg_t) + +#define VIDIOC_MSM_EEPROM_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_eeprom_cfg_data) + +#define VIDIOC_MSM_SENSOR_GET_AF_STATUS \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, uint32_t) + +#define VIDIOC_MSM_SENSOR_INIT_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct sensor_init_cfg_data) + +#define VIDIOC_MSM_SENSOR_NATIVE_CMD \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct ioctl_native_cmd) + +#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */ + +#endif /* __LINUX_MSM_CAM_SENSOR_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/media/msm_camera.h b/drivers/media/platform/msm/camera_v2_j5/include/media/msm_camera.h new file mode 100644 index 0000000000000000000000000000000000000000..58214e4685cb87a0241b38872265ead542d695fe --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/media/msm_camera.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2009-2013, The Linux Foundation. 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 and + * only 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. + * + */ +#ifndef __LINUX_MSM_CAMERA_H +#define __LINUX_MSM_CAMERA_H + +#include +#include + +#endif /* __LINUX_MSM_CAMERA_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/media/msm_camsensor_sdk.h b/drivers/media/platform/msm/camera_v2_j5/include/media/msm_camsensor_sdk.h new file mode 100644 index 0000000000000000000000000000000000000000..b01f3116dae304b0b4e383044e74521d4825d8e0 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/media/msm_camsensor_sdk.h @@ -0,0 +1,311 @@ +#ifndef __LINUX_MSM_CAMSENSOR_SDK_H +#define __LINUX_MSM_CAMSENSOR_SDK_H + +#include + +#define KVERSION 0x1 + +#define MAX_POWER_CONFIG 12 +#define GPIO_OUT_LOW (0 << 1) +#define GPIO_OUT_HIGH (1 << 1) +#define CSI_EMBED_DATA 0x12 +#define CSI_RESERVED_DATA_0 0x13 +#define CSI_YUV422_8 0x1E +#define CSI_RAW8 0x2A +#define CSI_RAW10 0x2B +#define CSI_RAW12 0x2C +#define CSI_DECODE_6BIT 0 +#define CSI_DECODE_8BIT 1 +#define CSI_DECODE_10BIT 2 +#define CSI_DECODE_DPCM_10_8_10 5 +#define MAX_CID 16 +#define I2C_SEQ_REG_DATA_MAX 256 +#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */ + +#define MAX_ACTUATOR_REG_TBL_SIZE 8 +#define MAX_ACTUATOR_REGION 5 +#define NUM_ACTUATOR_DIR 2 +#define MAX_ACTUATOR_SCENARIO 8 +#define MAX_ACT_MOD_NAME_SIZE 32 +#define MAX_ACT_NAME_SIZE 32 +#define MAX_ACTUATOR_INIT_SET 12 +#define MAX_I2C_REG_SET 12 + +#define MAX_NAME_SIZE 32 +#define MAX_FLASH_NUM 8 + +enum msm_sensor_camera_id_t { + CAMERA_0, + CAMERA_1, + CAMERA_2, + CAMERA_3, + MAX_CAMERAS, +}; + +enum i2c_freq_mode_t { + I2C_STANDARD_MODE, + I2C_FAST_MODE, + I2C_CUSTOM_MODE, + I2C_MAX_MODES, +}; + +enum camb_position_t { + BACK_CAMERA_B, + FRONT_CAMERA_B, + INVALID_CAMERA_B, +}; + +enum msm_sensor_power_seq_type_t { + SENSOR_CLK, + SENSOR_GPIO, + SENSOR_VREG, + SENSOR_I2C_MUX, + SENSOR_I2C, +}; + +enum msm_camera_i2c_reg_addr_type { + MSM_CAMERA_I2C_BYTE_ADDR = 1, + MSM_CAMERA_I2C_WORD_ADDR, + MSM_CAMERA_I2C_3B_ADDR, + MSM_CAMERA_I2C_ADDR_TYPE_MAX, +}; + +enum msm_camera_i2c_data_type { + MSM_CAMERA_I2C_BYTE_DATA = 1, + MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_DWORD_DATA, + MSM_CAMERA_I2C_SET_BYTE_MASK, + MSM_CAMERA_I2C_UNSET_BYTE_MASK, + MSM_CAMERA_I2C_SET_WORD_MASK, + MSM_CAMERA_I2C_UNSET_WORD_MASK, + MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA, + MSM_CAMERA_I2C_DATA_TYPE_MAX, +}; + +enum msm_sensor_power_seq_gpio_t { + SENSOR_GPIO_RESET, + SENSOR_GPIO_STANDBY, + SENSOR_GPIO_AF_PWDM, + SENSOR_GPIO_VIO, + SENSOR_GPIO_VANA, + SENSOR_GPIO_VDIG, + SENSOR_GPIO_VAF, + SENSOR_GPIO_FL_EN, + SENSOR_GPIO_FL_NOW, + SENSOR_GPIO_FL_RESET, + SENSOR_GPIO_CUSTOM1, + SENSOR_GPIO_CUSTOM2, + SENSOR_GPIO_MAX, +}; + +enum msm_camera_vreg_name_t { + CAM_VDIG, + CAM_VIO, + CAM_VANA, + CAM_VAF, + CAM_V_CUSTOM1, + CAM_V_CUSTOM2, + CAM_VREG_MAX, +}; + +enum msm_sensor_clk_type_t { + SENSOR_CAM_MCLK, + SENSOR_CAM_CLK, + SENSOR_CAM_CLK_MAX, +}; + +enum camerab_mode_t { + CAMERA_MODE_2D_B = (1<<0), + CAMERA_MODE_3D_B = (1<<1), + CAMERA_MODE_INVALID = (1<<2), +}; + +enum sensor_stats_type { + YRGB, + YYYY, +}; + +enum msm_actuator_data_type { + MSM_ACTUATOR_BYTE_DATA = 1, + MSM_ACTUATOR_WORD_DATA, +}; + +enum msm_actuator_addr_type { + MSM_ACTUATOR_BYTE_ADDR = 1, + MSM_ACTUATOR_WORD_ADDR, +}; + +enum msm_actuator_write_type { + MSM_ACTUATOR_WRITE_HW_DAMP, + MSM_ACTUATOR_WRITE_DAC, +}; + +enum msm_actuator_i2c_operation { + MSM_ACT_WRITE = 0, + MSM_ACT_POLL, +}; + +enum actuator_type { + ACTUATOR_VCM, + ACTUATOR_PIEZO, + ACTUATOR_HVCM, +}; + +enum msm_flash_driver_type { + FLASH_DRIVER_PMIC, + FLASH_DRIVER_I2C, + FLASH_DRIVER_GPIO, + FLASH_DRIVER_DEFAULT +}; + +enum msm_flash_cfg_type_t { + CFG_FLASH_INIT, + CFG_FLASH_RELEASE, + CFG_FLASH_OFF, + CFG_FLASH_LOW, + CFG_FLASH_HIGH, +}; + +struct msm_sensor_power_setting { + enum msm_sensor_power_seq_type_t seq_type; + uint16_t seq_val; + long config_val; + uint16_t delay; + void *data[10]; +}; + +struct msm_sensor_power_setting_array { + struct msm_sensor_power_setting power_setting_a[MAX_POWER_CONFIG]; + struct msm_sensor_power_setting *power_setting; + uint16_t size; + struct msm_sensor_power_setting power_down_setting_a[MAX_POWER_CONFIG]; + struct msm_sensor_power_setting *power_down_setting; + uint16_t size_down; +}; + +struct msm_sensor_init_params { + /* mask of modes supported: 2D, 3D */ + int modes_supported; + /* sensor position: front, back */ + enum camb_position_t position; + /* sensor mount angle */ + uint32_t sensor_mount_angle; +}; + +struct msm_sensor_id_info_t { + uint16_t sensor_id_reg_addr; + uint16_t sensor_id; +}; + +struct msm_camera_sensor_slave_info { + char sensor_name[32]; + char eeprom_name[32]; + char actuator_name[32]; + char ois_name[32]; + char flash_name[32]; + enum msm_sensor_camera_id_t camera_id; + uint16_t slave_addr; + enum i2c_freq_mode_t i2c_freq_mode; + enum msm_camera_i2c_reg_addr_type addr_type; + struct msm_sensor_id_info_t sensor_id_info; + struct msm_sensor_power_setting_array power_setting_array; + uint8_t is_init_params_valid; + struct msm_sensor_init_params sensor_init_params; + uint8_t is_flash_supported; +}; + +struct msm_camera_i2c_reg_array { + uint16_t reg_addr; + uint16_t reg_data; + uint32_t delay; +}; + +struct msm_camera_i2c_reg_setting { + struct msm_camera_i2c_reg_array *reg_setting; + uint16_t size; + enum msm_camera_i2c_reg_addr_type addr_type; + enum msm_camera_i2c_data_type data_type; + uint16_t delay; +}; + +struct msm_camera_csid_vc_cfg { + uint8_t cid; + uint8_t dt; + uint8_t decode_format; +}; + +struct msm_camera_csid_lut_params { + uint8_t num_cid; + struct msm_camera_csid_vc_cfg vc_cfg_a[MAX_CID]; + struct msm_camera_csid_vc_cfg *vc_cfg[MAX_CID]; +}; + +struct msm_camera_csid_params { + uint8_t lane_cnt; + uint16_t lane_assign; + uint8_t phy_sel; + uint32_t csi_clk; + struct msm_camera_csid_lut_params lut_params; +}; + +struct msm_camera_csiphy_params { + uint8_t lane_cnt; + uint8_t settle_cnt; + uint16_t lane_mask; + uint8_t combo_mode; + uint8_t csid_core; + uint32_t csiphy_clk; +}; + +struct msm_camera_i2c_seq_reg_array { + uint16_t reg_addr; + uint8_t reg_data[I2C_SEQ_REG_DATA_MAX]; + uint16_t reg_data_size; +}; + +struct msm_camera_i2c_seq_reg_setting { + struct msm_camera_i2c_seq_reg_array *reg_setting; + uint16_t size; + enum msm_camera_i2c_reg_addr_type addr_type; + uint16_t delay; +}; + +struct msm_actuator_reg_params_t { + enum msm_actuator_write_type reg_write_type; + uint32_t hw_mask; + uint16_t reg_addr; + uint16_t hw_shift; + uint16_t data_shift; +}; + +struct damping_params_t { + uint32_t damping_step; + uint32_t damping_delay; + uint32_t hw_params; +}; + +struct region_params_t { + /* [0] = ForwardDirection Macro boundary + [1] = ReverseDirection Inf boundary + */ + uint16_t step_bound[2]; + uint16_t code_per_step; +}; + +struct reg_settings_t { + uint16_t reg_addr; + enum msm_actuator_addr_type addr_type; + uint16_t reg_data; + enum msm_actuator_data_type data_type; + enum msm_actuator_i2c_operation i2c_operation; + uint32_t delay; +}; + +struct msm_camera_i2c_reg_setting_array { + struct msm_camera_i2c_reg_array reg_setting_a[MAX_I2C_REG_SET]; + uint16_t size; + enum msm_camera_i2c_reg_addr_type addr_type; + enum msm_camera_i2c_data_type data_type; + uint16_t delay; +}; +#endif /* __LINUX_MSM_CAM_SENSOR_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_camera.h b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_camera.h new file mode 100644 index 0000000000000000000000000000000000000000..7f19a88af73b1413fdbd60119acfc596b758a302 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_camera.h @@ -0,0 +1,185 @@ +#ifndef __LINUX_MSMB_CAMERA_H +#define __LINUX_MSMB_CAMERA_H + +#include +#include +#include + +#define MSM_CAM_V4L2_IOCTL_NOTIFY \ + _IOW('V', BASE_VIDIOC_PRIVATE + 30, struct msm_v4l2_event_data) + +#define MSM_CAM_V4L2_IOCTL_NOTIFY_META \ + _IOW('V', BASE_VIDIOC_PRIVATE + 31, struct msm_v4l2_event_data) + +#define MSM_CAM_V4L2_IOCTL_CMD_ACK \ + _IOW('V', BASE_VIDIOC_PRIVATE + 32, struct msm_v4l2_event_data) + +#define MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR \ + _IOW('V', BASE_VIDIOC_PRIVATE + 33, struct msm_v4l2_event_data) + +#define MSM_CAM_V4L2_IOCTL_NOTIFY_MODULE_STATUS \ + _IOW('V', BASE_VIDIOC_PRIVATE + 34, struct v4l2_event) + +#define QCAMERA_DEVICE_GROUP_ID 1 +#define QCAMERA_VNODE_GROUP_ID 2 +#define MSM_CAMERA_NAME "msm_camera" +#define MSM_CONFIGURATION_NAME "msm_config" +#define MSM_CAMERA_DUMMY_NAME "msm_cam_dummy" + +#define MSM_CAMERA_SUBDEV_CSIPHY 0 +#define MSM_CAMERA_SUBDEV_CSID 1 +#define MSM_CAMERA_SUBDEV_ISPIF 2 +#define MSM_CAMERA_SUBDEV_VFE 3 +#define MSM_CAMERA_SUBDEV_AXI 4 +#define MSM_CAMERA_SUBDEV_VPE 5 +#define MSM_CAMERA_SUBDEV_SENSOR 6 +#define MSM_CAMERA_SUBDEV_ACTUATOR 7 +#define MSM_CAMERA_SUBDEV_EEPROM 8 +#define MSM_CAMERA_SUBDEV_CPP 9 +#define MSM_CAMERA_SUBDEV_CCI 10 +#define MSM_CAMERA_SUBDEV_LED_FLASH 11 +#define MSM_CAMERA_SUBDEV_STROBE_FLASH 12 +#define MSM_CAMERA_SUBDEV_BUF_MNGR 13 +#define MSM_CAMERA_SUBDEV_SENSOR_INIT 14 + +#define MSM_MAX_CAMERA_SENSORS 5 + +/* The below macro is defined to put an upper limit on maximum + * number of buffer requested per stream. In case of extremely + * large value for number of buffer due to data structure corruption + * we return error to avoid integer overflow. This value may be + * configured in future*/ +#define MSM_CAMERA_MAX_STREAM_BUF 40 + +/* featur base */ +#define MSM_CAMERA_FEATURE_BASE 0x00010000 +#define MSM_CAMERA_FEATURE_SHUTDOWN (MSM_CAMERA_FEATURE_BASE + 1) + +#define MSM_CAMERA_STATUS_BASE 0x00020000 +#define MSM_CAMERA_STATUS_FAIL (MSM_CAMERA_STATUS_BASE + 1) +#define MSM_CAMERA_STATUS_SUCCESS (MSM_CAMERA_STATUS_BASE + 2) + +/* event type */ +#define MSM_CAMERA_V4L2_EVENT_TYPE (V4L2_EVENT_PRIVATE_START + 0x00002000) + +/* event id */ +#define MSM_CAMERA_EVENT_MIN 0 +#define MSM_CAMERA_NEW_SESSION (MSM_CAMERA_EVENT_MIN + 1) +#define MSM_CAMERA_DEL_SESSION (MSM_CAMERA_EVENT_MIN + 2) +#define MSM_CAMERA_SET_PARM (MSM_CAMERA_EVENT_MIN + 3) +#define MSM_CAMERA_GET_PARM (MSM_CAMERA_EVENT_MIN + 4) +#define MSM_CAMERA_MAPPING_CFG (MSM_CAMERA_EVENT_MIN + 5) +#define MSM_CAMERA_MAPPING_SES (MSM_CAMERA_EVENT_MIN + 6) +#define MSM_CAMERA_MSM_NOTIFY (MSM_CAMERA_EVENT_MIN + 7) +#define MSM_CAMERA_EVENT_MAX (MSM_CAMERA_EVENT_MIN + 8) + +/* data.command */ +#define MSM_CAMERA_PRIV_S_CROP (V4L2_CID_PRIVATE_BASE + 1) +#define MSM_CAMERA_PRIV_G_CROP (V4L2_CID_PRIVATE_BASE + 2) +#define MSM_CAMERA_PRIV_G_FMT (V4L2_CID_PRIVATE_BASE + 3) +#define MSM_CAMERA_PRIV_S_FMT (V4L2_CID_PRIVATE_BASE + 4) +#define MSM_CAMERA_PRIV_TRY_FMT (V4L2_CID_PRIVATE_BASE + 5) +#define MSM_CAMERA_PRIV_METADATA (V4L2_CID_PRIVATE_BASE + 6) +#define MSM_CAMERA_PRIV_QUERY_CAP (V4L2_CID_PRIVATE_BASE + 7) +#define MSM_CAMERA_PRIV_STREAM_ON (V4L2_CID_PRIVATE_BASE + 8) +#define MSM_CAMERA_PRIV_STREAM_OFF (V4L2_CID_PRIVATE_BASE + 9) +#define MSM_CAMERA_PRIV_NEW_STREAM (V4L2_CID_PRIVATE_BASE + 10) +#define MSM_CAMERA_PRIV_DEL_STREAM (V4L2_CID_PRIVATE_BASE + 11) +#define MSM_CAMERA_PRIV_SHUTDOWN (V4L2_CID_PRIVATE_BASE + 12) +#define MSM_CAMERA_PRIV_STREAM_INFO_SYNC \ + (V4L2_CID_PRIVATE_BASE + 13) + +/* data.status - success */ +#define MSM_CAMERA_CMD_SUCESS 0x00000001 +#define MSM_CAMERA_BUF_MAP_SUCESS 0x00000002 + +/* data.status - error */ +#define MSM_CAMERA_ERR_EVT_BASE 0x00010000 +#define MSM_CAMERA_ERR_CMD_FAIL (MSM_CAMERA_ERR_EVT_BASE + 1) +#define MSM_CAMERA_ERR_MAPPING (MSM_CAMERA_ERR_EVT_BASE + 2) + +/* The msm_v4l2_event_data structure should match the + * v4l2_event.u.data field. + * should not exceed 16 elements */ +struct msm_v4l2_event_data { + /*word 0*/ + unsigned int command; + /*word 1*/ + unsigned int status; + /*word 2*/ + unsigned int session_id; + /*word 3*/ + unsigned int stream_id; + /*word 4*/ + unsigned int map_op; + /*word 5*/ + unsigned int map_buf_idx; + /*word 6*/ + unsigned int notify; + /*word 7*/ + unsigned int arg_value; + /*word 8*/ + unsigned int ret_value; + /*word 9*/ + unsigned int v4l2_event_type; + /*word 10*/ + unsigned int v4l2_event_id; + /*word 11*/ + unsigned int nop5; + /*word 12*/ + unsigned int nop6; + /*word 13*/ + unsigned int nop7; + /*word 14*/ + unsigned int nop8; + /*word 15*/ + unsigned int nop9; +}; + +/* map to v4l2_format.fmt.raw_data */ +struct msm_v4l2_format_data { + enum v4l2_buf_type type; + unsigned int width; + unsigned int height; + unsigned int pixelformat; /* FOURCC */ + unsigned char num_planes; + unsigned int plane_sizes[VIDEO_MAX_PLANES]; +}; + +/* MSM Four-character-code (FOURCC) */ +#define msm_v4l2_fourcc(a, b, c, d)\ + ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) |\ + ((__u32)(d) << 24)) + +/* Composite stats */ +#define MSM_V4L2_PIX_FMT_STATS_COMB v4l2_fourcc('S', 'T', 'C', 'M') +/* AEC stats */ +#define MSM_V4L2_PIX_FMT_STATS_AE v4l2_fourcc('S', 'T', 'A', 'E') +/* AF stats */ +#define MSM_V4L2_PIX_FMT_STATS_AF v4l2_fourcc('S', 'T', 'A', 'F') +/* AWB stats */ +#define MSM_V4L2_PIX_FMT_STATS_AWB v4l2_fourcc('S', 'T', 'W', 'B') +/* IHIST stats */ +#define MSM_V4L2_PIX_FMT_STATS_IHST v4l2_fourcc('I', 'H', 'S', 'T') +/* Column count stats */ +#define MSM_V4L2_PIX_FMT_STATS_CS v4l2_fourcc('S', 'T', 'C', 'S') +/* Row count stats */ +#define MSM_V4L2_PIX_FMT_STATS_RS v4l2_fourcc('S', 'T', 'R', 'S') +/* Bayer Grid stats */ +#define MSM_V4L2_PIX_FMT_STATS_BG v4l2_fourcc('S', 'T', 'B', 'G') +/* Bayer focus stats */ +#define MSM_V4L2_PIX_FMT_STATS_BF v4l2_fourcc('S', 'T', 'B', 'F') +/* Bayer hist stats */ +#define MSM_V4L2_PIX_FMT_STATS_BHST v4l2_fourcc('B', 'H', 'S', 'T') + +enum smmu_attach_mode { + NON_SECURE_MODE, + SECURE_MODE, + MAX_PROTECTION_MODE, +}; + +struct msm_camera_smmu_attach_type { + enum smmu_attach_mode attach; +}; + +#endif /* __LINUX_MSMB_CAMERA_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_isp.h b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_isp.h new file mode 100644 index 0000000000000000000000000000000000000000..af9fae4e11cd61b1b734aa0ec6ac5f13b837b177 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_isp.h @@ -0,0 +1,489 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ +#ifndef __MSMB_ISP__ +#define __MSMB_ISP__ + +#include + +#define MAX_PLANES_PER_STREAM 3 +#define MAX_NUM_STREAM 7 + +#define ISP_VERSION_44 44 +#define ISP_VERSION_40 40 +#define ISP_VERSION_32 32 +#define ISP_NATIVE_BUF_BIT (0x10000 << 0) +#define ISP0_BIT (0x10000 << 1) +#define ISP1_BIT (0x10000 << 2) +#define ISP_META_CHANNEL_BIT (0x10000 << 3) +#define ISP_SCRATCH_BUF_BIT (0x10000 << 4) +#define ISP_STATS_STREAM_BIT 0x80000000 + +struct msm_vfe_cfg_cmd_list; + +#define MSM_VFE_REG_CFG_FRAME_ID_NOT_MATCH_ERROR 0xCACFC + +enum ISP_START_PIXEL_PATTERN { + ISP_BAYER_RGRGRG, + ISP_BAYER_GRGRGR, + ISP_BAYER_BGBGBG, + ISP_BAYER_GBGBGB, + ISP_YUV_YCbYCr, + ISP_YUV_YCrYCb, + ISP_YUV_CbYCrY, + ISP_YUV_CrYCbY, + ISP_PIX_PATTERN_MAX +}; + +enum msm_vfe_plane_fmt { + Y_PLANE, + CB_PLANE, + CR_PLANE, + CRCB_PLANE, + CBCR_PLANE, + VFE_PLANE_FMT_MAX +}; + +enum msm_vfe_input_src { + VFE_PIX_0, + VFE_RAW_0, + VFE_RAW_1, + VFE_RAW_2, + VFE_SRC_MAX, +}; + +enum msm_vfe_axi_stream_src { + PIX_ENCODER, + PIX_VIEWFINDER, + CAMIF_RAW, + IDEAL_RAW, + RDI_INTF_0, + RDI_INTF_1, + RDI_INTF_2, + VFE_AXI_SRC_MAX +}; + +enum msm_vfe_frame_skip_pattern { + NO_SKIP, + EVERY_2FRAME, + EVERY_3FRAME, + EVERY_4FRAME, + EVERY_5FRAME, + EVERY_6FRAME, + EVERY_7FRAME, + EVERY_8FRAME, + EVERY_16FRAME, + EVERY_32FRAME, + SKIP_ALL, + MAX_SKIP, +}; + +enum msm_vfe_camif_input { + CAMIF_DISABLED, + CAMIF_PAD_REG_INPUT, + CAMIF_MIDDI_INPUT, + CAMIF_MIPI_INPUT, +}; + +struct msm_vfe_camif_cfg { + uint32_t lines_per_frame; + uint32_t pixels_per_line; + uint32_t first_pixel; + uint32_t last_pixel; + uint32_t first_line; + uint32_t last_line; + uint32_t epoch_line0; + uint32_t epoch_line1; + enum msm_vfe_camif_input camif_input; +}; + +enum msm_vfe_inputmux { + CAMIF, + TESTGEN, + EXTERNAL_READ, +}; + +enum msm_vfe_stats_composite_group { + STATS_COMPOSITE_GRP_NONE, + STATS_COMPOSITE_GRP_1, + STATS_COMPOSITE_GRP_2, + STATS_COMPOSITE_GRP_MAX, +}; + +struct msm_vfe_pix_cfg { + struct msm_vfe_camif_cfg camif_cfg; + enum msm_vfe_inputmux input_mux; + enum ISP_START_PIXEL_PATTERN pixel_pattern; + uint32_t input_format; +}; + +struct msm_vfe_rdi_cfg { + uint8_t cid; + uint8_t frame_based; +}; + +struct msm_vfe_input_cfg { + union { + struct msm_vfe_pix_cfg pix_cfg; + struct msm_vfe_rdi_cfg rdi_cfg; + } d; + enum msm_vfe_input_src input_src; + uint32_t input_pix_clk; +}; + +struct msm_vfe_axi_plane_cfg { + uint32_t output_width; /*Include padding*/ + uint32_t output_height; + uint32_t output_stride; + uint32_t output_scan_lines; + uint32_t output_plane_format; /*Y/Cb/Cr/CbCr*/ + uint32_t plane_addr_offset; + uint8_t csid_src; /*RDI 0-2*/ + uint8_t rdi_cid;/*CID 1-16*/ +}; + +struct msm_vfe_axi_stream_request_cmd { + uint32_t session_id; + uint32_t stream_id; + uint32_t vt_enable; + uint32_t output_format;/*Planar/RAW/Misc*/ + enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/ + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; + + uint32_t burst_count; + uint32_t hfr_mode; + uint8_t frame_base; + + uint32_t init_frame_drop; /*MAX 31 Frames*/ + enum msm_vfe_frame_skip_pattern frame_skip_pattern; + uint8_t buf_divert; /* if TRUE no vb2 buf done. */ + /*Return values*/ + uint32_t axi_stream_handle; + uint32_t burst_len; +}; + +struct msm_vfe_axi_stream_release_cmd { + uint32_t stream_handle; +}; + +enum msm_vfe_axi_stream_cmd { + STOP_STREAM, + START_STREAM, + STOP_IMMEDIATELY, +}; + +struct msm_vfe_axi_stream_cfg_cmd { + uint8_t num_streams; + uint32_t stream_handle[MAX_NUM_STREAM]; + enum msm_vfe_axi_stream_cmd cmd; +}; + +enum msm_vfe_axi_stream_update_type { + AXI_STREAM_UPDATE_INVALID, + ENABLE_STREAM_BUF_DIVERT, + DISABLE_STREAM_BUF_DIVERT, + UPDATE_STREAM_FRAMEDROP_PATTERN, + UPDATE_STREAM_AXI_CONFIG, + UPDATE_STREAM_REQUEST_FRAMES, +}; + +struct msm_vfe_axi_stream_cfg_update_info { + uint32_t stream_handle; + uint32_t output_format; + uint32_t request_frm_num; + enum msm_vfe_frame_skip_pattern skip_pattern; + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; +}; + +struct msm_vfe_axi_halt_cmd { + uint32_t stop_camif; //Boolean whether stop camif is to be done + uint32_t overflow_detected; +}; + +struct msm_vfe_axi_reset_cmd { + uint32_t blocking; //Boolean whether stop camif is to be done + unsigned long frame_id; +}; + +struct msm_vfe_axi_restart_cmd { + uint32_t enable_camif; //Boolean whether stop camif is to be done +}; + +struct msm_vfe_axi_stream_update_cmd { + uint32_t num_streams; + enum msm_vfe_axi_stream_update_type update_type; + struct msm_vfe_axi_stream_cfg_update_info update_info[MAX_NUM_STREAM]; +}; + +enum msm_isp_stats_type { + MSM_ISP_STATS_AEC, /* legacy based AEC */ + MSM_ISP_STATS_AF, /* legacy based AF */ + MSM_ISP_STATS_AWB, /* legacy based AWB */ + MSM_ISP_STATS_RS, /* legacy based RS */ + MSM_ISP_STATS_CS, /* legacy based CS */ + MSM_ISP_STATS_IHIST, /* legacy based HIST */ + MSM_ISP_STATS_SKIN, /* legacy based SKIN */ + MSM_ISP_STATS_BG, /* Bayer Grids */ + MSM_ISP_STATS_BF, /* Bayer Focus */ + MSM_ISP_STATS_BE, /* Bayer Exposure*/ + MSM_ISP_STATS_BHIST, /* Bayer Hist */ + MSM_ISP_STATS_BF_SCALE, /* Bayer Focus scale */ + MSM_ISP_STATS_MAX /* MAX */ +}; + +struct msm_vfe_stats_stream_request_cmd { + uint32_t session_id; + uint32_t stream_id; + enum msm_isp_stats_type stats_type; + uint32_t composite_flag; + uint32_t framedrop_pattern; + uint32_t irq_subsample_pattern; + uint32_t buffer_offset; + uint32_t stream_handle; +}; + +struct msm_vfe_stats_stream_release_cmd { + uint32_t stream_handle; +}; +struct msm_vfe_stats_stream_cfg_cmd { + uint8_t num_streams; + uint32_t stream_handle[MSM_ISP_STATS_MAX]; + uint8_t enable; + uint32_t stats_burst_len; +}; + +enum msm_vfe_reg_cfg_type { + VFE_WRITE, + VFE_WRITE_MB, + VFE_READ, + VFE_CFG_MASK, + VFE_WRITE_DMI_16BIT, + VFE_WRITE_DMI_32BIT, + VFE_WRITE_DMI_64BIT, + VFE_READ_DMI_16BIT, + VFE_READ_DMI_32BIT, + VFE_READ_DMI_64BIT, + GET_MAX_CLK_RATE, + GET_ISP_ID, + VFE_HW_UPDATE_LOCK, + VFE_HW_UPDATE_UNLOCK, + SET_WM_UB_SIZE, +}; + +struct msm_vfe_cfg_cmd2 { + uint16_t num_cfg; + uint16_t cmd_len; + uint32_t frame_id; + void __user *cfg_data; + void __user *cfg_cmd; +}; + +struct msm_vfe_cfg_cmd_list { + struct msm_vfe_cfg_cmd2 cfg_cmd; + struct msm_vfe_cfg_cmd_list *next; + uint32_t next_size; +}; + +struct msm_vfe_reg_rw_info { + uint32_t reg_offset; + uint32_t cmd_data_offset; + uint32_t len; +}; + +struct msm_vfe_reg_mask_info { + uint32_t reg_offset; + uint32_t mask; + uint32_t val; +}; + +struct msm_vfe_reg_dmi_info { + uint32_t hi_tbl_offset; /*Optional*/ + uint32_t lo_tbl_offset; /*Required*/ + uint32_t len; +}; + +struct msm_vfe_reg_cfg_cmd { + union { + struct msm_vfe_reg_rw_info rw_info; + struct msm_vfe_reg_mask_info mask_info; + struct msm_vfe_reg_dmi_info dmi_info; + } u; + + enum msm_vfe_reg_cfg_type cmd_type; +}; + +enum msm_isp_buf_type { + ISP_PRIVATE_BUF, + ISP_SHARE_BUF, + MAX_ISP_BUF_TYPE, +}; + +struct msm_isp_buf_request { + uint32_t session_id; + uint32_t stream_id; + uint8_t num_buf; + uint32_t handle; + enum msm_isp_buf_type buf_type; +}; + +struct msm_isp_qbuf_info { + uint32_t handle; + int32_t buf_idx; + /*Only used for prepare buffer*/ + struct v4l2_buffer buffer; + /*Only used for diverted buffer*/ + uint32_t dirty_buf; +}; + +struct msm_vfe_axi_src_state { + enum msm_vfe_input_src input_src; + uint32_t src_active; +}; + +enum msm_isp_event_idx { + ISP_REG_UPDATE = 0, + ISP_EPOCH_0 = 1, + ISP_EPOCH_1 = 2, + ISP_START_ACK = 3, + ISP_STOP_ACK = 4, + ISP_IRQ_VIOLATION = 5, + ISP_WM_BUS_OVERFLOW = 6, + ISP_STATS_OVERFLOW = 7, + ISP_CAMIF_ERROR = 8, + ISP_BUF_DONE = 9, + ISP_FE_RD_DONE = 10, + ISP_EVENT_MAX = 11 +}; + +#define ISP_EVENT_OFFSET 8 +#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START) +#define ISP_BUF_EVENT_BASE (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET)) +#define ISP_STATS_EVENT_BASE (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET)) +#define ISP_CAMIF_EVENT_BASE (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET)) +#define ISP_STREAM_EVENT_BASE (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET)) +#define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE) +#define ISP_EVENT_EPOCH_0 (ISP_EVENT_BASE + ISP_EPOCH_0) +#define ISP_EVENT_EPOCH_1 (ISP_EVENT_BASE + ISP_EPOCH_1) +#define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK) +#define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK) +#define ISP_EVENT_IRQ_VIOLATION (ISP_EVENT_BASE + ISP_IRQ_VIOLATION) +#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW) +#define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW) +#define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR) +#define ISP_EVENT_SOF (ISP_CAMIF_EVENT_BASE) +#define ISP_EVENT_EOF (ISP_CAMIF_EVENT_BASE + 1) +#define ISP_EVENT_BUF_DONE (ISP_EVENT_BASE + ISP_BUF_DONE) +#define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE) +#define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE) +#define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX) +#define ISP_EVENT_FE_READ_DONE (ISP_EVENT_BASE + ISP_FE_RD_DONE) +#define ISP_EVENT_STREAM_UPDATE_DONE (ISP_STREAM_EVENT_BASE) +/* The msm_v4l2_event_data structure should match the + * v4l2_event.u.data field. + * should not exceed 64 bytes */ + +struct msm_isp_buf_event { + uint32_t session_id; + uint32_t stream_id; + uint32_t handle; + uint32_t output_format; + int8_t buf_idx; +}; +struct msm_isp_stats_event { + uint32_t stats_mask; /* 4 bytes */ + uint8_t stats_buf_idxs[MSM_ISP_STATS_MAX]; /* 11 bytes */ +}; + +struct msm_isp_stream_ack { + uint32_t session_id; + uint32_t stream_id; + uint32_t handle; +}; + +struct msm_isp_event_data { + /*Wall clock except for buffer divert events + *which use monotonic clock + */ + struct timeval timestamp; + /* Monotonic timestamp since bootup */ + struct timeval mono_timestamp; + enum msm_vfe_input_src input_intf; + uint32_t frame_id; + union { + struct msm_isp_stats_event stats; + struct msm_isp_buf_event buf_done; + } u; /* union can have max 52 bytes */ +}; + +#define V4L2_PIX_FMT_QBGGR8 v4l2_fourcc('Q', 'B', 'G', '8') +#define V4L2_PIX_FMT_QGBRG8 v4l2_fourcc('Q', 'G', 'B', '8') +#define V4L2_PIX_FMT_QGRBG8 v4l2_fourcc('Q', 'G', 'R', '8') +#define V4L2_PIX_FMT_QRGGB8 v4l2_fourcc('Q', 'R', 'G', '8') +#define V4L2_PIX_FMT_QBGGR10 v4l2_fourcc('Q', 'B', 'G', '0') +#define V4L2_PIX_FMT_QGBRG10 v4l2_fourcc('Q', 'G', 'B', '0') +#define V4L2_PIX_FMT_QGRBG10 v4l2_fourcc('Q', 'G', 'R', '0') +#define V4L2_PIX_FMT_QRGGB10 v4l2_fourcc('Q', 'R', 'G', '0') +#define V4L2_PIX_FMT_QBGGR12 v4l2_fourcc('Q', 'B', 'G', '2') +#define V4L2_PIX_FMT_QGBRG12 v4l2_fourcc('Q', 'G', 'B', '2') +#define V4L2_PIX_FMT_QGRBG12 v4l2_fourcc('Q', 'G', 'R', '2') +#define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2') +#define V4L2_PIX_FMT_NV14 v4l2_fourcc('N', 'V', '1', '4') +#define V4L2_PIX_FMT_NV41 v4l2_fourcc('N', 'V', '4', '1') +#define V4L2_PIX_FMT_META v4l2_fourcc('Q', 'M', 'E', 'T') + +#define VIDIOC_MSM_VFE_REG_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2) + +#define VIDIOC_MSM_ISP_REQUEST_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct msm_isp_buf_request) + +#define VIDIOC_MSM_ISP_ENQUEUE_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE+2, struct msm_isp_qbuf_info) + +#define VIDIOC_MSM_ISP_RELEASE_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE+3, struct msm_isp_buf_request) + +#define VIDIOC_MSM_ISP_REQUEST_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+4, struct msm_vfe_axi_stream_request_cmd) + +#define VIDIOC_MSM_ISP_CFG_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+5, struct msm_vfe_axi_stream_cfg_cmd) + +#define VIDIOC_MSM_ISP_RELEASE_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+6, struct msm_vfe_axi_stream_release_cmd) + +#define VIDIOC_MSM_ISP_INPUT_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE+7, struct msm_vfe_input_cfg) + +#define VIDIOC_MSM_ISP_SET_SRC_STATE \ + _IOWR('V', BASE_VIDIOC_PRIVATE+8, struct msm_vfe_axi_src_state) + +#define VIDIOC_MSM_ISP_REQUEST_STATS_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+9, \ + struct msm_vfe_stats_stream_request_cmd) + +#define VIDIOC_MSM_ISP_CFG_STATS_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+10, struct msm_vfe_stats_stream_cfg_cmd) + +#define VIDIOC_MSM_ISP_RELEASE_STATS_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+11, \ + struct msm_vfe_stats_stream_release_cmd) + +#define VIDIOC_MSM_ISP_REG_UPDATE_CMD \ + _IOWR('V', BASE_VIDIOC_PRIVATE+12, enum msm_vfe_input_src) + +#define VIDIOC_MSM_ISP_UPDATE_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE+13, struct msm_vfe_axi_stream_update_cmd) + +#define VIDIOC_MSM_VFE_REG_LIST_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE+14, struct msm_vfe_cfg_cmd_list) + +#endif /* __MSMB_ISP__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_ispif.h b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_ispif.h new file mode 100644 index 0000000000000000000000000000000000000000..641723731ac01c2d4b423a0c31677d6b32d4b38e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_ispif.h @@ -0,0 +1,124 @@ +#ifndef MSM_CAM_ISPIF_H +#define MSM_CAM_ISPIF_H + +#define CSID_VERSION_V20 0x02000011 +#define CSID_VERSION_V22 0x02001000 +#define CSID_VERSION_V30 0x30000000 +#define CSID_VERSION_V3 0x30000000 + +enum msm_ispif_vfe_intf { + VFE0, + VFE1, + VFE_MAX +}; +#define VFE0_MASK (1 << VFE0) +#define VFE1_MASK (1 << VFE1) + +enum msm_ispif_intftype { + PIX0, + RDI0, + PIX1, + RDI1, + RDI2, + INTF_MAX +}; +#define MAX_PARAM_ENTRIES (INTF_MAX * 2) +#define MAX_CID_CH 8 + +#define PIX0_MASK (1 << PIX0) +#define PIX1_MASK (1 << PIX1) +#define RDI0_MASK (1 << RDI0) +#define RDI1_MASK (1 << RDI1) +#define RDI2_MASK (1 << RDI2) + + +enum msm_ispif_vc { + VC0, + VC1, + VC2, + VC3, + VC_MAX +}; + +enum msm_ispif_cid { + CID0, + CID1, + CID2, + CID3, + CID4, + CID5, + CID6, + CID7, + CID8, + CID9, + CID10, + CID11, + CID12, + CID13, + CID14, + CID15, + CID_MAX +}; + +enum msm_ispif_csid { + CSID0, + CSID1, + CSID2, + CSID3, + CSID_MAX +}; + +struct msm_ispif_params_entry { + enum msm_ispif_vfe_intf vfe_intf; + enum msm_ispif_intftype intftype; + int num_cids; + enum msm_ispif_cid cids[3]; + enum msm_ispif_csid csid; + int crop_enable; + uint16_t crop_start_pixel; + uint16_t crop_end_pixel; +}; + +struct msm_ispif_param_data { + uint32_t num; + struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES]; +}; + +struct msm_isp_info { + uint32_t max_resolution; + uint32_t id; + uint32_t ver; +}; + +struct msm_ispif_vfe_info { + int num_vfe; + struct msm_isp_info info[VFE_MAX]; +}; + +enum ispif_cfg_type_t { + ISPIF_CLK_ENABLE, + ISPIF_CLK_DISABLE, + ISPIF_INIT, + ISPIF_CFG, + ISPIF_START_FRAME_BOUNDARY, + ISPIF_STOP_FRAME_BOUNDARY, + ISPIF_STOP_IMMEDIATELY, + ISPIF_RELEASE, + ISPIF_ENABLE_REG_DUMP, + ISPIF_SET_VFE_INFO, +}; + +struct ispif_cfg_data { + enum ispif_cfg_type_t cfg_type; + union { + int reg_dump; /* ISPIF_ENABLE_REG_DUMP */ + uint32_t csid_version; /* ISPIF_INIT */ + struct msm_ispif_vfe_info vfe_info; /* ISPIF_SET_VFE_INFO */ + struct msm_ispif_param_data params; /* CFG, START, STOP */ + }; +}; + +#define VIDIOC_MSM_ISPIF_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data) + +#endif /* MSM_CAM_ISPIF_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_pproc.h b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_pproc.h new file mode 100644 index 0000000000000000000000000000000000000000..fd76f554af192d2d17fafbc75d6084fba5459e63 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/media/msmb_pproc.h @@ -0,0 +1,361 @@ +#ifndef __MSMB_PPROC_H +#define __MSMB_PPROC_H + +#ifdef MSM_CAMERA_BIONIC +#include +#endif +#include +#include +#include + +/* Should be same as VIDEO_MAX_PLANES in videodev2.h */ +#define MAX_PLANES VIDEO_MAX_PLANES + +#define MAX_NUM_CPP_STRIPS 8 +#define MSM_CPP_MAX_NUM_PLANES 3 +#define MSM_CPP_MAX_FRAME_LENGTH 1024 +#define MSM_CPP_MAX_FW_NAME_LEN 32 +#define MAX_FREQ_TBL 10 + + +enum msm_cpp_frame_type { + MSM_CPP_OFFLINE_FRAME, + MSM_CPP_REALTIME_FRAME, +}; + +enum msm_vpe_frame_type { + MSM_VPE_OFFLINE_FRAME, + MSM_VPE_REALTIME_FRAME, +}; + +struct msm_cpp_frame_strip_info { + int scale_v_en; + int scale_h_en; + + int upscale_v_en; + int upscale_h_en; + + int src_start_x; + int src_end_x; + int src_start_y; + int src_end_y; + + /* Padding is required for upscaler because it does not + * pad internally like other blocks, also needed for rotation + * rotation expects all the blocks in the stripe to be the same size + * Padding is done such that all the extra padded pixels + * are on the right and bottom + */ + int pad_bottom; + int pad_top; + int pad_right; + int pad_left; + + int v_init_phase; + int h_init_phase; + int h_phase_step; + int v_phase_step; + + int prescale_crop_width_first_pixel; + int prescale_crop_width_last_pixel; + int prescale_crop_height_first_line; + int prescale_crop_height_last_line; + + int postscale_crop_height_first_line; + int postscale_crop_height_last_line; + int postscale_crop_width_first_pixel; + int postscale_crop_width_last_pixel; + + int dst_start_x; + int dst_end_x; + int dst_start_y; + int dst_end_y; + + int bytes_per_pixel; + unsigned int source_address; + unsigned int destination_address; + unsigned int compl_destination_address; + unsigned int src_stride; + unsigned int dst_stride; + int rotate_270; + int horizontal_flip; + int vertical_flip; + int scale_output_width; + int scale_output_height; + int prescale_crop_en; + int postscale_crop_en; +}; + +struct msm_cpp_buffer_info_t { + int fd; + uint32_t index; + uint32_t offset; + uint8_t native_buff; + uint8_t processed_divert; + uint32_t identity; +}; + +struct msm_cpp_stream_buff_info_t { + uint32_t identity; + uint32_t num_buffs; + struct msm_cpp_buffer_info_t *buffer_info; +}; + +struct msm_cpp_frame_info_t { + int32_t frame_id; + struct timeval timestamp; + uint32_t inst_id; + uint32_t identity; + uint32_t client_id; + enum msm_cpp_frame_type frame_type; + uint32_t num_strips; + struct msm_cpp_frame_strip_info *strip_info; + uint32_t msg_len; + uint32_t *cpp_cmd_msg; + int src_fd; + int dst_fd; + struct ion_handle *src_ion_handle; + struct ion_handle *dest_ion_handle; + struct timeval in_time, out_time; + void *cookie; + int32_t *status; + int32_t duplicate_output; + uint32_t duplicate_identity; + struct msm_cpp_buffer_info_t input_buffer_info; + struct msm_cpp_buffer_info_t output_buffer_info[2]; +}; + +struct cpp_hw_info { + uint32_t cpp_hw_version; + uint32_t cpp_hw_caps; + unsigned long freq_tbl[MAX_FREQ_TBL]; + uint32_t freq_tbl_count; +}; + +struct msm_vpe_frame_strip_info { + uint32_t src_w; + uint32_t src_h; + uint32_t dst_w; + uint32_t dst_h; + uint32_t src_x; + uint32_t src_y; + uint32_t phase_step_x; + uint32_t phase_step_y; + uint32_t phase_init_x; + uint32_t phase_init_y; +}; + +struct msm_vpe_buffer_info_t { + int fd; + uint32_t index; + uint32_t offset; + uint8_t native_buff; + uint8_t processed_divert; +}; + +struct msm_vpe_stream_buff_info_t { + uint32_t identity; + uint32_t num_buffs; + struct msm_vpe_buffer_info_t *buffer_info; +}; + +struct msm_vpe_frame_info_t { + int32_t frame_id; + struct timeval timestamp; + uint32_t inst_id; + uint32_t identity; + uint32_t client_id; + enum msm_vpe_frame_type frame_type; + struct msm_vpe_frame_strip_info strip_info; + int src_fd; + int dst_fd; + struct ion_handle *src_ion_handle; + struct ion_handle *dest_ion_handle; + unsigned long src_phyaddr; + unsigned long dest_phyaddr; + unsigned long src_chroma_plane_offset; + unsigned long dest_chroma_plane_offset; + struct timeval in_time, out_time; + void *cookie; + + struct msm_vpe_buffer_info_t input_buffer_info; + struct msm_vpe_buffer_info_t output_buffer_info; +}; + +struct msm_pproc_queue_buf_info { + struct msm_buf_mngr_info buff_mgr_info; + uint8_t is_buf_dirty; +}; + +#define VIDIOC_MSM_CPP_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_GET_INST_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_LOAD_FIRMWARE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_GET_HW_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_FLUSH_QUEUE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t) + + +#define VIDIOC_MSM_VPE_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_TRANSACTION_SETUP \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_GET_INST_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_QUEUE_BUF \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_SET_CLOCK \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_POP_STREAM_BUFFER \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_IOMMU_ATTACH \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_IOMMU_DETACH \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_camera_v4l2_ioctl_t) + +#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0) +#define V4L2_EVENT_VPE_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 1) + +struct msm_camera_v4l2_ioctl_t { + uint32_t id; + uint32_t len; + int32_t trans_code; + void __user *ioctl_ptr; +}; + +#ifdef CONFIG_COMPAT +struct msm_cpp_frame_info32_t { + int32_t frame_id; + struct compat_timeval timestamp; + uint32_t inst_id; + uint32_t identity; + uint32_t client_id; + enum msm_cpp_frame_type frame_type; + uint32_t num_strips; + compat_caddr_t strip_info; + uint32_t msg_len; + compat_uint_t cpp_cmd_msg; + int src_fd; + int dst_fd; + struct compat_timeval in_time, out_time; + compat_caddr_t cookie; + compat_int_t status; + int32_t duplicate_output; + uint32_t duplicate_identity; + struct msm_cpp_buffer_info_t input_buffer_info; + struct msm_cpp_buffer_info_t output_buffer_info[2]; + struct msm_cpp_buffer_info_t tnr_scratch_buffer_info[2]; +}; + +struct msm_cpp_stream_buff_info32_t { + uint32_t identity; + uint32_t num_buffs; + compat_caddr_t buffer_info; +}; + +struct msm_pproc_queue_buf_info32_t { + struct msm_buf_mngr_info32_t buff_mgr_info; + uint8_t is_buf_dirty; +}; + +#define VIDIOC_MSM_CPP_CFG32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_GET_EVENTPAYLOAD32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_GET_INST_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_LOAD_FIRMWARE32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_GET_HW_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_FLUSH_QUEUE32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_CFG32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_TRANSACTION_SETUP32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_GET_INST_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_QUEUE_BUF32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_SET_CLOCK32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_POP_STREAM_BUFFER32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_IOMMU_ATTACH32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_camera_v4l2_ioctl32_t) + +#define VIDIOC_MSM_CPP_IOMMU_DETACH32 \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_camera_v4l2_ioctl32_t) + +struct msm_camera_v4l2_ioctl32_t { + uint32_t id; + uint32_t len; + int32_t trans_code; + compat_caddr_t ioctl_ptr; +}; +#endif + +#endif /* __MSMB_PPROC_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/include/soc/qcom/camera2.h b/drivers/media/platform/msm/camera_v2_j5/include/soc/qcom/camera2.h new file mode 100644 index 0000000000000000000000000000000000000000..371fec8c135942781cea69e4e7c81c66e41b1e50 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/soc/qcom/camera2.h @@ -0,0 +1,164 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + * + */ + +#ifndef __CAMERA2_H__ +#define __CAMERA2_H__ + +#include "../../../include/media/msm_cam_sensor.h" +#include + +enum msm_camera_device_type_t { + MSM_CAMERA_I2C_DEVICE, + MSM_CAMERA_PLATFORM_DEVICE, + MSM_CAMERA_SPI_DEVICE, +}; + +enum msm_bus_perf_setting { + S_INIT, + S_PREVIEW, + S_VIDEO, + S_CAPTURE, + S_ZSL, + S_STEREO_VIDEO, + S_STEREO_CAPTURE, + S_DEFAULT, + S_LIVESHOT, + S_DUAL, + S_EXIT +}; + +struct msm_camera_slave_info { + uint16_t sensor_slave_addr; + uint16_t sensor_id_reg_addr; + uint16_t sensor_id; +}; + +struct msm_cam_clk_info { + const char *clk_name; + long clk_rate; + uint32_t delay; +}; + +struct msm_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + bool use_pinctrl; +}; + +struct msm_cam_clk_setting { + struct msm_cam_clk_info *clk_info; + uint16_t num_clk_info; + uint8_t enable; +}; + +struct v4l2_subdev_info { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + uint16_t fmt; + uint16_t order; +}; + +struct msm_camera_power_ctrl_t { + struct device *dev; + struct msm_sensor_power_setting *power_setting; + uint16_t power_setting_size; + struct msm_sensor_power_setting *power_down_setting; + uint16_t power_down_setting_size; + struct msm_camera_gpio_conf *gpio_conf; + struct camera_vreg_t *cam_vreg; + int num_vreg; + struct msm_camera_i2c_conf *i2c_conf; + struct msm_cam_clk_info *clk_info; + struct msm_pinctrl_info pinctrl_info; + uint8_t cam_pinctrl_status; + uint16_t clk_info_size; +}; + +struct msm_camera_sensor_board_info { + const char *sensor_name; + const char *eeprom_name; + const char *actuator_name; + struct msm_camera_slave_info *slave_info; + struct msm_camera_csi_lane_params *csi_lane_params; + struct msm_camera_sensor_strobe_flash_data *strobe_flash_data; + struct msm_actuator_info *actuator_info; + struct msm_sensor_info_t *sensor_info; + const char *misc_regulator; + struct msm_camera_power_ctrl_t power_info; + struct msm_camera_sensor_slave_info *cam_slave_info; +}; + +enum msm_camera_i2c_cmd_type { + MSM_CAMERA_I2C_CMD_WRITE, + MSM_CAMERA_I2C_CMD_POLL, +}; + +struct msm_camera_i2c_reg_conf { + uint16_t reg_addr; + uint16_t reg_data; + enum msm_camera_i2c_data_type dt; + enum msm_camera_i2c_cmd_type cmd_type; + int16_t mask; +}; + +struct msm_camera_i2c_conf_array { + struct msm_camera_i2c_reg_conf *conf; + uint16_t size; + uint16_t delay; + enum msm_camera_i2c_data_type data_type; +}; + +struct eeprom_map_t { + uint32_t valid_size; + uint32_t addr; + uint32_t addr_t; + uint32_t data; + uint32_t data_t; + uint32_t delay; +}; + +struct eeprom_slave_add_t { + uint32_t addr; +}; + +struct msm_eeprom_memory_map_t { + struct eeprom_map_t page; + struct eeprom_map_t pageen; + struct eeprom_map_t poll; + struct eeprom_map_t mem; + struct eeprom_slave_add_t saddr; +}; + +struct msm_eeprom_memory_block_t { + struct msm_eeprom_memory_map_t *map; + uint32_t num_map; /* number of map blocks */ + uint8_t *mapdata; + uint32_t num_data; /* size of total mapdata */ +}; + +struct msm_eeprom_cmm_t { + uint32_t cmm_support; + uint32_t cmm_compression; + uint32_t cmm_offset; + uint32_t cmm_size; +}; + +struct msm_eeprom_board_info { + const char *eeprom_name; + uint16_t i2c_slaveaddr; + struct msm_camera_power_ctrl_t power_info; + struct msm_eeprom_cmm_t cmm_data; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/include/uapi/media/msm_camera.h b/drivers/media/platform/msm/camera_v2_j5/include/uapi/media/msm_camera.h new file mode 100644 index 0000000000000000000000000000000000000000..458e1baf8e3a649623ed6867386cdfc8a57c474b --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/include/uapi/media/msm_camera.h @@ -0,0 +1,2280 @@ +/* Copyright (c) 2009-2012, 2014, The Linux Foundation. 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 and + * only 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. + * + */ +#ifndef __UAPI_MSM_CAMERA_H +#define __UAPI_MSM_CAMERA_H + +#ifdef MSM_CAMERA_BIONIC +#include +#endif +#include +#include +#include +#ifdef MSM_CAMERA_GCC +#include +#else +#include +#endif + +#include + +#define BIT(nr) (1UL << (nr)) + +#define MSM_CAM_IOCTL_MAGIC 'm' + +#define MAX_SERVER_PAYLOAD_LENGTH 8192 + +#define MSM_CAM_IOCTL_GET_SENSOR_INFO \ + _IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *) + +#define MSM_CAM_IOCTL_REGISTER_PMEM \ + _IOW(MSM_CAM_IOCTL_MAGIC, 2, struct msm_pmem_info *) + +#define MSM_CAM_IOCTL_UNREGISTER_PMEM \ + _IOW(MSM_CAM_IOCTL_MAGIC, 3, unsigned) + +#define MSM_CAM_IOCTL_CTRL_COMMAND \ + _IOW(MSM_CAM_IOCTL_MAGIC, 4, struct msm_ctrl_cmd *) + +#define MSM_CAM_IOCTL_CONFIG_VFE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 5, struct msm_camera_vfe_cfg_cmd *) + +#define MSM_CAM_IOCTL_GET_STATS \ + _IOR(MSM_CAM_IOCTL_MAGIC, 6, struct msm_camera_stats_event_ctrl *) + +#define MSM_CAM_IOCTL_GETFRAME \ + _IOR(MSM_CAM_IOCTL_MAGIC, 7, struct msm_camera_get_frame *) + +#define MSM_CAM_IOCTL_ENABLE_VFE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 8, struct camera_enable_cmd *) + +#define MSM_CAM_IOCTL_CTRL_CMD_DONE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 9, struct camera_cmd *) + +#define MSM_CAM_IOCTL_CONFIG_CMD \ + _IOW(MSM_CAM_IOCTL_MAGIC, 10, struct camera_cmd *) + +#define MSM_CAM_IOCTL_DISABLE_VFE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 11, struct camera_enable_cmd *) + +#define MSM_CAM_IOCTL_PAD_REG_RESET2 \ + _IOW(MSM_CAM_IOCTL_MAGIC, 12, struct camera_enable_cmd *) + +#define MSM_CAM_IOCTL_VFE_APPS_RESET \ + _IOW(MSM_CAM_IOCTL_MAGIC, 13, struct camera_enable_cmd *) + +#define MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER \ + _IOW(MSM_CAM_IOCTL_MAGIC, 14, struct camera_enable_cmd *) + +#define MSM_CAM_IOCTL_RELEASE_STATS_BUFFER \ + _IOW(MSM_CAM_IOCTL_MAGIC, 15, struct msm_stats_buf *) + +#define MSM_CAM_IOCTL_AXI_CONFIG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 16, struct msm_camera_vfe_cfg_cmd *) + +#define MSM_CAM_IOCTL_GET_PICTURE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 17, struct msm_frame *) + +#define MSM_CAM_IOCTL_SET_CROP \ + _IOW(MSM_CAM_IOCTL_MAGIC, 18, struct crop_info *) + +#define MSM_CAM_IOCTL_PICT_PP \ + _IOW(MSM_CAM_IOCTL_MAGIC, 19, uint8_t *) + +#define MSM_CAM_IOCTL_PICT_PP_DONE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 20, struct msm_snapshot_pp_status *) + +#define MSM_CAM_IOCTL_SENSOR_IO_CFG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 21, struct sensor_cfg_data *) + +#define MSM_CAM_IOCTL_FLASH_LED_CFG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 22, unsigned *) + +#define MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME \ + _IO(MSM_CAM_IOCTL_MAGIC, 23) + +#define MSM_CAM_IOCTL_CTRL_COMMAND_2 \ + _IOW(MSM_CAM_IOCTL_MAGIC, 24, struct msm_ctrl_cmd *) + +#define MSM_CAM_IOCTL_AF_CTRL \ + _IOR(MSM_CAM_IOCTL_MAGIC, 25, struct msm_ctrl_cmt_t *) + +#define MSM_CAM_IOCTL_AF_CTRL_DONE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 26, struct msm_ctrl_cmt_t *) + +#define MSM_CAM_IOCTL_CONFIG_VPE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 27, struct msm_camera_vpe_cfg_cmd *) + +#define MSM_CAM_IOCTL_AXI_VPE_CONFIG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 28, struct msm_camera_vpe_cfg_cmd *) + +#define MSM_CAM_IOCTL_STROBE_FLASH_CFG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 29, uint32_t *) + +#define MSM_CAM_IOCTL_STROBE_FLASH_CHARGE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 30, uint32_t *) + +#define MSM_CAM_IOCTL_STROBE_FLASH_RELEASE \ + _IO(MSM_CAM_IOCTL_MAGIC, 31) + +#define MSM_CAM_IOCTL_FLASH_CTRL \ + _IOW(MSM_CAM_IOCTL_MAGIC, 32, struct flash_ctrl_data *) + +#define MSM_CAM_IOCTL_ERROR_CONFIG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 33, uint32_t *) + +#define MSM_CAM_IOCTL_ABORT_CAPTURE \ + _IO(MSM_CAM_IOCTL_MAGIC, 34) + +#define MSM_CAM_IOCTL_SET_FD_ROI \ + _IOW(MSM_CAM_IOCTL_MAGIC, 35, struct fd_roi_info *) + +#define MSM_CAM_IOCTL_GET_CAMERA_INFO \ + _IOR(MSM_CAM_IOCTL_MAGIC, 36, struct msm_camera_info *) + +#define MSM_CAM_IOCTL_UNBLOCK_POLL_PIC_FRAME \ + _IO(MSM_CAM_IOCTL_MAGIC, 37) + +#define MSM_CAM_IOCTL_RELEASE_PIC_BUFFER \ + _IOW(MSM_CAM_IOCTL_MAGIC, 38, struct camera_enable_cmd *) + +#define MSM_CAM_IOCTL_PUT_ST_FRAME \ + _IOW(MSM_CAM_IOCTL_MAGIC, 39, struct msm_camera_st_frame *) + +#define MSM_CAM_IOCTL_V4L2_EVT_NOTIFY \ + _IOW(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event_and_payload) + +#define MSM_CAM_IOCTL_SET_MEM_MAP_INFO \ + _IOR(MSM_CAM_IOCTL_MAGIC, 41, struct msm_mem_map_info *) + +#define MSM_CAM_IOCTL_ACTUATOR_IO_CFG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 42, struct msm_actuator_cfg_data *) + +#define MSM_CAM_IOCTL_MCTL_POST_PROC \ + _IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_mctl_post_proc_cmd *) + +#define MSM_CAM_IOCTL_RESERVE_FREE_FRAME \ + _IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_cam_evt_divert_frame *) + +#define MSM_CAM_IOCTL_RELEASE_FREE_FRAME \ + _IOR(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *) + +#define MSM_CAM_IOCTL_PICT_PP_DIVERT_DONE \ + _IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_pp_frame *) + +#define MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL \ + _IOR(MSM_CAM_IOCTL_MAGIC, 47, struct v4l2_control) + +#define MSM_CAM_IOCTL_SENSOR_V4l2_QUERY_CTRL \ + _IOR(MSM_CAM_IOCTL_MAGIC, 48, struct v4l2_queryctrl) + +#define MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME \ + _IOW(MSM_CAM_IOCTL_MAGIC, 49, struct timeval *) + +#define MSM_CAM_IOCTL_SET_VFE_OUTPUT_TYPE \ + _IOW(MSM_CAM_IOCTL_MAGIC, 50, uint32_t *) + +#define MSM_CAM_IOCTL_MCTL_DIVERT_DONE \ + _IOR(MSM_CAM_IOCTL_MAGIC, 51, struct msm_cam_evt_divert_frame *) + +#define MSM_CAM_IOCTL_GET_ACTUATOR_INFO \ + _IOW(MSM_CAM_IOCTL_MAGIC, 52, struct msm_actuator_cfg_data *) + +#define MSM_CAM_IOCTL_EEPROM_IO_CFG \ + _IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *) + +#define MSM_CAM_IOCTL_ISPIF_IO_CFG \ + _IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *) + +#define MSM_CAM_IOCTL_STATS_REQBUF \ + _IOR(MSM_CAM_IOCTL_MAGIC, 55, struct msm_stats_reqbuf *) + +#define MSM_CAM_IOCTL_STATS_ENQUEUEBUF \ + _IOR(MSM_CAM_IOCTL_MAGIC, 56, struct msm_stats_buf_info *) + +#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \ + _IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *) + +#define MSM_CAM_IOCTL_SET_MCTL_SDEV \ + _IOW(MSM_CAM_IOCTL_MAGIC, 58, struct msm_mctl_set_sdev_data *) + +#define MSM_CAM_IOCTL_UNSET_MCTL_SDEV \ + _IOW(MSM_CAM_IOCTL_MAGIC, 59, struct msm_mctl_set_sdev_data *) + +#define MSM_CAM_IOCTL_GET_INST_HANDLE \ + _IOR(MSM_CAM_IOCTL_MAGIC, 60, uint32_t *) + +#define MSM_CAM_IOCTL_STATS_UNREG_BUF \ + _IOR(MSM_CAM_IOCTL_MAGIC, 61, struct msm_stats_flush_bufq *) + +#define MSM_CAM_IOCTL_CSIC_IO_CFG \ + _IOWR(MSM_CAM_IOCTL_MAGIC, 62, struct csic_cfg_data *) + +#define MSM_CAM_IOCTL_CSID_IO_CFG \ + _IOWR(MSM_CAM_IOCTL_MAGIC, 63, struct csid_cfg_data *) + +#define MSM_CAM_IOCTL_CSIPHY_IO_CFG \ + _IOR(MSM_CAM_IOCTL_MAGIC, 64, struct csiphy_cfg_data *) + +#define MSM_CAM_IOCTL_OEM \ + _IOW(MSM_CAM_IOCTL_MAGIC, 65, struct sensor_cfg_data *) + +#define MSM_CAM_IOCTL_AXI_INIT \ + _IOWR(MSM_CAM_IOCTL_MAGIC, 66, uint8_t *) + +#define MSM_CAM_IOCTL_AXI_RELEASE \ + _IO(MSM_CAM_IOCTL_MAGIC, 67) + +struct v4l2_event_and_payload { + struct v4l2_event evt; + uint32_t payload_length; + uint32_t transaction_id; + void *payload; +}; + +struct msm_stats_reqbuf { + int num_buf; /* how many buffers requested */ + int stats_type; /* stats type */ +}; + +struct msm_stats_flush_bufq { + int stats_type; /* enum msm_stats_enum_type */ +}; + +struct msm_mctl_pp_cmd { + int32_t id; + uint16_t length; + void *value; +}; + +struct msm_mctl_post_proc_cmd { + int32_t type; + struct msm_mctl_pp_cmd cmd; +}; + +#define MSM_CAMERA_LED_OFF 0 +#define MSM_CAMERA_LED_LOW 1 +#define MSM_CAMERA_LED_HIGH 2 +#define MSM_CAMERA_LED_INIT 3 +#define MSM_CAMERA_LED_RELEASE 4 + +#define MSM_CAMERA_STROBE_FLASH_NONE 0 +#define MSM_CAMERA_STROBE_FLASH_XENON 1 + +#define MSM_MAX_CAMERA_SENSORS 5 +#define MAX_SENSOR_NAME 32 +#define MAX_CAM_NAME_SIZE 32 +#define MAX_ACT_MOD_NAME_SIZE 32 +#define MAX_ACT_NAME_SIZE 32 +#define NUM_ACTUATOR_DIR 2 +#define MAX_ACTUATOR_SCENARIO 8 +#define MAX_ACTUATOR_REGION 5 +#define MAX_ACTUATOR_INIT_SET 12 +#define MAX_ACTUATOR_TYPE_SIZE 32 +#define MAX_ACTUATOR_REG_TBL_SIZE 8 + + +#define MSM_MAX_CAMERA_CONFIGS 2 + +#define PP_SNAP 0x01 +#define PP_RAW_SNAP ((0x01)<<1) +#define PP_PREV ((0x01)<<2) +#define PP_THUMB ((0x01)<<3) +#define PP_MASK (PP_SNAP|PP_RAW_SNAP|PP_PREV|PP_THUMB) + +#define MSM_CAM_CTRL_CMD_DONE 0 +#define MSM_CAM_SENSOR_VFE_CMD 1 + +/* Should be same as VIDEO_MAX_PLANES in videodev2.h */ +#define MAX_PLANES 8 + +/***************************************************** + * structure + *****************************************************/ + +/* define five type of structures for userspace <==> kernel + * space communication: + * command 1 - 2 are from userspace ==> kernel + * command 3 - 4 are from kernel ==> userspace + * + * 1. control command: control command(from control thread), + * control status (from config thread); + */ +struct msm_ctrl_cmd { + uint16_t type; + uint16_t length; + void *value; + uint16_t status; + uint32_t timeout_ms; + int resp_fd; /* FIXME: to be used by the kernel, pass-through for now */ + int vnode_id; /* video dev id. Can we overload resp_fd? */ + int queue_idx; + uint32_t evt_id; + uint32_t stream_type; /* used to pass value to qcamera server */ + int config_ident; /*used as identifier for config node*/ +}; + +struct msm_cam_evt_msg { + unsigned short type; /* 1 == event (RPC), 0 == message (adsp) */ + unsigned short msg_id; + unsigned int len; /* size in, number of bytes out */ + uint32_t frame_id; + void *data; + struct timespec timestamp; +}; + +struct msm_pp_frame_sp { + /* phy addr of the buffer */ + unsigned long phy_addr; + uint32_t y_off; + uint32_t cbcr_off; + /* buffer length */ + uint32_t length; + int32_t fd; + uint32_t addr_offset; + /* mapped addr */ + unsigned long vaddr; +}; + +struct msm_pp_frame_mp { + /* phy addr of the plane */ + unsigned long phy_addr; + /* offset of plane data */ + uint32_t data_offset; + /* plane length */ + uint32_t length; + int32_t fd; + uint32_t addr_offset; + /* mapped addr */ + unsigned long vaddr; +}; + +struct msm_pp_frame { + uint32_t handle; /* stores vb cookie */ + uint32_t frame_id; + unsigned short buf_idx; + int path; + unsigned short image_type; + unsigned short num_planes; /* 1 for sp */ + struct timeval timestamp; + union { + struct msm_pp_frame_sp sp; + struct msm_pp_frame_mp mp[MAX_PLANES]; + }; + int node_type; + uint32_t inst_handle; +}; + +struct msm_pp_crop { + uint32_t src_x; + uint32_t src_y; + uint32_t src_w; + uint32_t src_h; + uint32_t dst_x; + uint32_t dst_y; + uint32_t dst_w; + uint32_t dst_h; + uint8_t update_flag; +}; + +struct msm_mctl_pp_frame_cmd { + uint32_t cookie; + uint8_t vpe_output_action; + struct msm_pp_frame src_frame; + struct msm_pp_frame dest_frame; + struct msm_pp_crop crop; + int path; +}; + +struct msm_cam_evt_divert_frame { + unsigned short image_mode; + unsigned short op_mode; + unsigned short inst_idx; + unsigned short node_idx; + struct msm_pp_frame frame; + int do_pp; +}; + +struct msm_mctl_pp_cmd_ack_event { + uint32_t cmd; /* VPE_CMD_ZOOM? */ + int status; /* 0 done, < 0 err */ + uint32_t cookie; /* daemon's cookie */ +}; + +struct msm_mctl_pp_event_info { + int32_t event; + union { + struct msm_mctl_pp_cmd_ack_event ack; + }; +}; + +struct msm_isp_event_ctrl { + unsigned short resptype; + union { + struct msm_cam_evt_msg isp_msg; + struct msm_ctrl_cmd ctrl; + struct msm_cam_evt_divert_frame div_frame; + struct msm_mctl_pp_event_info pp_event_info; + } isp_data; +}; + +#define MSM_CAM_RESP_CTRL 0 +#define MSM_CAM_RESP_STAT_EVT_MSG 1 +#define MSM_CAM_RESP_STEREO_OP_1 2 +#define MSM_CAM_RESP_STEREO_OP_2 3 +#define MSM_CAM_RESP_V4L2 4 +#define MSM_CAM_RESP_DIV_FRAME_EVT_MSG 5 +#define MSM_CAM_RESP_DONE_EVENT 6 +#define MSM_CAM_RESP_MCTL_PP_EVENT 7 +#define MSM_CAM_RESP_MAX 8 + +#define MSM_CAM_APP_NOTIFY_EVENT 0 +#define MSM_CAM_APP_NOTIFY_ERROR_EVENT 1 + +/* this one is used to send ctrl/status up to config thread */ + +struct msm_stats_event_ctrl { + /* 0 - ctrl_cmd from control thread, + * 1 - stats/event kernel, + * 2 - V4L control or read request */ + int resptype; + int timeout_ms; + struct msm_ctrl_cmd ctrl_cmd; + /* struct vfe_event_t stats_event; */ + struct msm_cam_evt_msg stats_event; +}; + +/* 2. config command: config command(from config thread); */ +struct msm_camera_cfg_cmd { + /* what to config: + * 1 - sensor config, 2 - vfe config */ + uint16_t cfg_type; + + /* sensor config type */ + uint16_t cmd_type; + uint16_t queue; + uint16_t length; + void *value; +}; + +#define CMD_GENERAL 0 +#define CMD_AXI_CFG_OUT1 1 +#define CMD_AXI_CFG_SNAP_O1_AND_O2 2 +#define CMD_AXI_CFG_OUT2 3 +#define CMD_PICT_T_AXI_CFG 4 +#define CMD_PICT_M_AXI_CFG 5 +#define CMD_RAW_PICT_AXI_CFG 6 + +#define CMD_FRAME_BUF_RELEASE 7 +#define CMD_PREV_BUF_CFG 8 +#define CMD_SNAP_BUF_RELEASE 9 +#define CMD_SNAP_BUF_CFG 10 +#define CMD_STATS_DISABLE 11 +#define CMD_STATS_AEC_AWB_ENABLE 12 +#define CMD_STATS_AF_ENABLE 13 +#define CMD_STATS_AEC_ENABLE 14 +#define CMD_STATS_AWB_ENABLE 15 +#define CMD_STATS_ENABLE 16 + +#define CMD_STATS_AXI_CFG 17 +#define CMD_STATS_AEC_AXI_CFG 18 +#define CMD_STATS_AF_AXI_CFG 19 +#define CMD_STATS_AWB_AXI_CFG 20 +#define CMD_STATS_RS_AXI_CFG 21 +#define CMD_STATS_CS_AXI_CFG 22 +#define CMD_STATS_IHIST_AXI_CFG 23 +#define CMD_STATS_SKIN_AXI_CFG 24 + +#define CMD_STATS_BUF_RELEASE 25 +#define CMD_STATS_AEC_BUF_RELEASE 26 +#define CMD_STATS_AF_BUF_RELEASE 27 +#define CMD_STATS_AWB_BUF_RELEASE 28 +#define CMD_STATS_RS_BUF_RELEASE 29 +#define CMD_STATS_CS_BUF_RELEASE 30 +#define CMD_STATS_IHIST_BUF_RELEASE 31 +#define CMD_STATS_SKIN_BUF_RELEASE 32 + +#define UPDATE_STATS_INVALID 33 +#define CMD_AXI_CFG_SNAP_GEMINI 34 +#define CMD_AXI_CFG_SNAP 35 +#define CMD_AXI_CFG_PREVIEW 36 +#define CMD_AXI_CFG_VIDEO 37 + +#define CMD_STATS_IHIST_ENABLE 38 +#define CMD_STATS_RS_ENABLE 39 +#define CMD_STATS_CS_ENABLE 40 +#define CMD_VPE 41 +#define CMD_AXI_CFG_VPE 42 +#define CMD_AXI_CFG_ZSL 43 +#define CMD_AXI_CFG_SNAP_VPE 44 +#define CMD_AXI_CFG_SNAP_THUMB_VPE 45 + +#define CMD_CONFIG_PING_ADDR 46 +#define CMD_CONFIG_PONG_ADDR 47 +#define CMD_CONFIG_FREE_BUF_ADDR 48 +#define CMD_AXI_CFG_ZSL_ALL_CHNLS 49 +#define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50 +#define CMD_VFE_BUFFER_RELEASE 51 +#define CMD_VFE_PROCESS_IRQ 52 +#define CMD_STATS_BG_ENABLE 53 +#define CMD_STATS_BF_ENABLE 54 +#define CMD_STATS_BHIST_ENABLE 55 +#define CMD_STATS_BG_BUF_RELEASE 56 +#define CMD_STATS_BF_BUF_RELEASE 57 +#define CMD_STATS_BHIST_BUF_RELEASE 58 +#define CMD_VFE_PIX_SOF_COUNT_UPDATE 59 +#define CMD_VFE_COUNT_PIX_SOF_ENABLE 60 +#define CMD_STATS_BE_ENABLE 61 +#define CMD_STATS_BE_BUF_RELEASE 62 + +#define CMD_AXI_CFG_PRIM BIT(8) +#define CMD_AXI_CFG_PRIM_ALL_CHNLS BIT(9) +#define CMD_AXI_CFG_SEC BIT(10) +#define CMD_AXI_CFG_SEC_ALL_CHNLS BIT(11) +#define CMD_AXI_CFG_TERT1 BIT(12) +#define CMD_AXI_CFG_TERT2 BIT(13) + +#define CMD_AXI_START 0xE1 +#define CMD_AXI_STOP 0xE2 +#define CMD_AXI_RESET 0xE3 +#define CMD_AXI_ABORT 0xE4 + + + +#define AXI_CMD_PREVIEW BIT(0) +#define AXI_CMD_CAPTURE BIT(1) +#define AXI_CMD_RECORD BIT(2) +#define AXI_CMD_ZSL BIT(3) +#define AXI_CMD_RAW_CAPTURE BIT(4) +#define AXI_CMD_LIVESHOT BIT(5) + +/* vfe config command: config command(from config thread)*/ +struct msm_vfe_cfg_cmd { + int cmd_type; + uint16_t length; + void *value; +}; + +struct msm_vpe_cfg_cmd { + int cmd_type; + uint16_t length; + void *value; +}; + +#define MAX_CAMERA_ENABLE_NAME_LEN 32 +struct camera_enable_cmd { + char name[MAX_CAMERA_ENABLE_NAME_LEN]; +}; + +#define MSM_PMEM_OUTPUT1 0 +#define MSM_PMEM_OUTPUT2 1 +#define MSM_PMEM_OUTPUT1_OUTPUT2 2 +#define MSM_PMEM_THUMBNAIL 3 +#define MSM_PMEM_MAINIMG 4 +#define MSM_PMEM_RAW_MAINIMG 5 +#define MSM_PMEM_AEC_AWB 6 +#define MSM_PMEM_AF 7 +#define MSM_PMEM_AEC 8 +#define MSM_PMEM_AWB 9 +#define MSM_PMEM_RS 10 +#define MSM_PMEM_CS 11 +#define MSM_PMEM_IHIST 12 +#define MSM_PMEM_SKIN 13 +#define MSM_PMEM_VIDEO 14 +#define MSM_PMEM_PREVIEW 15 +#define MSM_PMEM_VIDEO_VPE 16 +#define MSM_PMEM_C2D 17 +#define MSM_PMEM_MAINIMG_VPE 18 +#define MSM_PMEM_THUMBNAIL_VPE 19 +#define MSM_PMEM_BAYER_GRID 20 +#define MSM_PMEM_BAYER_FOCUS 21 +#define MSM_PMEM_BAYER_HIST 22 +#define MSM_PMEM_BAYER_EXPOSURE 23 +#define MSM_PMEM_MAX 24 + +#define STAT_AEAW 0 +#define STAT_AEC 1 +#define STAT_AF 2 +#define STAT_AWB 3 +#define STAT_RS 4 +#define STAT_CS 5 +#define STAT_IHIST 6 +#define STAT_SKIN 7 +#define STAT_BG 8 +#define STAT_BF 9 +#define STAT_BE 10 +#define STAT_BHIST 11 +#define STAT_MAX 12 + +#define FRAME_PREVIEW_OUTPUT1 0 +#define FRAME_PREVIEW_OUTPUT2 1 +#define FRAME_SNAPSHOT 2 +#define FRAME_THUMBNAIL 3 +#define FRAME_RAW_SNAPSHOT 4 +#define FRAME_MAX 5 + +enum msm_stats_enum_type { + MSM_STATS_TYPE_AEC, /* legacy based AEC */ + MSM_STATS_TYPE_AF, /* legacy based AF */ + MSM_STATS_TYPE_AWB, /* legacy based AWB */ + MSM_STATS_TYPE_RS, /* legacy based RS */ + MSM_STATS_TYPE_CS, /* legacy based CS */ + MSM_STATS_TYPE_IHIST, /* legacy based HIST */ + MSM_STATS_TYPE_SKIN, /* legacy based SKIN */ + MSM_STATS_TYPE_BG, /* Bayer Grids */ + MSM_STATS_TYPE_BF, /* Bayer Focus */ + MSM_STATS_TYPE_BE, /* Bayer Exposure*/ + MSM_STATS_TYPE_BHIST, /* Bayer Hist */ + MSM_STATS_TYPE_AE_AW, /* legacy stats for vfe 2.x*/ + MSM_STATS_TYPE_COMP, /* Composite stats */ + MSM_STATS_TYPE_MAX /* MAX */ +}; + +struct msm_stats_buf_info { + int type; /* msm_stats_enum_type */ + int fd; + void *vaddr; + uint32_t offset; + uint32_t len; + uint32_t y_off; + uint32_t cbcr_off; + uint32_t planar0_off; + uint32_t planar1_off; + uint32_t planar2_off; + uint8_t active; + int buf_idx; +}; + +struct msm_pmem_info { + int type; + int fd; + void *vaddr; + uint32_t offset; + uint32_t len; + uint32_t y_off; + uint32_t cbcr_off; + uint32_t planar0_off; + uint32_t planar1_off; + uint32_t planar2_off; + uint8_t active; +}; + +struct outputCfg { + uint32_t height; + uint32_t width; + + uint32_t window_height_firstline; + uint32_t window_height_lastline; +}; + +#define VIDEO_NODE 0 +#define MCTL_NODE 1 + +#define OUTPUT_1 0 +#define OUTPUT_2 1 +#define OUTPUT_1_AND_2 2 /* snapshot only */ +#define OUTPUT_1_AND_3 3 /* video */ +#define CAMIF_TO_AXI_VIA_OUTPUT_2 4 +#define OUTPUT_1_AND_CAMIF_TO_AXI_VIA_OUTPUT_2 5 +#define OUTPUT_2_AND_CAMIF_TO_AXI_VIA_OUTPUT_1 6 +#define OUTPUT_1_2_AND_3 7 +#define OUTPUT_ALL_CHNLS 8 +#define OUTPUT_VIDEO_ALL_CHNLS 9 +#define OUTPUT_ZSL_ALL_CHNLS 10 +#define LAST_AXI_OUTPUT_MODE_ENUM = OUTPUT_ZSL_ALL_CHNLS + +#define OUTPUT_PRIM BIT(8) +#define OUTPUT_PRIM_ALL_CHNLS BIT(9) +#define OUTPUT_SEC BIT(10) +#define OUTPUT_SEC_ALL_CHNLS BIT(11) +#define OUTPUT_TERT1 BIT(12) +#define OUTPUT_TERT2 BIT(13) + + + +#define MSM_FRAME_PREV_1 0 +#define MSM_FRAME_PREV_2 1 +#define MSM_FRAME_ENC 2 + +#define OUTPUT_TYPE_P BIT(0) +#define OUTPUT_TYPE_T BIT(1) +#define OUTPUT_TYPE_S BIT(2) +#define OUTPUT_TYPE_V BIT(3) +#define OUTPUT_TYPE_L BIT(4) +#define OUTPUT_TYPE_ST_L BIT(5) +#define OUTPUT_TYPE_ST_R BIT(6) +#define OUTPUT_TYPE_ST_D BIT(7) +#define OUTPUT_TYPE_R BIT(8) +#define OUTPUT_TYPE_R1 BIT(9) +#define OUTPUT_TYPE_SAEC BIT(10) +#define OUTPUT_TYPE_SAFC BIT(11) +#define OUTPUT_TYPE_SAWB BIT(12) +#define OUTPUT_TYPE_IHST BIT(13) +#define OUTPUT_TYPE_CSTA BIT(14) + +struct fd_roi_info { + void *info; + int info_len; +}; + +struct msm_mem_map_info { + uint32_t cookie; + uint32_t length; + uint32_t mem_type; +}; + +#define MSM_MEM_MMAP 0 +#define MSM_MEM_USERPTR 1 +#define MSM_PLANE_MAX 8 +#define MSM_PLANE_Y 0 +#define MSM_PLANE_UV 1 + +struct msm_frame { + struct timespec ts; + int path; + int type; + unsigned long buffer; + uint32_t phy_offset; + uint32_t y_off; + uint32_t cbcr_off; + uint32_t planar0_off; + uint32_t planar1_off; + uint32_t planar2_off; + int fd; + + void *cropinfo; + int croplen; + uint32_t error_code; + struct fd_roi_info roi_info; + uint32_t frame_id; + int stcam_quality_ind; + uint32_t stcam_conv_value; + + struct ion_allocation_data ion_alloc; + struct ion_fd_data fd_data; + int ion_dev_fd; +}; + +enum msm_st_frame_packing { + SIDE_BY_SIDE_HALF, + SIDE_BY_SIDE_FULL, + TOP_DOWN_HALF, + TOP_DOWN_FULL, +}; + +struct msm_st_crop { + uint32_t in_w; + uint32_t in_h; + uint32_t out_w; + uint32_t out_h; +}; + +struct msm_st_half { + uint32_t buf_p0_off; + uint32_t buf_p1_off; + uint32_t buf_p0_stride; + uint32_t buf_p1_stride; + uint32_t pix_x_off; + uint32_t pix_y_off; + struct msm_st_crop stCropInfo; +}; + +struct msm_st_frame { + struct msm_frame buf_info; + int type; + enum msm_st_frame_packing packing; + struct msm_st_half L; + struct msm_st_half R; + int frame_id; +}; + +#define MSM_CAMERA_ERR_MASK (0xFFFFFFFF & 1) + +struct stats_buff { + unsigned long buff; + int fd; +}; + +struct msm_stats_buf { + uint8_t awb_ymin; + struct stats_buff aec; + struct stats_buff awb; + struct stats_buff af; + struct stats_buff be; + struct stats_buff ihist; + struct stats_buff rs; + struct stats_buff cs; + struct stats_buff skin; + int type; + uint32_t status_bits; + unsigned long buffer; + int fd; + int length; + struct ion_handle *handle; + uint32_t frame_id; + int buf_idx; +}; +#define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0 +/* video capture mode in VIDIOC_S_PARM */ +#define MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+1) +/* extendedmode for video recording in VIDIOC_S_PARM */ +#define MSM_V4L2_EXT_CAPTURE_MODE_VIDEO \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+2) +/* extendedmode for the full size main image in VIDIOC_S_PARM */ +#define MSM_V4L2_EXT_CAPTURE_MODE_MAIN (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+3) +/* extendedmode for the thumb nail image in VIDIOC_S_PARM */ +#define MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+4) +/* ISP_PIX_OUTPUT1: no pp, directly send output1 buf to user */ +#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT1 \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+5) +/* ISP_PIX_OUTPUT2: no pp, directly send output2 buf to user */ +#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT2 \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+6) +/* raw image type */ +#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+7) +/* RDI dump */ +#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+8) +/* RDI dump 1 */ +#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9) +/* RDI dump 2 */ +#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+10) +#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+11) +#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+12) +#define MSM_V4L2_EXT_CAPTURE_MODE_AF \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+13) +#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+14) +#define MSM_V4L2_EXT_CAPTURE_MODE_CS \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15) +#define MSM_V4L2_EXT_CAPTURE_MODE_RS \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16) +#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17) +#define MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT \ + (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18) +#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+19) + + +#define MSM_V4L2_PID_MOTION_ISO V4L2_CID_PRIVATE_BASE +#define MSM_V4L2_PID_EFFECT (V4L2_CID_PRIVATE_BASE+1) +#define MSM_V4L2_PID_HJR (V4L2_CID_PRIVATE_BASE+2) +#define MSM_V4L2_PID_LED_MODE (V4L2_CID_PRIVATE_BASE+3) +#define MSM_V4L2_PID_PREP_SNAPSHOT (V4L2_CID_PRIVATE_BASE+4) +#define MSM_V4L2_PID_EXP_METERING (V4L2_CID_PRIVATE_BASE+5) +#define MSM_V4L2_PID_ISO (V4L2_CID_PRIVATE_BASE+6) +#define MSM_V4L2_PID_CAM_MODE (V4L2_CID_PRIVATE_BASE+7) +#define MSM_V4L2_PID_LUMA_ADAPTATION (V4L2_CID_PRIVATE_BASE+8) +#define MSM_V4L2_PID_BEST_SHOT (V4L2_CID_PRIVATE_BASE+9) +#define MSM_V4L2_PID_FOCUS_MODE (V4L2_CID_PRIVATE_BASE+10) +#define MSM_V4L2_PID_BL_DETECTION (V4L2_CID_PRIVATE_BASE+11) +#define MSM_V4L2_PID_SNOW_DETECTION (V4L2_CID_PRIVATE_BASE+12) +#define MSM_V4L2_PID_CTRL_CMD (V4L2_CID_PRIVATE_BASE+13) +#define MSM_V4L2_PID_EVT_SUB_INFO (V4L2_CID_PRIVATE_BASE+14) +#define MSM_V4L2_PID_STROBE_FLASH (V4L2_CID_PRIVATE_BASE+15) +#define MSM_V4L2_PID_INST_HANDLE (V4L2_CID_PRIVATE_BASE+16) +#define MSM_V4L2_PID_MMAP_INST (V4L2_CID_PRIVATE_BASE+17) +#define MSM_V4L2_PID_PP_PLANE_INFO (V4L2_CID_PRIVATE_BASE+18) +#define MSM_V4L2_PID_MAX MSM_V4L2_PID_PP_PLANE_INFO + +/* camera operation mode for video recording - two frame output queues */ +#define MSM_V4L2_CAM_OP_DEFAULT 0 +/* camera operation mode for video recording - two frame output queues */ +#define MSM_V4L2_CAM_OP_PREVIEW (MSM_V4L2_CAM_OP_DEFAULT+1) +/* camera operation mode for video recording - two frame output queues */ +#define MSM_V4L2_CAM_OP_VIDEO (MSM_V4L2_CAM_OP_DEFAULT+2) +/* camera operation mode for standard shapshot - two frame output queues */ +#define MSM_V4L2_CAM_OP_CAPTURE (MSM_V4L2_CAM_OP_DEFAULT+3) +/* camera operation mode for zsl shapshot - three output queues */ +#define MSM_V4L2_CAM_OP_ZSL (MSM_V4L2_CAM_OP_DEFAULT+4) +/* camera operation mode for raw snapshot - one frame output queue */ +#define MSM_V4L2_CAM_OP_RAW (MSM_V4L2_CAM_OP_DEFAULT+5) +/* camera operation mode for jpeg snapshot - one frame output queue */ +#define MSM_V4L2_CAM_OP_JPEG_CAPTURE (MSM_V4L2_CAM_OP_DEFAULT+6) + + +#define MSM_V4L2_VID_CAP_TYPE 0 +#define MSM_V4L2_STREAM_ON 1 +#define MSM_V4L2_STREAM_OFF 2 +#define MSM_V4L2_SNAPSHOT 3 +#define MSM_V4L2_QUERY_CTRL 4 +#define MSM_V4L2_GET_CTRL 5 +#define MSM_V4L2_SET_CTRL 6 +#define MSM_V4L2_QUERY 7 +#define MSM_V4L2_GET_CROP 8 +#define MSM_V4L2_SET_CROP 9 +#define MSM_V4L2_OPEN 10 +#define MSM_V4L2_CLOSE 11 +#define MSM_V4L2_SET_CTRL_CMD 12 +#define MSM_V4L2_EVT_SUB_MASK 13 +#define MSM_V4L2_PRIVATE_CMD 14 +#define MSM_V4L2_MAX 15 +#define V4L2_CAMERA_EXIT 43 + +struct crop_info { + void *info; + int len; +}; + +struct msm_postproc { + int ftnum; + struct msm_frame fthumnail; + int fmnum; + struct msm_frame fmain; +}; + +struct msm_snapshot_pp_status { + void *status; +}; + +#define CFG_SET_MODE 0 +#define CFG_SET_EFFECT 1 +#define CFG_START 2 +#define CFG_PWR_UP 3 +#define CFG_PWR_DOWN 4 +#define CFG_WRITE_EXPOSURE_GAIN 5 +#define CFG_SET_DEFAULT_FOCUS 6 +#define CFG_MOVE_FOCUS 7 +#define CFG_REGISTER_TO_REAL_GAIN 8 +#define CFG_REAL_TO_REGISTER_GAIN 9 +#define CFG_SET_FPS 10 +#define CFG_SET_PICT_FPS 11 +#define CFG_SET_BRIGHTNESS 12 +#define CFG_SET_CONTRAST 13 +#define CFG_SET_ZOOM 14 +#define CFG_SET_EXPOSURE_MODE 15 +#define CFG_SET_WB 16 +#define CFG_SET_ANTIBANDING 17 +#define CFG_SET_EXP_GAIN 18 +#define CFG_SET_PICT_EXP_GAIN 19 +#define CFG_SET_LENS_SHADING 20 +#define CFG_GET_PICT_FPS 21 +#define CFG_GET_PREV_L_PF 22 +#define CFG_GET_PREV_P_PL 23 +#define CFG_GET_PICT_L_PF 24 +#define CFG_GET_PICT_P_PL 25 +#define CFG_GET_AF_MAX_STEPS 26 +#define CFG_GET_PICT_MAX_EXP_LC 27 +#define CFG_SEND_WB_INFO 28 +#define CFG_SENSOR_INIT 29 +#define CFG_GET_3D_CALI_DATA 30 +#define CFG_GET_CALIB_DATA 31 +#define CFG_GET_OUTPUT_INFO 32 +#define CFG_GET_EEPROM_INFO 33 +#define CFG_GET_EEPROM_DATA 34 +#define CFG_SET_ACTUATOR_INFO 35 +#define CFG_GET_ACTUATOR_INFO 36 +/* TBD: QRD */ +#define CFG_SET_SATURATION 37 +#define CFG_SET_SHARPNESS 38 +#define CFG_SET_TOUCHAEC 39 +#define CFG_SET_AUTO_FOCUS 40 +#define CFG_SET_AUTOFLASH 41 +#define CFG_SET_EXPOSURE_COMPENSATION 42 +#define CFG_SET_ISO 43 +#define CFG_START_STREAM 44 +#define CFG_STOP_STREAM 45 +#define CFG_GET_CSI_PARAMS 46 +#define CFG_POWER_UP 47 +#define CFG_POWER_DOWN 48 +#define CFG_WRITE_I2C_ARRAY 49 +#define CFG_READ_I2C_ARRAY 50 +#define CFG_PCLK_CHANGE 51 +#define CFG_CONFIG_VREG_ARRAY 52 +#define CFG_CONFIG_CLK_ARRAY 53 +#define CFG_GPIO_OP 54 +#define CFG_MAX 55 + + +#define MOVE_NEAR 0 +#define MOVE_FAR 1 + +#define SENSOR_PREVIEW_MODE 0 +#define SENSOR_SNAPSHOT_MODE 1 +#define SENSOR_RAW_SNAPSHOT_MODE 2 +#define SENSOR_HFR_60FPS_MODE 3 +#define SENSOR_HFR_90FPS_MODE 4 +#define SENSOR_HFR_120FPS_MODE 5 + +#define SENSOR_QTR_SIZE 0 +#define SENSOR_FULL_SIZE 1 +#define SENSOR_QVGA_SIZE 2 +#define SENSOR_INVALID_SIZE 3 + +#define CAMERA_EFFECT_OFF 0 +#define CAMERA_EFFECT_MONO 1 +#define CAMERA_EFFECT_NEGATIVE 2 +#define CAMERA_EFFECT_SOLARIZE 3 +#define CAMERA_EFFECT_SEPIA 4 +#define CAMERA_EFFECT_POSTERIZE 5 +#define CAMERA_EFFECT_WHITEBOARD 6 +#define CAMERA_EFFECT_BLACKBOARD 7 +#define CAMERA_EFFECT_AQUA 8 +#define CAMERA_EFFECT_EMBOSS 9 +#define CAMERA_EFFECT_SKETCH 10 +#define CAMERA_EFFECT_NEON 11 +#define CAMERA_EFFECT_FADED 12 +#define CAMERA_EFFECT_VINTAGECOOL 13 +#define CAMERA_EFFECT_VINTAGEWARM 14 +#define CAMERA_EFFECT_ACCENT_BLUE 15 +#define CAMERA_EFFECT_ACCENT_GREEN 16 +#define CAMERA_EFFECT_ACCENT_ORANGE 17 +#define CAMERA_EFFECT_MAX 18 + +/* QRD */ +#define CAMERA_EFFECT_BW 10 +#define CAMERA_EFFECT_BLUISH 12 +#define CAMERA_EFFECT_REDDISH 13 +#define CAMERA_EFFECT_GREENISH 14 + +/* QRD */ +#define CAMERA_ANTIBANDING_OFF 0 +#define CAMERA_ANTIBANDING_50HZ 2 +#define CAMERA_ANTIBANDING_60HZ 1 +#define CAMERA_ANTIBANDING_AUTO 3 + +#define CAMERA_CONTRAST_LV0 0 +#define CAMERA_CONTRAST_LV1 1 +#define CAMERA_CONTRAST_LV2 2 +#define CAMERA_CONTRAST_LV3 3 +#define CAMERA_CONTRAST_LV4 4 +#define CAMERA_CONTRAST_LV5 5 +#define CAMERA_CONTRAST_LV6 6 +#define CAMERA_CONTRAST_LV7 7 +#define CAMERA_CONTRAST_LV8 8 +#define CAMERA_CONTRAST_LV9 9 + +#define CAMERA_BRIGHTNESS_LV0 0 +#define CAMERA_BRIGHTNESS_LV1 1 +#define CAMERA_BRIGHTNESS_LV2 2 +#define CAMERA_BRIGHTNESS_LV3 3 +#define CAMERA_BRIGHTNESS_LV4 4 +#define CAMERA_BRIGHTNESS_LV5 5 +#define CAMERA_BRIGHTNESS_LV6 6 +#define CAMERA_BRIGHTNESS_LV7 7 +#define CAMERA_BRIGHTNESS_LV8 8 + + +#define CAMERA_SATURATION_LV0 0 +#define CAMERA_SATURATION_LV1 1 +#define CAMERA_SATURATION_LV2 2 +#define CAMERA_SATURATION_LV3 3 +#define CAMERA_SATURATION_LV4 4 +#define CAMERA_SATURATION_LV5 5 +#define CAMERA_SATURATION_LV6 6 +#define CAMERA_SATURATION_LV7 7 +#define CAMERA_SATURATION_LV8 8 + +#define CAMERA_SHARPNESS_LV0 0 +#define CAMERA_SHARPNESS_LV1 3 +#define CAMERA_SHARPNESS_LV2 6 +#define CAMERA_SHARPNESS_LV3 9 +#define CAMERA_SHARPNESS_LV4 12 +#define CAMERA_SHARPNESS_LV5 15 +#define CAMERA_SHARPNESS_LV6 18 +#define CAMERA_SHARPNESS_LV7 21 +#define CAMERA_SHARPNESS_LV8 24 +#define CAMERA_SHARPNESS_LV9 27 +#define CAMERA_SHARPNESS_LV10 30 + +#define CAMERA_SETAE_AVERAGE 0 +#define CAMERA_SETAE_CENWEIGHT 1 + +#define CAMERA_WB_AUTO 1 /* This list must match aeecamera.h */ +#define CAMERA_WB_CUSTOM 2 +#define CAMERA_WB_INCANDESCENT 3 +#define CAMERA_WB_FLUORESCENT 4 +#define CAMERA_WB_DAYLIGHT 5 +#define CAMERA_WB_CLOUDY_DAYLIGHT 6 +#define CAMERA_WB_TWILIGHT 7 +#define CAMERA_WB_SHADE 8 + +#define CAMERA_EXPOSURE_COMPENSATION_LV0 12 +#define CAMERA_EXPOSURE_COMPENSATION_LV1 6 +#define CAMERA_EXPOSURE_COMPENSATION_LV2 0 +#define CAMERA_EXPOSURE_COMPENSATION_LV3 -6 +#define CAMERA_EXPOSURE_COMPENSATION_LV4 -12 + +enum msm_v4l2_saturation_level { + MSM_V4L2_SATURATION_L0, + MSM_V4L2_SATURATION_L1, + MSM_V4L2_SATURATION_L2, + MSM_V4L2_SATURATION_L3, + MSM_V4L2_SATURATION_L4, + MSM_V4L2_SATURATION_L5, + MSM_V4L2_SATURATION_L6, + MSM_V4L2_SATURATION_L7, + MSM_V4L2_SATURATION_L8, + MSM_V4L2_SATURATION_L9, + MSM_V4L2_SATURATION_L10, +}; + +enum msm_v4l2_contrast_level { + MSM_V4L2_CONTRAST_L0, + MSM_V4L2_CONTRAST_L1, + MSM_V4L2_CONTRAST_L2, + MSM_V4L2_CONTRAST_L3, + MSM_V4L2_CONTRAST_L4, + MSM_V4L2_CONTRAST_L5, + MSM_V4L2_CONTRAST_L6, + MSM_V4L2_CONTRAST_L7, + MSM_V4L2_CONTRAST_L8, + MSM_V4L2_CONTRAST_L9, + MSM_V4L2_CONTRAST_L10, +}; + + +enum msm_v4l2_exposure_level { + MSM_V4L2_EXPOSURE_N2, + MSM_V4L2_EXPOSURE_N1, + MSM_V4L2_EXPOSURE_D, + MSM_V4L2_EXPOSURE_P1, + MSM_V4L2_EXPOSURE_P2, +}; + +enum msm_v4l2_sharpness_level { + MSM_V4L2_SHARPNESS_L0, + MSM_V4L2_SHARPNESS_L1, + MSM_V4L2_SHARPNESS_L2, + MSM_V4L2_SHARPNESS_L3, + MSM_V4L2_SHARPNESS_L4, + MSM_V4L2_SHARPNESS_L5, + MSM_V4L2_SHARPNESS_L6, +}; + +enum msm_v4l2_expo_metering_mode { + MSM_V4L2_EXP_FRAME_AVERAGE, + MSM_V4L2_EXP_CENTER_WEIGHTED, + MSM_V4L2_EXP_SPOT_METERING, +}; + +enum msm_v4l2_iso_mode { + MSM_V4L2_ISO_AUTO = 0, + MSM_V4L2_ISO_DEBLUR, + MSM_V4L2_ISO_100, + MSM_V4L2_ISO_200, + MSM_V4L2_ISO_400, + MSM_V4L2_ISO_800, + MSM_V4L2_ISO_1600, +}; + +enum msm_v4l2_wb_mode { + MSM_V4L2_WB_OFF, + MSM_V4L2_WB_AUTO , + MSM_V4L2_WB_CUSTOM, + MSM_V4L2_WB_INCANDESCENT, + MSM_V4L2_WB_FLUORESCENT, + MSM_V4L2_WB_DAYLIGHT, + MSM_V4L2_WB_CLOUDY_DAYLIGHT, +}; + +enum msm_v4l2_special_effect { + MSM_V4L2_EFFECT_OFF, + MSM_V4L2_EFFECT_MONO, + MSM_V4L2_EFFECT_NEGATIVE, + MSM_V4L2_EFFECT_SOLARIZE, + MSM_V4L2_EFFECT_SEPIA, + MSM_V4L2_EFFECT_POSTERAIZE, + MSM_V4L2_EFFECT_WHITEBOARD, + MSM_V4L2_EFFECT_BLACKBOARD, + MSM_V4L2_EFFECT_AQUA, + MSM_V4L2_EFFECT_EMBOSS, + MSM_V4L2_EFFECT_SKETCH, + MSM_V4L2_EFFECT_NEON, + MSM_V4L2_EFFECT_MAX, +}; + +enum msm_v4l2_power_line_frequency { + MSM_V4L2_POWER_LINE_OFF, + MSM_V4L2_POWER_LINE_60HZ, + MSM_V4L2_POWER_LINE_50HZ, + MSM_V4L2_POWER_LINE_AUTO, +}; + +#define CAMERA_ISO_TYPE_AUTO 0 +#define CAMEAR_ISO_TYPE_HJR 1 +#define CAMEAR_ISO_TYPE_100 2 +#define CAMERA_ISO_TYPE_200 3 +#define CAMERA_ISO_TYPE_400 4 +#define CAMEAR_ISO_TYPE_800 5 +#define CAMERA_ISO_TYPE_1600 6 + +struct sensor_pict_fps { + uint16_t prevfps; + uint16_t pictfps; +}; + +struct exp_gain_cfg { + uint16_t gain; + uint32_t line; +}; + +struct focus_cfg { + int32_t steps; + int dir; +}; + +struct fps_cfg { + uint16_t f_mult; + uint16_t fps_div; + uint32_t pict_fps_div; +}; +struct wb_info_cfg { + uint16_t red_gain; + uint16_t green_gain; + uint16_t blue_gain; +}; +struct sensor_3d_exp_cfg { + uint16_t gain; + uint32_t line; + uint16_t r_gain; + uint16_t b_gain; + uint16_t gr_gain; + uint16_t gb_gain; + uint16_t gain_adjust; +}; +struct sensor_3d_cali_data_t{ + unsigned char left_p_matrix[3][4][8]; + unsigned char right_p_matrix[3][4][8]; + unsigned char square_len[8]; + unsigned char focal_len[8]; + unsigned char pixel_pitch[8]; + uint16_t left_r; + uint16_t left_b; + uint16_t left_gb; + uint16_t left_af_far; + uint16_t left_af_mid; + uint16_t left_af_short; + uint16_t left_af_5um; + uint16_t left_af_50up; + uint16_t left_af_50down; + uint16_t right_r; + uint16_t right_b; + uint16_t right_gb; + uint16_t right_af_far; + uint16_t right_af_mid; + uint16_t right_af_short; + uint16_t right_af_5um; + uint16_t right_af_50up; + uint16_t right_af_50down; +}; +struct sensor_init_cfg { + uint8_t prev_res; + uint8_t pict_res; +}; + +struct sensor_calib_data { + /* Color Related Measurements */ + uint16_t r_over_g; + uint16_t b_over_g; + uint16_t gr_over_gb; + + /* Lens Related Measurements */ + uint16_t macro_2_inf; + uint16_t inf_2_macro; + uint16_t stroke_amt; + uint16_t af_pos_1m; + uint16_t af_pos_inf; +}; + +enum msm_sensor_resolution_t { + MSM_SENSOR_RES_FULL, + MSM_SENSOR_RES_QTR, + MSM_SENSOR_RES_2, + MSM_SENSOR_RES_3, + MSM_SENSOR_RES_4, + MSM_SENSOR_RES_5, + MSM_SENSOR_RES_6, + MSM_SENSOR_RES_7, + MSM_SENSOR_INVALID_RES, +}; + +struct msm_sensor_output_info_t { + uint16_t x_output; + uint16_t y_output; + uint16_t line_length_pclk; + uint16_t frame_length_lines; + uint32_t vt_pixel_clk; + uint32_t op_pixel_clk; + uint16_t binning_factor; +}; + +struct sensor_output_info_t { + struct msm_sensor_output_info_t *output_info; + uint16_t num_info; +}; + +struct msm_sensor_exp_gain_info_t { + uint16_t coarse_int_time_addr; + uint16_t global_gain_addr; + uint16_t vert_offset; +}; + +struct msm_sensor_output_reg_addr_t { + uint16_t x_output; + uint16_t y_output; + uint16_t line_length_pclk; + uint16_t frame_length_lines; +}; + +struct sensor_driver_params_type { + struct msm_camera_i2c_reg_setting *init_settings; + uint16_t init_settings_size; + struct msm_camera_i2c_reg_setting *mode_settings; + uint16_t mode_settings_size; + struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr; + struct msm_camera_i2c_reg_setting *start_settings; + struct msm_camera_i2c_reg_setting *stop_settings; + struct msm_camera_i2c_reg_setting *groupon_settings; + struct msm_camera_i2c_reg_setting *groupoff_settings; + struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info; + struct msm_sensor_output_info_t *output_info; +}; + +struct mirror_flip { + int32_t x_mirror; + int32_t y_flip; +}; + +struct cord { + uint32_t x; + uint32_t y; +}; + +struct msm_eeprom_data_t { + void *eeprom_data; + uint16_t index; +}; + +struct msm_camera_csid_vc_cfg { + uint8_t cid; + uint8_t dt; + uint8_t decode_format; +}; + +struct csi_lane_params_t { + uint16_t csi_lane_assign; + uint8_t csi_lane_mask; + uint8_t csi_if; + uint8_t csid_core[2]; + uint8_t csi_phy_sel; +}; + +struct msm_camera_csid_lut_params { + uint8_t num_cid; + struct msm_camera_csid_vc_cfg *vc_cfg; +}; + +struct msm_camera_csid_params { + uint8_t lane_cnt; + uint16_t lane_assign; + uint8_t phy_sel; + struct msm_camera_csid_lut_params lut_params; +}; + +struct msm_camera_csiphy_params { + uint8_t lane_cnt; + uint8_t settle_cnt; + uint16_t lane_mask; + uint8_t combo_mode; + uint8_t csid_core; +}; + +struct msm_camera_csi2_params { + struct msm_camera_csid_params csid_params; + struct msm_camera_csiphy_params csiphy_params; +}; + +enum msm_camera_csi_data_format { + CSI_8BIT, + CSI_10BIT, + CSI_12BIT, +}; + +struct msm_camera_csi_params { + enum msm_camera_csi_data_format data_format; + uint8_t lane_cnt; + uint8_t lane_assign; + uint8_t settle_cnt; + uint8_t dpcm_scheme; +}; + +enum csic_cfg_type_t { + CSIC_INIT, + CSIC_CFG, +}; + +struct csic_cfg_data { + enum csic_cfg_type_t cfgtype; + struct msm_camera_csi_params *csic_params; +}; + +enum csid_cfg_type_t { + CSID_INIT, + CSID_CFG, +}; + +struct csid_cfg_data { + enum csid_cfg_type_t cfgtype; + union { + uint32_t csid_version; + struct msm_camera_csid_params *csid_params; + } cfg; +}; + +enum csiphy_cfg_type_t { + CSIPHY_INIT, + CSIPHY_CFG, +}; + +struct csiphy_cfg_data { + enum csiphy_cfg_type_t cfgtype; + struct msm_camera_csiphy_params *csiphy_params; +}; + +#define CSI_EMBED_DATA 0x12 +#define CSI_RESERVED_DATA_0 0x13 +#define CSI_YUV422_8 0x1E +#define CSI_RAW8 0x2A +#define CSI_RAW10 0x2B +#define CSI_RAW12 0x2C + +#define CSI_DECODE_6BIT 0 +#define CSI_DECODE_8BIT 1 +#define CSI_DECODE_10BIT 2 +#define CSI_DECODE_DPCM_10_8_10 5 + +#define ISPIF_STREAM(intf, action, vfe) (((intf)<> 24) : 0xFF) + +#define CLR_IMG_MODE(handle) (handle &= 0xFF00FFFF) +#define SET_IMG_MODE(handle, data) \ + (handle |= ((0x1 << 23) | ((data & 0x7F) << 16))) +#define GET_IMG_MODE(handle) \ + ((handle & 0x800000) ? ((handle & 0x7F0000) >> 16) : 0xFF) + +#define CLR_MCTLPP_INST_IDX(handle) (handle &= 0xFFFF00FF) +#define SET_MCTLPP_INST_IDX(handle, data) \ + (handle |= ((0x1 << 15) | ((data & 0x7F) << 8))) +#define GET_MCTLPP_INST_IDX(handle) \ + ((handle & 0x8000) ? ((handle & 0x7F00) >> 8) : 0xFF) + +#define CLR_VIDEO_INST_IDX(handle) (handle &= 0xFFFFFF00) +#define GET_VIDEO_INST_IDX(handle) \ + ((handle & 0x80) ? (handle & 0x7F) : 0xFF) +#define SET_VIDEO_INST_IDX(handle, data) \ + (handle |= (0x1 << 7) | (data & 0x7F)) + +#endif /* __UAPI_MSM_CAMERA_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/Makefile b/drivers/media/platform/msm/camera_v2_j5/isp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8300d3bef6a46fd292a174159025e127a6526768 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSMB_CAMERA) += msm_isp.o msm_buf_mgr.o msm_isp_util.o msm_isp_axi_util.o msm_isp_stats_util.o +obj-$(CONFIG_MSMB_CAMERA) += msm_isp44.o msm_isp40.o msm_isp32.o diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_buf_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..c71f5a6102e169b2fa484aa82d4adc3f2a50169e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_buf_mgr.c @@ -0,0 +1,962 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include "../include/media/msm_camera.h" +#include + +#include + +#include "msm.h" +#include "msm_buf_mgr.h" + +/*#define CONFIG_MSM_ISP_DBG*/ +#undef CDBG +#ifdef CONFIG_MSM_ISP_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static struct msm_isp_bufq *msm_isp_get_bufq( + struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle) +{ + struct msm_isp_bufq *bufq = NULL; + uint32_t bufq_index = bufq_handle & 0xFF; + if (bufq_index > buf_mgr->num_buf_q) + return bufq; + + bufq = &buf_mgr->bufq[bufq_index]; + if (bufq->bufq_handle == bufq_handle) + return bufq; + + return NULL; +} + +static struct msm_isp_buffer *msm_isp_get_buf_ptr( + struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index) +{ + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return buf_info; + } + + if (bufq->num_bufs <= buf_index) { + pr_err("%s: Invalid buf index\n", __func__); + return buf_info; + } + buf_info = &bufq->bufs[buf_index]; + return buf_info; +} + +static uint32_t msm_isp_get_buf_handle( + struct msm_isp_buf_mgr *buf_mgr, + uint32_t session_id, uint32_t stream_id) +{ + int i; + if ((buf_mgr->buf_handle_cnt << 8) == 0) + buf_mgr->buf_handle_cnt++; + + for (i = 0; i < buf_mgr->num_buf_q; i++) { + if (buf_mgr->bufq[i].session_id == session_id && + buf_mgr->bufq[i].stream_id == stream_id) + return 0; + } + + for (i = 0; i < buf_mgr->num_buf_q; i++) { + if (buf_mgr->bufq[i].bufq_handle == 0) { + memset(&buf_mgr->bufq[i], + 0, sizeof(struct msm_isp_bufq)); + buf_mgr->bufq[i].bufq_handle = + (++buf_mgr->buf_handle_cnt) << 8 | i; + return buf_mgr->bufq[i].bufq_handle; + } + } + return 0; +} + +static int msm_isp_free_buf_handle(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle) +{ + struct msm_isp_bufq *bufq = + msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) + return -EINVAL; + memset(bufq, 0, sizeof(struct msm_isp_bufq)); + return 0; +} + +static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buffer *buf_info, + struct v4l2_buffer *v4l2_buf) +{ + int i, rc = -1; + struct msm_isp_buffer_mapped_info *mapped_info; + struct buffer_cmd *buf_pending = NULL; + + for (i = 0; i < v4l2_buf->length; i++) { + mapped_info = &buf_info->mapped_info[i]; + mapped_info->handle = + ion_import_dma_buf(buf_mgr->client, + v4l2_buf->m.planes[i].m.userptr); + if (IS_ERR_OR_NULL(mapped_info->handle)) { + pr_err("%s: buf has null/error ION handle %p\n", + __func__, mapped_info->handle); + goto ion_map_error; + } + if (ion_map_iommu(buf_mgr->client, mapped_info->handle, + buf_mgr->iommu_domain_num, 0, SZ_4K, + 0, &(mapped_info->paddr), + &(mapped_info->len), 0, 0) < 0) { + rc = -EINVAL; + pr_err("%s: cannot map address", __func__); + ion_free(buf_mgr->client, mapped_info->handle); + goto ion_map_error; + } + mapped_info->paddr += v4l2_buf->m.planes[i].data_offset; + CDBG("%s: plane: %d addr:%lu\n", + __func__, i, mapped_info->paddr); + + buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC); + if (!buf_pending) { + pr_err("No free memory for buf_pending\n"); + return rc; + } + + buf_pending->mapped_info = mapped_info; + list_add_tail(&buf_pending->list, &buf_mgr->buffer_q); + } + buf_info->num_planes = v4l2_buf->length; + return 0; +ion_map_error: + for (--i; i >= 0; i--) { + mapped_info = &buf_info->mapped_info[i]; + ion_unmap_iommu(buf_mgr->client, mapped_info->handle, + buf_mgr->iommu_domain_num, 0); + ion_free(buf_mgr->client, mapped_info->handle); + } + return rc; +} + +static void msm_isp_unprepare_v4l2_buf( + struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buffer *buf_info) +{ + int i; + struct msm_isp_buffer_mapped_info *mapped_info; + struct buffer_cmd *buf_pending = NULL; + + for (i = 0; i < buf_info->num_planes; i++) { + mapped_info = &buf_info->mapped_info[i]; + + list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) { + if (!buf_pending) + break; + + if (buf_pending->mapped_info == mapped_info) { + ion_unmap_iommu(buf_mgr->client, + mapped_info->handle, + buf_mgr->iommu_domain_num, 0); + ion_free(buf_mgr->client, mapped_info->handle); + + list_del_init(&buf_pending->list); + kfree(buf_pending); + break; + } + } + } + return; +} + +static int msm_isp_buf_prepare(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_qbuf_info *info, struct vb2_buffer *vb2_buf) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + struct v4l2_buffer *buf = NULL; + struct v4l2_plane *plane = NULL; + + buf_info = msm_isp_get_buf_ptr(buf_mgr, + info->handle, info->buf_idx); + if (!buf_info) { + pr_err("Invalid buffer prepare\n"); + return rc; + } + + bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { + rc = buf_info->state; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + + if (buf_info->state != MSM_ISP_BUFFER_STATE_INITIALIZED) { + pr_err("%s: Invalid buffer state: %d\n", + __func__, buf_info->state); + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + if (vb2_buf) { + buf = &vb2_buf->v4l2_buf; + buf_info->vb2_buf = vb2_buf; + } else { + buf = &info->buffer; + plane = + kzalloc(sizeof(struct v4l2_plane) * buf->length, + GFP_KERNEL); + if (!plane) { + pr_err("%s: Cannot alloc plane: %d\n", + __func__, buf_info->state); + return rc; + } + if (copy_from_user(plane, + (void __user *)(buf->m.planes), + sizeof(struct v4l2_plane) * buf->length)) { + kfree(plane); + return rc; + } + buf->m.planes = plane; + } + + rc = msm_isp_prepare_v4l2_buf(buf_mgr, buf_info, buf); + if (rc < 0) { + pr_err("%s: Prepare buffer error\n", __func__); + kfree(plane); + return rc; + } + spin_lock_irqsave(&bufq->bufq_lock, flags); + buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + kfree(plane); + return rc; +} + +static int msm_isp_buf_unprepare(struct msm_isp_buf_mgr *buf_mgr, + uint32_t buf_handle) +{ + int rc = -1, i; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + bufq = msm_isp_get_bufq(buf_mgr, buf_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + + for (i = 0; i < bufq->num_bufs; i++) { + buf_info = msm_isp_get_buf_ptr(buf_mgr, buf_handle, i); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + if (buf_info->state == MSM_ISP_BUFFER_STATE_UNUSED || + buf_info->state == + MSM_ISP_BUFFER_STATE_INITIALIZED) + continue; + + if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) { + if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || + buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) + buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, + bufq->session_id, bufq->stream_id); + } + msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info); + } + return 0; +} + +static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, + uint32_t bufq_handle, struct msm_isp_buffer **buf_info) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_buffer *temp_buf_info; + struct msm_isp_bufq *bufq = NULL; + struct vb2_buffer *vb2_buf = NULL; + struct buffer_cmd *buf_pending = NULL; + struct msm_isp_buffer_mapped_info *mped_info_tmp1; + struct msm_isp_buffer_mapped_info *mped_info_tmp2; + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + if (!bufq->bufq_handle) { + pr_err("%s: Invalid bufq handle\n", __func__); + return rc; + } + + *buf_info = NULL; + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (bufq->buf_type == ISP_SHARE_BUF) { + list_for_each_entry(temp_buf_info, + &bufq->share_head, share_list) { + if (!temp_buf_info->buf_used[id]) { + temp_buf_info->buf_used[id] = 1; + temp_buf_info->buf_get_count++; + if (temp_buf_info->buf_get_count == + bufq->buf_client_count) + list_del_init( + &temp_buf_info->share_list); + if (temp_buf_info->buf_reuse_flag) { + kfree(temp_buf_info); + } else { + *buf_info = temp_buf_info; + rc = 0; + } + spin_unlock_irqrestore( + &bufq->bufq_lock, flags); + return rc; + } + } + } + + switch (BUF_SRC(bufq->stream_id)) { + case MSM_ISP_BUFFER_SRC_NATIVE: + list_for_each_entry(temp_buf_info, &bufq->head, list) { + if (temp_buf_info->state == + MSM_ISP_BUFFER_STATE_QUEUED) { + + list_for_each_entry(buf_pending, + &buf_mgr->buffer_q, list) { + if (!buf_pending) + break; + mped_info_tmp1 = + buf_pending->mapped_info; + mped_info_tmp2 = + &temp_buf_info->mapped_info[0]; + + if (mped_info_tmp1 == mped_info_tmp2 + && (mped_info_tmp1->len == + mped_info_tmp2->len) + && (mped_info_tmp1->paddr == + mped_info_tmp2->paddr)) { + /* found one buf */ + list_del_init( + &temp_buf_info->list); + *buf_info = temp_buf_info; + break; + } + } + break; + } + } + break; + case MSM_ISP_BUFFER_SRC_HAL: + vb2_buf = buf_mgr->vb2_ops->get_buf( + bufq->session_id, bufq->stream_id); + if (vb2_buf) { + if (vb2_buf->v4l2_buf.index < bufq->num_bufs) { + + list_for_each_entry(buf_pending, + &buf_mgr->buffer_q, list) { + if (!buf_pending) + break; + mped_info_tmp1 = + buf_pending->mapped_info; + mped_info_tmp2 = + &bufq->bufs[vb2_buf->v4l2_buf.index] + .mapped_info[0]; + + if (mped_info_tmp1 == mped_info_tmp2 + && (mped_info_tmp1->len == + mped_info_tmp2->len) + && (mped_info_tmp1->paddr == + mped_info_tmp2->paddr)) { + *buf_info = + &bufq->bufs[vb2_buf->v4l2_buf.index]; + (*buf_info)->vb2_buf = vb2_buf; + break; + } + } + } else { + pr_err("%s: Incorrect buf index %d\n", + __func__, vb2_buf->v4l2_buf.index); + rc = -EINVAL; + } + } + break; + case MSM_ISP_BUFFER_SRC_SCRATCH: + /* In scratch buf case we have only on buffer in queue. + * We return every time same buffer. */ + *buf_info = list_entry(bufq->head.next, typeof(**buf_info), + list); + break; + default: + pr_err("%s: Incorrect buf source.\n", __func__); + rc = -EINVAL; + return rc; + } + + if (!(*buf_info)) { + if (bufq->buf_type == ISP_SHARE_BUF) { + temp_buf_info = kzalloc( + sizeof(struct msm_isp_buffer), GFP_ATOMIC); + if (temp_buf_info) { + temp_buf_info->buf_reuse_flag = 1; + temp_buf_info->buf_used[id] = 1; + temp_buf_info->buf_get_count = 1; + list_add_tail(&temp_buf_info->share_list, + &bufq->share_head); + } else + rc = -ENOMEM; + } + } else { + (*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED; + if (bufq->buf_type == ISP_SHARE_BUF) { + memset((*buf_info)->buf_used, 0, + sizeof(uint8_t) * bufq->buf_client_count); + (*buf_info)->buf_used[id] = 1; + (*buf_info)->buf_get_count = 1; + (*buf_info)->buf_put_count = 0; + (*buf_info)->buf_reuse_flag = 0; + list_add_tail(&(*buf_info)->share_list, + &bufq->share_head); + } + rc = 0; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; +} + +static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + switch (buf_info->state) { + case MSM_ISP_BUFFER_STATE_PREPARED: + if (MSM_ISP_BUFFER_SRC_SCRATCH == BUF_SRC(bufq->stream_id)) + list_add_tail(&buf_info->list, &bufq->head); + case MSM_ISP_BUFFER_STATE_DEQUEUED: + case MSM_ISP_BUFFER_STATE_DIVERTED: + if (MSM_ISP_BUFFER_SRC_NATIVE == BUF_SRC(bufq->stream_id)) + list_add_tail(&buf_info->list, &bufq->head); + else if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) + buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf, + bufq->session_id, bufq->stream_id); + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + rc = 0; + break; + case MSM_ISP_BUFFER_STATE_DISPATCHED: + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + rc = 0; + break; + case MSM_ISP_BUFFER_STATE_QUEUED: + rc = 0; + break; + default: + pr_err("%s: incorrect state = %d", + __func__, buf_info->state); + break; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + return rc; +} + +static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id, uint32_t output_format) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + enum msm_isp_buffer_state state; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq\n"); + return rc; + } + + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + state = buf_info->state; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + if (state == MSM_ISP_BUFFER_STATE_DEQUEUED || + state == MSM_ISP_BUFFER_STATE_DIVERTED) { + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (bufq->buf_type == ISP_SHARE_BUF) { + buf_info->buf_put_count++; + if (buf_info->buf_put_count != ISP_SHARE_BUF_CLIENT) { + rc = buf_info->buf_put_count; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + } + buf_info->state = MSM_ISP_BUFFER_STATE_DISPATCHED; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) { + buf_info->vb2_buf->v4l2_buf.timestamp = *tv; + buf_info->vb2_buf->v4l2_buf.sequence = frame_id; + buf_info->vb2_buf->v4l2_buf.reserved = output_format; + buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf, + bufq->session_id, bufq->stream_id); + } else { + rc = msm_isp_put_buf(buf_mgr, buf_info->bufq_handle, + buf_info->buf_idx); + if (rc < 0) { + pr_err("%s: Buf put failed\n", __func__); + return rc; + } + } + } + + return 0; +} + +static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type) +{ + int rc = -1, i; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq\n"); + return rc; + } + + for (i = 0; i < bufq->num_bufs; i++) { + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, i); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + continue; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (flush_type == MSM_ISP_BUFFER_FLUSH_DIVERTED && + buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + } else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL && + (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED || + buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED || + buf_info->state == MSM_ISP_BUFFER_STATE_DISPATCHED)) { + buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + } + return 0; +} + +static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id) +{ + int rc = -1; + unsigned long flags; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq\n"); + return rc; + } + + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + + spin_lock_irqsave(&bufq->bufq_lock, flags); + if (bufq->buf_type == ISP_SHARE_BUF) { + buf_info->buf_put_count++; + if (buf_info->buf_put_count != ISP_SHARE_BUF_CLIENT) { + rc = buf_info->buf_put_count; + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + return rc; + } + } + + if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED) { + buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; + buf_info->tv = tv; + buf_info->frame_id = frame_id; + } + spin_unlock_irqrestore(&bufq->bufq_lock, flags); + + return 0; +} + +static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_qbuf_info *info) +{ + int rc = -1, buf_state; + struct msm_isp_bufq *bufq = NULL; + struct msm_isp_buffer *buf_info = NULL; + buf_state = msm_isp_buf_prepare(buf_mgr, info, NULL); + if (buf_state < 0) { + pr_err("%s: Buf prepare failed\n", __func__); + return -EINVAL; + } + + if (buf_state == MSM_ISP_BUFFER_STATE_DIVERTED) { + buf_info = msm_isp_get_buf_ptr(buf_mgr, + info->handle, info->buf_idx); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return rc; + } + if (info->dirty_buf) { + rc = msm_isp_put_buf(buf_mgr, + info->handle, info->buf_idx); + } else { + bufq = msm_isp_get_bufq(buf_mgr, info->handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + if (BUF_SRC(bufq->stream_id)) + pr_err("%s: Invalid native buffer state\n", + __func__); + else + rc = msm_isp_buf_done(buf_mgr, + info->handle, info->buf_idx, + buf_info->tv, buf_info->frame_id, 0); + } + } else { + bufq = msm_isp_get_bufq(buf_mgr, info->handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return rc; + } + if (MSM_ISP_BUFFER_SRC_HAL != BUF_SRC(bufq->stream_id)) { + rc = msm_isp_put_buf(buf_mgr, + info->handle, info->buf_idx); + if (rc < 0) { + pr_err("%s: Buf put failed\n", __func__); + return rc; + } + } + } + return rc; +} + +static int msm_isp_get_bufq_handle(struct msm_isp_buf_mgr *buf_mgr, + uint32_t session_id, uint32_t stream_id) +{ + int i; + for (i = 0; i < buf_mgr->num_buf_q; i++) { + if (buf_mgr->bufq[i].session_id == session_id && + buf_mgr->bufq[i].stream_id == stream_id) { + return buf_mgr->bufq[i].bufq_handle; + } + } + return 0; +} + +static int msm_isp_get_buf_src(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t *buf_src) +{ + struct msm_isp_bufq *bufq = NULL; + + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("%s: Invalid bufq\n", __func__); + return -EINVAL; + } + *buf_src = BUF_SRC(bufq->stream_id); + + return 0; +} + +static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buf_request *buf_request) +{ + int rc = -1, i; + struct msm_isp_bufq *bufq = NULL; + CDBG("%s: E\n", __func__); + + if (!buf_request->num_buf || buf_request->num_buf > VIDEO_MAX_FRAME) { + pr_err("Invalid buffer request\n"); + return rc; + } + + buf_request->handle = msm_isp_get_buf_handle(buf_mgr, + buf_request->session_id, buf_request->stream_id); + if (!buf_request->handle) { + pr_err("Invalid buffer handle\n"); + return rc; + } + + bufq = msm_isp_get_bufq(buf_mgr, buf_request->handle); + if (!bufq) { + pr_err("Invalid buffer queue\n"); + return rc; + } + + bufq->bufs = kzalloc(sizeof(struct msm_isp_buffer) * + buf_request->num_buf, GFP_KERNEL); + if (!bufq->bufs) { + pr_err("No free memory for buf info\n"); + msm_isp_free_buf_handle(buf_mgr, buf_request->handle); + return rc; + } + + spin_lock_init(&bufq->bufq_lock); + bufq->bufq_handle = buf_request->handle; + bufq->session_id = buf_request->session_id; + bufq->stream_id = buf_request->stream_id; + bufq->num_bufs = buf_request->num_buf; + bufq->buf_type = buf_request->buf_type; + if (bufq->buf_type == ISP_SHARE_BUF) + bufq->buf_client_count = ISP_SHARE_BUF_CLIENT; + INIT_LIST_HEAD(&bufq->head); + INIT_LIST_HEAD(&bufq->share_head); + for (i = 0; i < buf_request->num_buf; i++) { + bufq->bufs[i].state = MSM_ISP_BUFFER_STATE_INITIALIZED; + bufq->bufs[i].bufq_handle = bufq->bufq_handle; + bufq->bufs[i].buf_idx = i; + } + + return 0; +} + +static int msm_isp_release_bufq(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle) +{ + struct msm_isp_bufq *bufq = NULL; + int rc = -1; + bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); + if (!bufq) { + pr_err("Invalid bufq release\n"); + return rc; + } + + msm_isp_buf_unprepare(buf_mgr, bufq_handle); + + kfree(bufq->bufs); + msm_isp_free_buf_handle(buf_mgr, bufq_handle); + return 0; +} + +static void msm_isp_release_all_bufq( + struct msm_isp_buf_mgr *buf_mgr) +{ + struct msm_isp_bufq *bufq = NULL; + int i; + for (i = 0; i < buf_mgr->num_buf_q; i++) { + bufq = &buf_mgr->bufq[i]; + if (!bufq->bufq_handle) + continue; + msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle); + + kfree(bufq->bufs); + msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle); + } +} + +static void msm_isp_register_ctx(struct msm_isp_buf_mgr *buf_mgr, + struct device **iommu_ctx, int num_iommu_ctx) +{ + int i; + buf_mgr->num_iommu_ctx = num_iommu_ctx; + for (i = 0; i < num_iommu_ctx; i++) + buf_mgr->iommu_ctx[i] = iommu_ctx[i]; +} + +static int msm_isp_attach_ctx(struct msm_isp_buf_mgr *buf_mgr) +{ + int rc, i; + for (i = 0; i < buf_mgr->num_iommu_ctx; i++) { + rc = iommu_attach_device(buf_mgr->iommu_domain, + buf_mgr->iommu_ctx[i]); + if (rc) { + pr_err("%s: Iommu attach error\n", __func__); + return -EINVAL; + } + } + return 0; +} + +static void msm_isp_detach_ctx(struct msm_isp_buf_mgr *buf_mgr) +{ + int i; + for (i = 0; i < buf_mgr->num_iommu_ctx; i++) + iommu_detach_device(buf_mgr->iommu_domain, + buf_mgr->iommu_ctx[i]); +} + +static int msm_isp_init_isp_buf_mgr( + struct msm_isp_buf_mgr *buf_mgr, + const char *ctx_name, uint16_t num_buf_q) +{ + int rc = -1; + if (buf_mgr->open_count++) + return 0; + + if (!num_buf_q) { + pr_err("Invalid buffer queue number\n"); + return rc; + } + CDBG("%s: E\n", __func__); + + msm_isp_attach_ctx(buf_mgr); + INIT_LIST_HEAD(&buf_mgr->buffer_q); + buf_mgr->num_buf_q = num_buf_q; + buf_mgr->bufq = + kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q, + GFP_KERNEL); + if (!buf_mgr->bufq) { + pr_err("Bufq malloc error\n"); + goto bufq_error; + } + buf_mgr->client = msm_ion_client_create(ctx_name); + buf_mgr->buf_handle_cnt = 0; + return 0; +bufq_error: + return rc; +} + +static int msm_isp_deinit_isp_buf_mgr( + struct msm_isp_buf_mgr *buf_mgr) +{ + if (--buf_mgr->open_count) + return 0; + msm_isp_release_all_bufq(buf_mgr); + ion_client_destroy(buf_mgr->client); + kfree(buf_mgr->bufq); + buf_mgr->num_buf_q = 0; + msm_isp_detach_ctx(buf_mgr); + return 0; +} + +int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, + unsigned int cmd, void *arg) +{ + switch (cmd) { + case VIDIOC_MSM_ISP_REQUEST_BUF: { + struct msm_isp_buf_request *buf_req = arg; + buf_mgr->ops->request_buf(buf_mgr, buf_req); + break; + } + case VIDIOC_MSM_ISP_ENQUEUE_BUF: { + struct msm_isp_qbuf_info *qbuf_info = arg; + buf_mgr->ops->enqueue_buf(buf_mgr, qbuf_info); + break; + } + case VIDIOC_MSM_ISP_RELEASE_BUF: { + struct msm_isp_buf_request *buf_req = arg; + buf_mgr->ops->release_buf(buf_mgr, buf_req->handle); + break; + } + } + return 0; +} + +static struct msm_isp_buf_ops isp_buf_ops = { + .request_buf = msm_isp_request_bufq, + .enqueue_buf = msm_isp_buf_enqueue, + .release_buf = msm_isp_release_bufq, + .get_bufq_handle = msm_isp_get_bufq_handle, + .get_buf_src = msm_isp_get_buf_src, + .get_buf = msm_isp_get_buf, + .put_buf = msm_isp_put_buf, + .flush_buf = msm_isp_flush_buf, + .buf_done = msm_isp_buf_done, + .buf_divert = msm_isp_buf_divert, + .register_ctx = msm_isp_register_ctx, + .buf_mgr_init = msm_isp_init_isp_buf_mgr, + .buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr, +}; + +int msm_isp_create_isp_buf_mgr( + struct msm_isp_buf_mgr *buf_mgr, + struct msm_sd_req_vb2_q *vb2_ops, + struct msm_iova_layout *iova_layout) +{ + int rc = 0; + if (buf_mgr->init_done) + return rc; + + buf_mgr->iommu_domain_num = msm_register_domain(iova_layout); + if (buf_mgr->iommu_domain_num < 0) { + pr_err("%s: Invalid iommu domain number\n", __func__); + rc = -1; + goto iommu_domain_error; + } + + buf_mgr->iommu_domain = msm_get_iommu_domain( + buf_mgr->iommu_domain_num); + if (!buf_mgr->iommu_domain) { + pr_err("%s: Invalid iommu domain\n", __func__); + rc = -1; + goto iommu_domain_error; + } + + buf_mgr->ops = &isp_buf_ops; + buf_mgr->vb2_ops = vb2_ops; + buf_mgr->init_done = 1; + buf_mgr->open_count = 0; + return 0; +iommu_domain_error: + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_buf_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..b98067e44151d9aa32105f12d3dd7bd85c2ee34b --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_buf_mgr.h @@ -0,0 +1,170 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef _MSM_ISP_BUF_H_ +#define _MSM_ISP_BUF_H_ + +#include "../include/media/msmb_isp.h" +#include +#include "msm_sd.h" + +/* Buffer type could be userspace / HAL. + * Userspase could provide native or scratch buffer. */ +#define BUF_SRC(id) ( \ + (id & ISP_SCRATCH_BUF_BIT) ? MSM_ISP_BUFFER_SRC_SCRATCH : \ + (id & ISP_NATIVE_BUF_BIT) ? MSM_ISP_BUFFER_SRC_NATIVE : \ + MSM_ISP_BUFFER_SRC_HAL) + +#define ISP_SHARE_BUF_CLIENT 2 + +struct msm_isp_buf_mgr; + +enum msm_isp_buffer_src_t { + MSM_ISP_BUFFER_SRC_HAL, + MSM_ISP_BUFFER_SRC_NATIVE, + MSM_ISP_BUFFER_SRC_SCRATCH, + MSM_ISP_BUFFER_SRC_MAX, +}; + +enum msm_isp_buffer_state { + MSM_ISP_BUFFER_STATE_UNUSED, /* not used */ + MSM_ISP_BUFFER_STATE_INITIALIZED, /* REQBUF done */ + MSM_ISP_BUFFER_STATE_PREPARED, /* BUF mapped */ + MSM_ISP_BUFFER_STATE_QUEUED, /* buf queued */ + MSM_ISP_BUFFER_STATE_DEQUEUED, /* in use in VFE */ + MSM_ISP_BUFFER_STATE_DIVERTED, /* Sent to other hardware*/ + MSM_ISP_BUFFER_STATE_DISPATCHED, /* Sent to HAL*/ +}; + +enum msm_isp_buffer_flush_t { + MSM_ISP_BUFFER_FLUSH_DIVERTED, + MSM_ISP_BUFFER_FLUSH_ALL, +}; + +struct msm_isp_buffer_mapped_info { + unsigned long len; + dma_addr_t paddr; + struct ion_handle *handle; +}; + +struct buffer_cmd { + struct list_head list; + struct msm_isp_buffer_mapped_info *mapped_info; +}; + +struct msm_isp_buffer { + /*Common Data structure*/ + int num_planes; + struct msm_isp_buffer_mapped_info mapped_info[VIDEO_MAX_PLANES]; + int buf_idx; + uint32_t bufq_handle; + uint32_t frame_id; + struct timeval *tv; + + /*Native buffer*/ + struct list_head list; + enum msm_isp_buffer_state state; + + /*Vb2 buffer data*/ + struct vb2_buffer *vb2_buf; + + /*Share buffer cache state*/ + struct list_head share_list; + uint8_t buf_used[ISP_SHARE_BUF_CLIENT]; + uint8_t buf_get_count; + uint8_t buf_put_count; + uint8_t buf_reuse_flag; +}; + +struct msm_isp_bufq { + uint32_t session_id; + uint32_t stream_id; + uint32_t num_bufs; + uint32_t bufq_handle; + enum msm_isp_buf_type buf_type; + struct msm_isp_buffer *bufs; + spinlock_t bufq_lock; + + /*Native buffer queue*/ + struct list_head head; + /*Share buffer cache queue*/ + struct list_head share_head; + uint8_t buf_client_count; +}; + +struct msm_isp_buf_ops { + int (*request_buf) (struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_buf_request *buf_request); + + int (*enqueue_buf) (struct msm_isp_buf_mgr *buf_mgr, + struct msm_isp_qbuf_info *info); + + int (*release_buf) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle); + + int (*get_bufq_handle) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t session_id, uint32_t stream_id); + + int (*get_buf_src) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t *buf_src); + + int (*get_buf) (struct msm_isp_buf_mgr *buf_mgr, uint32_t id, + uint32_t bufq_handle, struct msm_isp_buffer **buf_info); + + int (*put_buf) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index); + + int (*flush_buf) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type); + + int (*buf_done) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id, uint32_t output_format); + int (*buf_divert) (struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id); + void (*register_ctx) (struct msm_isp_buf_mgr *buf_mgr, + struct device **iommu_ctx, int num_iommu_ctx); + int (*buf_mgr_init) (struct msm_isp_buf_mgr *buf_mgr, + const char *ctx_name, uint16_t num_buf_q); + int (*buf_mgr_deinit) (struct msm_isp_buf_mgr *buf_mgr); +}; + +struct msm_isp_buf_mgr { + int init_done; + uint32_t open_count; + spinlock_t lock; + uint16_t num_buf_q; + struct msm_isp_bufq *bufq; + + struct ion_client *client; + struct msm_isp_buf_ops *ops; + uint32_t buf_handle_cnt; + + struct msm_sd_req_vb2_q *vb2_ops; + + /*IOMMU specific*/ + int iommu_domain_num; + struct iommu_domain *iommu_domain; + + int num_iommu_ctx; + struct device *iommu_ctx[2]; + struct list_head buffer_q; +}; + +int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr, + struct msm_sd_req_vb2_q *vb2_ops, struct msm_iova_layout *iova_layout); + +int msm_isp_proc_buf_cmd(struct msm_isp_buf_mgr *buf_mgr, + unsigned int cmd, void *arg); + +#endif /* _MSM_ISP_BUF_H_ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp.c new file mode 100644 index 0000000000000000000000000000000000000000..f2586f872f803d8b99350d9b070214e1fd36a2da --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp.c @@ -0,0 +1,317 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_isp.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_sd.h" +#include "msm_isp44.h" +#include "msm_isp40.h" +#include "msm_isp32.h" + +static struct msm_sd_req_vb2_q vfe_vb2_ops; + +static const struct of_device_id msm_vfe_dt_match[] = { + { + .compatible = "qcom,vfe44", + .data = &vfe44_hw_info, + }, + { + .compatible = "qcom,vfe40", + .data = &vfe40_hw_info, + }, + { + .compatible = "qcom,vfe32", + .data = &vfe32_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_vfe_dt_match); + +static const struct platform_device_id msm_vfe_dev_id[] = { + {"msm_vfe32", (kernel_ulong_t) &vfe32_hw_info}, + {} +}; + +#define MAX_OVERFLOW_COUNTERS 15 +#define OVERFLOW_LENGTH 512 +#define OVERFLOW_BUFFER_LENGTH 32 +static struct msm_isp_buf_mgr vfe_buf_mgr; +static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats); +static char *stats_str[MAX_OVERFLOW_COUNTERS] = { + "imgmaster0_overflow_cnt", + "imgmaster1_overflow_cnt", + "imgmaster2_overflow_cnt", + "imgmaster3_overflow_cnt", + "imgmaster4_overflow_cnt", + "imgmaster5_overflow_cnt", + "imgmaster6_overflow_cnt", + "be_overflow_cnt", + "bg_overflow_cnt", + "bf_overflow_cnt", + "awb_overflow_cnt", + "rs_overflow_cnt", + "cs_overflow_cnt", + "ihist_overflow_cnt", + "skinbhist_overflow_cnt", +}; + +static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char, + size_t t_size_t, loff_t *t_loff_t) +{ + int i; + char name[OVERFLOW_LENGTH] = {0}; + int *ptr; + char buffer[OVERFLOW_BUFFER_LENGTH] = {0}; + struct msm_isp_statistics *stats = (struct msm_isp_statistics *) + t_file->private_data; + ptr = (int *)stats; + + for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) { + strlcat(name, stats_str[i], sizeof(name)); + strlcat(name, " ", sizeof(name)); + snprintf(buffer, sizeof(buffer), "%d", ptr[i]); + strlcat(name, buffer, sizeof(name)); + strlcat(name, "\r\n", sizeof(name)); + } + return simple_read_from_buffer(t_char, t_size_t, + t_loff_t, name, strlen(name)); +} + +static ssize_t vfe_debugfs_statistics_write(struct file *t_file, + const char *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + struct msm_isp_statistics *stats = (struct msm_isp_statistics *) + t_file->private_data; + memset(stats, 0, sizeof(struct msm_isp_statistics)); + + return sizeof(struct msm_isp_statistics); +} + +static const struct file_operations vfe_debugfs_error = { + .open = vfe_debugfs_statistics_open, + .read = vfe_debugfs_statistics_read, + .write = vfe_debugfs_statistics_write, +}; + +static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats) +{ + struct dentry *debugfs_base; + debugfs_base = debugfs_create_dir("msm_isp", NULL); + if (!debugfs_base) + return -ENOMEM; + if (!debugfs_create_file("stats", S_IRUGO | S_IWUSR, debugfs_base, + stats, &vfe_debugfs_error)) + return -ENOMEM; + return 0; +} +static long msm_isp_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + + switch (cmd) { + case VIDIOC_DQEVENT: + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + + default: + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); + } +} + +static long msm_isp_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_isp_subdev_do_ioctl); +} + +static struct v4l2_file_operations msm_isp_v4l2_subdev_fops = { +#ifdef CONFIG_COMPAT + .compat_ioctl = msm_isp_subdev_fops_ioctl, +#endif + .unlocked_ioctl = msm_isp_subdev_fops_ioctl +}; + +static int vfe_probe(struct platform_device *pdev) +{ + struct vfe_device *vfe_dev; + /*struct msm_cam_subdev_info sd_info;*/ + const struct of_device_id *match_dev; + int rc = 0; + + struct msm_iova_partition vfe_partition = { + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + struct msm_iova_layout vfe_layout = { + .partitions = &vfe_partition, + .npartitions = 1, + .client_name = "vfe", + .domain_flags = 0, + }; + + vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL); + if (!vfe_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL); + if (!vfe_dev->stats) { + pr_err("%s: no enough memory\n", __func__); + kfree(vfe_dev); + return -ENOMEM; + } + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + match_dev = of_match_device(msm_vfe_dt_match, &pdev->dev); + if (!match_dev) { + pr_err("%s: No vfe hardware info\n", __func__); + kfree(vfe_dev); + return -EINVAL; + } + vfe_dev->hw_info = + (struct msm_vfe_hardware_info *) match_dev->data; + } else { + vfe_dev->hw_info = (struct msm_vfe_hardware_info *) + platform_get_device_id(pdev)->driver_data; + } + + if (!vfe_dev->hw_info) { + pr_err("%s: No vfe hardware info\n", __func__); + kfree(vfe_dev); + return -EINVAL; + } + ISP_DBG("%s: device id = %d\n", __func__, pdev->id); + + vfe_dev->pdev = pdev; + rc = vfe_dev->hw_info->vfe_ops.core_ops.get_platform_data(vfe_dev); + if (rc < 0) { + pr_err("%s: failed to get platform resources\n", __func__); + kfree(vfe_dev); + return -ENOMEM; + } + + INIT_LIST_HEAD(&vfe_dev->tasklet_q); + tasklet_init(&vfe_dev->vfe_tasklet, + msm_isp_do_tasklet, (unsigned long)vfe_dev); + + v4l2_subdev_init(&vfe_dev->subdev.sd, vfe_dev->hw_info->subdev_ops); + vfe_dev->subdev.sd.internal_ops = + vfe_dev->hw_info->subdev_internal_ops; + snprintf(vfe_dev->subdev.sd.name, + ARRAY_SIZE(vfe_dev->subdev.sd.name), + "vfe"); + vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + vfe_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + v4l2_set_subdevdata(&vfe_dev->subdev.sd, vfe_dev); + platform_set_drvdata(pdev, &vfe_dev->subdev.sd); + mutex_init(&vfe_dev->realtime_mutex); + mutex_init(&vfe_dev->core_mutex); + spin_lock_init(&vfe_dev->tasklet_lock); + spin_lock_init(&vfe_dev->shared_data_lock); +#if defined(CONFIG_SR200PC20) && defined(CONFIG_SR544) + spin_lock_init(&vfe_dev->sof_lock); +#endif + media_entity_init(&vfe_dev->subdev.sd.entity, 0, NULL, 0); + vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE; + vfe_dev->subdev.sd.entity.name = pdev->name; + vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2; + rc = msm_sd_register(&vfe_dev->subdev); + if (rc != 0) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + kfree(vfe_dev); + goto end; + } + + msm_isp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_isp_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_isp_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_isp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + + vfe_dev->subdev.sd.devnode->fops = &msm_isp_v4l2_subdev_fops; + + vfe_dev->buf_mgr = &vfe_buf_mgr; + v4l2_subdev_notify(&vfe_dev->subdev.sd, + MSM_SD_NOTIFY_REQ_CB, &vfe_vb2_ops); + rc = msm_isp_create_isp_buf_mgr(vfe_dev->buf_mgr, + &vfe_vb2_ops, &vfe_layout); + if (rc < 0) { + pr_err("%s: Unable to create buffer manager\n", __func__); + kfree(vfe_dev); + return -EINVAL; + } + msm_isp_enable_debugfs(vfe_dev->stats); + vfe_dev->buf_mgr->ops->register_ctx(vfe_dev->buf_mgr, + &vfe_dev->iommu_ctx[0], vfe_dev->hw_info->num_iommu_ctx); + vfe_dev->vfe_open_cnt = 0; +end: + return rc; +} + +static struct platform_driver vfe_driver = { + .probe = vfe_probe, + .driver = { + .name = "msm_vfe", + .owner = THIS_MODULE, + .of_match_table = msm_vfe_dt_match, + }, + .id_table = msm_vfe_dev_id, +}; + +static int __init msm_vfe_init_module(void) +{ + return platform_driver_register(&vfe_driver); +} + +static void __exit msm_vfe_exit_module(void) +{ + platform_driver_unregister(&vfe_driver); +} + +module_init(msm_vfe_init_module); +module_exit(msm_vfe_exit_module); +MODULE_DESCRIPTION("MSM VFE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp.h new file mode 100644 index 0000000000000000000000000000000000000000..cb16d8d93c2298d49ff5b748d05687181f499e52 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp.h @@ -0,0 +1,541 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_VFE_H__ +#define __MSM_VFE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/media/msmb_isp.h" +#include +#include +#include "msm_buf_mgr.h" + +#define VFE40_8974V1_VERSION 0x10000018 +#define VFE40_8974V2_VERSION 0x1001001A +#define VFE40_8974V3_VERSION 0x1001001B +#define VFE40_8x26_VERSION 0x20000013 +#define VFE40_8x26V2_VERSION 0x20010014 +#define VFE40_8916_VERSION 0x10030000 +#define VFE40_8939_VERSION 0x10040000 + +#define MAX_IOMMU_CTX 2 +#define MAX_NUM_WM 7 +#define MAX_NUM_RDI 3 +#define MAX_NUM_RDI_MASTER 3 +#define MAX_NUM_COMPOSITE_MASK 4 +#define MAX_NUM_STATS_COMP_MASK 2 +#define MAX_INIT_FRAME_DROP 31 +#define ISP_Q2 (1 << 2) + +#define AVTIMER_MSW_PHY_ADDR 0xFE05300C +#define AVTIMER_LSW_PHY_ADDR 0xFE053008 +#define AVTIMER_MSW_PHY_ADDR_8916 0x7706010 +#define AVTIMER_LSW_PHY_ADDR_8916 0x770600C +#define AVTIMER_MODE_CTL_PHY_ADDR_8916 0x7706040 +/*AVTimer h/w is configured to generate 27Mhz ticks*/ +#define AVTIMER_TICK_SCALER_8916 27 +#define AVTIMER_ITERATION_CTR 16 + +#define VFE_PING_FLAG 0xFFFFFFFF +#define VFE_PONG_FLAG 0x0 + +#define VFE_MAX_CFG_TIMEOUT 3000 +#define VFE_CLK_INFO_MAX 16 +#define STATS_COMP_BIT_MASK 0xFF0000 + +struct vfe_device; +struct msm_vfe_axi_stream; +struct msm_vfe_stats_stream; + +struct vfe_subscribe_info { + struct v4l2_fh *vfh; + uint32_t active; +}; + +enum msm_isp_pack_fmt { + QCOM, + MIPI, + DPCM6, + DPCM8, + PLAIN8, + PLAIN16, + MAX_ISP_PACK_FMT, +}; + +enum msm_isp_camif_update_state { + NO_UPDATE, + ENABLE_CAMIF, + DISABLE_CAMIF, + DISABLE_CAMIF_IMMEDIATELY +}; + +enum msm_isp_reset_type { + ISP_RST_HARD, + ISP_RST_SOFT, + ISP_RST_MAX +}; + +struct msm_isp_timestamp { + /*Monotonic clock for v4l2 buffer*/ + struct timeval buf_time; + /*Monotonic clock for VT */ + struct timeval vt_time; + /*Wall clock for userspace event*/ + struct timeval event_time; +}; + +struct msm_vfe_irq_ops { + void (*read_irq_status) (struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1); + void (*process_reg_update) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_epoch_irq)(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_reset_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1); + void (*process_halt_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1); + void (*process_camif_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_axi_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); + void (*process_stats_irq) (struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +}; + +struct msm_vfe_axi_ops { + void (*reload_wm) (struct vfe_device *vfe_dev, + uint32_t reload_mask); + void (*enable_wm) (struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable); + int32_t (*cfg_io_format) (struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, + uint32_t io_format); + void (*cfg_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*cfg_comp_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_comp_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info); + + void (*cfg_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx); + void (*clear_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); + + void (*cfg_wm_xbar_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx); + void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx); + + void (*cfg_ub) (struct vfe_device *vfe_dev); + + void (*update_ping_pong_addr) (struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr); + + uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev); + long (*halt) (struct vfe_device *vfe_dev, uint32_t blocking); +}; + +struct msm_vfe_core_ops { + void (*reg_update) (struct vfe_device *vfe_dev, uint32_t input_src); + long (*reset_hw) (struct vfe_device *vfe_dev, + enum msm_isp_reset_type reset_type, + uint32_t blocking); + int (*init_hw) (struct vfe_device *vfe_dev); + void (*init_hw_reg) (struct vfe_device *vfe_dev); + void (*release_hw) (struct vfe_device *vfe_dev); + void (*cfg_camif) (struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg); + void (*update_camif_state) (struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state); + void (*cfg_rdi_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_rdi_cfg *rdi_cfg, + enum msm_vfe_input_src input_src); + int (*get_platform_data) (struct vfe_device *vfe_dev); + void (*get_error_mask) (uint32_t *error_mask0, uint32_t *error_mask1); + void (*process_error_status) (struct vfe_device *vfe_dev); + void (*get_overflow_mask) (uint32_t *overflow_mask); + void (*get_irq_mask) (struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask); + void (*restore_irq_mask) (struct vfe_device *vfe_dev); + void (*get_halt_restart_mask) (uint32_t *irq0_mask, + uint32_t *irq1_mask); + void (*init_vbif_counters) (struct vfe_device *vfe_dev); + void (*vbif_clear_counters) (struct vfe_device *vfe_dev); + void (*vbif_read_counters) (struct vfe_device *vfe_dev); +}; +struct msm_vfe_stats_ops { + int (*get_stats_idx) (enum msm_isp_stats_type stats_type); + int (*check_streams) (struct msm_vfe_stats_stream *stream_info); + void (*cfg_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_framedrop) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*cfg_comp_mask) (struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable); + void (*cfg_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_wm_irq_mask) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + + void (*cfg_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + void (*clear_wm_reg) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info); + + void (*cfg_ub) (struct vfe_device *vfe_dev); + + void (*enable_module) (struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable); + + void (*update_ping_pong_addr) (struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, + uint32_t pingpong_status, dma_addr_t paddr); + + uint32_t (*get_frame_id) (struct vfe_device *vfe_dev); + uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1); + uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev); +}; + +struct msm_vfe_ops { + struct msm_vfe_irq_ops irq_ops; + struct msm_vfe_axi_ops axi_ops; + struct msm_vfe_core_ops core_ops; + struct msm_vfe_stats_ops stats_ops; +}; + +struct msm_vfe_hardware_info { + int num_iommu_ctx; + int vfe_clk_idx; + struct msm_vfe_ops vfe_ops; + struct msm_vfe_axi_hardware_info *axi_hw_info; + struct msm_vfe_stats_hardware_info *stats_hw_info; + struct v4l2_subdev_internal_ops *subdev_internal_ops; + struct v4l2_subdev_ops *subdev_ops; + uint32_t dmi_reg_offset; +}; + +struct msm_vfe_axi_hardware_info { + uint8_t num_wm; + uint8_t num_rdi; + uint8_t num_rdi_master; + uint8_t num_comp_mask; + uint32_t min_wm_ub; +}; + +enum msm_vfe_axi_state { + AVALIABLE, + INACTIVE, + ACTIVE, + PAUSED, + START_PENDING, + STOP_PENDING, + PAUSE_PENDING, + RESUME_PENDING, + STARTING, + STOPPING, + PAUSING, + RESUMING, +}; + +enum msm_vfe_axi_cfg_update_state { + NO_AXI_CFG_UPDATE, + APPLYING_UPDATE_RESUME, + UPDATE_REQUESTED, +}; + +#define VFE_NO_DROP 0xFFFFFFFF +#define VFE_DROP_EVERY_2FRAME 0x55555555 +#define VFE_DROP_EVERY_4FRAME 0x11111111 +#define VFE_DROP_EVERY_8FRAME 0x01010101 +#define VFE_DROP_EVERY_16FRAME 0x00010001 +#define VFE_DROP_EVERY_32FRAME 0x00000001 + +enum msm_vfe_axi_stream_type { + CONTINUOUS_STREAM, + BURST_STREAM, +}; + +struct msm_vfe_axi_stream { + uint32_t frame_id; + enum msm_vfe_axi_state state; + enum msm_vfe_axi_stream_src stream_src; + uint8_t num_planes; + uint8_t wm[MAX_PLANES_PER_STREAM]; + uint32_t output_format;/*Planar/RAW/Misc*/ + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; + uint8_t comp_mask_index; + struct msm_isp_buffer *buf[2]; + uint32_t session_id; + uint32_t stream_id; + uint32_t bufq_handle; + uint32_t bufq_scratch_handle; + uint32_t stream_handle; + uint32_t request_frm_num; + uint8_t buf_divert; + enum msm_vfe_axi_stream_type stream_type; + uint32_t vt_enable; + uint32_t frame_based; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t num_burst_capture;/*number of frame to capture*/ + uint32_t init_frame_drop; + uint32_t burst_frame_count;/*number of sof before burst stop*/ + uint8_t framedrop_update; + spinlock_t lock; + + /*Bandwidth calculation info*/ + uint32_t max_width; + /*Based on format plane size in Q2. e.g NV12 = 1.5*/ + uint32_t format_factor; + uint32_t bandwidth; + + /*Run time update variables*/ + uint32_t runtime_init_frame_drop; + uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/ + uint32_t runtime_num_burst_capture; + uint8_t runtime_framedrop_update; + uint32_t runtime_output_format; + enum msm_vfe_frame_skip_pattern frame_skip_pattern; + +}; + +enum msm_vfe_overflow_state { + NO_OVERFLOW, + OVERFLOW_DETECTED, + HALT_REQUESTED, + RESTART_REQUESTED, +}; + +struct msm_vfe_axi_composite_info { + uint32_t stream_handle; + uint32_t stream_composite_mask; +}; + +struct msm_vfe_src_info { + uint32_t frame_id; + uint8_t active; + uint8_t pix_stream_count; + uint8_t raw_stream_count; + enum msm_vfe_inputmux input_mux; + uint32_t width; + long pixel_clock; + uint32_t session_id; + uint32_t input_format;/*V4L2 pix format with bayer pattern*/ + uint32_t last_updt_frm_id; +}; + +enum msm_wm_ub_cfg_type { + MSM_WM_UB_CFG_DEFAULT, + MSM_WM_UB_EQUAL_SLICING, + MSM_WM_UB_CFG_MAX_NUM +}; +#define MAX_SESSIONS 5 +struct msm_vfe_axi_shared_data { + struct msm_vfe_axi_hardware_info *hw_info; + struct msm_vfe_axi_stream stream_info[MAX_NUM_STREAM]; + uint32_t free_wm[MAX_NUM_WM]; + uint32_t wm_image_size[MAX_NUM_WM]; + enum msm_wm_ub_cfg_type wm_ub_cfg_policy; + uint8_t num_used_wm; + uint8_t num_active_stream; + struct msm_vfe_axi_composite_info + composite_info[MAX_NUM_COMPOSITE_MASK]; + uint8_t num_used_composite_mask; + uint32_t stream_update; + atomic_t axi_cfg_update; + enum msm_isp_camif_update_state pipeline_update; + struct msm_vfe_src_info src_info[VFE_SRC_MAX]; + uint16_t stream_handle_cnt; + uint16_t current_frame_src_mask[MAX_SESSIONS]; + uint16_t session_frame_src_mask[MAX_SESSIONS]; + unsigned int frame_id[MAX_SESSIONS]; + uint32_t event_mask; + uint32_t burst_len; +}; + +struct msm_vfe_stats_hardware_info { + uint32_t stats_capability_mask; + uint8_t *stats_ping_pong_offset; + uint8_t num_stats_type; + uint8_t num_stats_comp_mask; +}; + +enum msm_vfe_stats_state { + STATS_AVALIABLE, + STATS_INACTIVE, + STATS_ACTIVE, + STATS_START_PENDING, + STATS_STOP_PENDING, + STATS_STARTING, + STATS_STOPPING, +}; + +struct msm_vfe_stats_stream { + uint32_t session_id; + uint32_t stream_id; + uint32_t stream_handle; + uint32_t composite_flag; + enum msm_isp_stats_type stats_type; + enum msm_vfe_stats_state state; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t irq_subsample_pattern; + + uint32_t buffer_offset; + struct msm_isp_buffer *buf[2]; + uint32_t bufq_handle; +}; + +struct msm_vfe_stats_shared_data { + struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX]; + uint8_t num_active_stream; + atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK]; + uint16_t stream_handle_cnt; + atomic_t stats_update; + uint32_t stats_mask; + uint32_t stats_burst_len; +}; + +struct msm_vfe_tasklet_queue_cmd { + struct list_head list; + uint32_t vfeInterruptStatus0; + uint32_t vfeInterruptStatus1; + struct msm_isp_timestamp ts; + uint8_t cmd_used; +}; + +#define MSM_VFE_TASKLETQ_SIZE 200 + +struct msm_vfe_error_info { + atomic_t overflow_state; + uint32_t overflow_recover_irq_mask0; + uint32_t overflow_recover_irq_mask1; + uint32_t error_mask0; + uint32_t error_mask1; + uint32_t violation_status; + uint32_t camif_status; + uint32_t stream_framedrop_count[MAX_NUM_STREAM]; + uint32_t stats_framedrop_count[MSM_ISP_STATS_MAX]; + uint32_t info_dump_frame_count; + uint32_t error_count; +}; + +struct msm_isp_statistics { + int32_t imagemaster0_overflow; + int32_t imagemaster1_overflow; + int32_t imagemaster2_overflow; + int32_t imagemaster3_overflow; + int32_t imagemaster4_overflow; + int32_t imagemaster5_overflow; + int32_t imagemaster6_overflow; + int32_t be_overflow; + int32_t bg_overflow; + int32_t bf_overflow; + int32_t awb_overflow; + int32_t rs_overflow; + int32_t cs_overflow; + int32_t ihist_overflow; + int32_t skinbhist_overflow; +}; + +struct msm_vbif_cntrs { + int previous_write_val; + int vfe_total_iter; + int fb_err_lvl; + int total_vbif_cnt_2; +}; + +struct vfe_device { + struct platform_device *pdev; + struct msm_sd_subdev subdev; + struct resource *vfe_irq; + struct resource *vfe_mem; + struct resource *vfe_vbif_mem; + struct resource *vfe_io; + struct resource *vfe_vbif_io; + void __iomem *vfe_base; + void __iomem *vfe_vbif_base; + + struct device *iommu_ctx[MAX_IOMMU_CTX]; + + struct regulator *fs_vfe; + struct clk **vfe_clk; + uint32_t num_clk; + + uint32_t bus_perf_client; + + struct completion reset_complete; + struct completion halt_complete; + struct completion stream_config_complete; + struct completion stats_config_complete; + struct mutex realtime_mutex; + struct mutex core_mutex; + + atomic_t irq_cnt; + uint8_t taskletq_idx; + spinlock_t tasklet_lock; + spinlock_t shared_data_lock; +#if defined(CONFIG_SR200PC20) && defined(CONFIG_SR544) + spinlock_t sof_lock; +#endif + struct list_head tasklet_q; + struct tasklet_struct vfe_tasklet; + struct msm_vfe_tasklet_queue_cmd + tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE]; + uint32_t vfe_hw_version; + struct msm_vfe_hardware_info *hw_info; + struct msm_vfe_axi_shared_data axi_data; + struct msm_vfe_stats_shared_data stats_data; + struct msm_vfe_error_info error_info; + struct msm_isp_buf_mgr *buf_mgr; + int dump_reg; + int vfe_clk_idx; + uint32_t vfe_open_cnt; + uint8_t vt_enable; + void __iomem *p_avtimer_msw; + void __iomem *p_avtimer_lsw; + void __iomem *p_avtimer_ctl; + uint8_t avtimer_scaler; + uint8_t ignore_error; + struct msm_isp_statistics *stats; + struct msm_vbif_cntrs vbif_cntrs; + uint32_t vfe_ub_size; + uint32_t frame_id; + uint32_t eof_event_occur; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp32.c new file mode 100644 index 0000000000000000000000000000000000000000..e8fd4f0bc4fc487fad1348275686b6f9a2ad9b29 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp32.c @@ -0,0 +1,1350 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include + +#include "msm_isp32.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_isp.h" +#include "msm.h" +#include "msm_camera_io_util.h" + +#define VFE32_BURST_LEN 2 +#define VFE32_UB_SIZE 1024 +#define VFE32_EQUAL_SLICE_UB 194 +#define VFE32_AXI_SLICE_UB 792 +#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx) +#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC) +#define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4)) +#define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8) +#define VFE32_PING_PONG_BASE(wm, ping_pong) \ + (VFE32_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) + +static uint8_t stats_pingpong_offset_map[] = { + 7, 8, 9, 10, 11, 12, 13}; + +#define VFE32_NUM_STATS_TYPE 7 +#define VFE32_STATS_BASE(idx) (0xF4 + 0xC * idx) +#define VFE32_STATS_PING_PONG_BASE(idx, ping_pong) \ + (VFE32_STATS_BASE(idx) + 0x4 * \ + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) + +#define VFE32_CLK_IDX 0 +#define MSM_ISP32_TOTAL_WM_UB 792 +/*792 double word*/ + +static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = { + /*vfe32 clock info for B-family: 8610 */ + {"vfe_clk_src", 266670000}, + {"vfe_clk", -1}, + {"vfe_ahb_clk", -1}, + {"csi_vfe_clk", -1}, + {"bus_clk", -1}, +}; + +static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = { + /*vfe32 clock info for A-family: 8960 */ + {"vfe_clk", 266667000}, + {"vfe_pclk", -1}, + {"csi_vfe_clk", -1}, +}; + +static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev) +{ + int rc = -1; + vfe_dev->vfe_clk_idx = 0; + rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (vfe_dev->fs_vfe) { + rc = regulator_enable(vfe_dev->fs_vfe); + if (rc) { + pr_err("%s: Regulator enable failed\n", __func__); + goto fs_failed; + } + } + if (vfe_dev->num_clk <= 0) { + pr_err("%s: Invalid num of clock\n", __func__); + goto fs_failed; + } else { + vfe_dev->vfe_clk = + kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, + GFP_KERNEL); + if (!vfe_dev->vfe_clk) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + } + + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info, + vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1); + if (rc < 0) { + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_2_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_2_clk_info), 1); + if (rc < 0) + goto clk_enable_failed; + else + vfe_dev->vfe_clk_idx = 2; + } else + vfe_dev->vfe_clk_idx = 1; + + vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, + resource_size(vfe_dev->vfe_mem)); + if (!vfe_dev->vfe_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vfe_remap_failed; + } + + rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, + IRQF_TRIGGER_RISING, "vfe", vfe_dev); + if (rc < 0) { + pr_err("%s: irq request failed\n", __func__); + goto irq_req_failed; + } + + return rc; +irq_req_failed: + iounmap(vfe_dev->vfe_base); +vfe_remap_failed: + if (vfe_dev->vfe_clk_idx == 1) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_1_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_1_clk_info), 0); + if (vfe_dev->vfe_clk_idx == 2) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_2_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_2_clk_info), 0); +clk_enable_failed: + if (vfe_dev->fs_vfe) + regulator_disable(vfe_dev->fs_vfe); + kfree(vfe_dev->vfe_clk); +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +bus_scale_register_failed: + return rc; +} + +static void msm_vfe32_release_hardware(struct vfe_device *vfe_dev) +{ + free_irq(vfe_dev->vfe_irq->start, vfe_dev); + tasklet_kill(&vfe_dev->vfe_tasklet); + iounmap(vfe_dev->vfe_base); + if (vfe_dev->vfe_clk_idx == 1) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_1_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_1_clk_info), 0); + if (vfe_dev->vfe_clk_idx == 2) + msm_cam_clk_enable(&vfe_dev->pdev->dev, + msm_vfe32_2_clk_info, vfe_dev->vfe_clk, + ARRAY_SIZE(msm_vfe32_2_clk_info), 0); + kfree(vfe_dev->vfe_clk); + regulator_disable(vfe_dev->fs_vfe); + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +} + +static void msm_vfe32_init_hardware_reg(struct vfe_device *vfe_dev) +{ + /* CGC_OVERRIDE */ + msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC); + /* BUS_CFG */ + msm_camera_io_w(0x00000009, vfe_dev->vfe_base + 0x3C); + msm_camera_io_w(0x01000025, vfe_dev->vfe_base + 0x1C); + msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20); + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24); + msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28); + msm_camera_io_w(0x0, vfe_dev->vfe_base+0x6FC); + msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(1)); + msm_camera_io_w(0x10000000, vfe_dev->vfe_base + VFE32_RDI_BASE(2)); + msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(0)); + msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(4)); + +} + +static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status1 & BIT(23)) + complete(&vfe_dev->reset_complete); +} + +static void msm_vfe32_process_halt_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status1 & (1 << 24)) { + msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8); + } +} + +static void msm_vfe32_process_epoch_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0x18)) + return; + if (irq_status0 & (1 << 3)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); +} + +static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0x1F)) + return; + + if (irq_status0 & BIT(0)) { + ISP_DBG("%s: SOF IRQ\n", __func__); + if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 + && vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count == 0) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + } + } +} + +static void msm_vfe32_process_violation_status(struct vfe_device *vfe_dev) +{ + uint32_t violation_status = vfe_dev->error_info.violation_status; + if (!violation_status) + return; + + if (violation_status & BIT(0)) + pr_err("%s: black violation\n", __func__); + if (violation_status & BIT(1)) + pr_err("%s: rolloff violation\n", __func__); + if (violation_status & BIT(2)) + pr_err("%s: demux violation\n", __func__); + if (violation_status & BIT(3)) + pr_err("%s: demosaic violation\n", __func__); + if (violation_status & BIT(4)) + pr_err("%s: crop violation\n", __func__); + if (violation_status & BIT(5)) + pr_err("%s: scale violation\n", __func__); + if (violation_status & BIT(6)) + pr_err("%s: wb violation\n", __func__); + if (violation_status & BIT(7)) + pr_err("%s: clf violation\n", __func__); + if (violation_status & BIT(8)) + pr_err("%s: matrix violation\n", __func__); + if (violation_status & BIT(9)) + pr_err("%s: rgb lut violation\n", __func__); + if (violation_status & BIT(10)) + pr_err("%s: la violation\n", __func__); + if (violation_status & BIT(11)) + pr_err("%s: chroma enhance violation\n", __func__); + if (violation_status & BIT(12)) + pr_err("%s: chroma supress mce violation\n", __func__); + if (violation_status & BIT(13)) + pr_err("%s: skin enhance violation\n", __func__); + if (violation_status & BIT(14)) + pr_err("%s: asf violation\n", __func__); + if (violation_status & BIT(15)) + pr_err("%s: scale y violation\n", __func__); + if (violation_status & BIT(16)) + pr_err("%s: scale cbcr violation\n", __func__); + if (violation_status & BIT(17)) + pr_err("%s: chroma subsample violation\n", __func__); + if (violation_status & BIT(18)) + pr_err("%s: framedrop enc y violation\n", __func__); + if (violation_status & BIT(19)) + pr_err("%s: framedrop enc cbcr violation\n", __func__); + if (violation_status & BIT(20)) + pr_err("%s: framedrop view y violation\n", __func__); + if (violation_status & BIT(21)) + pr_err("%s: framedrop view cbcr violation\n", __func__); + if (violation_status & BIT(22)) + pr_err("%s: realign buf y violation\n", __func__); + if (violation_status & BIT(23)) + pr_err("%s: realign buf cb violation\n", __func__); + if (violation_status & BIT(24)) + pr_err("%s: realign buf cr violation\n", __func__); +} + +static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev) +{ + uint32_t error_status1 = vfe_dev->error_info.error_mask1; + + if (error_status1 & BIT(0)) + pr_err("%s: camif error status: 0x%x\n", + __func__, vfe_dev->error_info.camif_status); + if (error_status1 & BIT(1)) + pr_err("%s: stats bhist overwrite\n", __func__); + if (error_status1 & BIT(2)) + pr_err("%s: stats cs overwrite\n", __func__); + if (error_status1 & BIT(3)) + pr_err("%s: stats ihist overwrite\n", __func__); + if (error_status1 & BIT(4)) + pr_err("%s: realign buf y overflow\n", __func__); + if (error_status1 & BIT(5)) + pr_err("%s: realign buf cb overflow\n", __func__); + if (error_status1 & BIT(6)) + pr_err("%s: realign buf cr overflow\n", __func__); + if (error_status1 & BIT(7)) { + pr_err("%s: violation\n", __func__); + msm_vfe32_process_violation_status(vfe_dev); + } + if (error_status1 & BIT(8)) { + vfe_dev->stats->imagemaster0_overflow++; + pr_err("%s: image master 0 bus overflow\n", __func__); + } + if (error_status1 & BIT(9)) { + vfe_dev->stats->imagemaster1_overflow++; + pr_err("%s: image master 1 bus overflow\n", __func__); + } + if (error_status1 & BIT(10)) { + vfe_dev->stats->imagemaster2_overflow++; + pr_err("%s: image master 2 bus overflow\n", __func__); + } + if (error_status1 & BIT(11)) { + vfe_dev->stats->imagemaster3_overflow++; + pr_err("%s: image master 3 bus overflow\n", __func__); + } + if (error_status1 & BIT(12)) { + vfe_dev->stats->imagemaster4_overflow++; + pr_err("%s: image master 4 bus overflow\n", __func__); + } + if (error_status1 & BIT(13)) { + vfe_dev->stats->imagemaster5_overflow++; + pr_err("%s: image master 5 bus overflow\n", __func__); + } + if (error_status1 & BIT(14)) { + vfe_dev->stats->imagemaster6_overflow++; + pr_err("%s: image master 6 bus overflow\n", __func__); + } + if (error_status1 & BIT(15)) { + vfe_dev->stats->bg_overflow++; + pr_err("%s: status ae/bg bus overflow\n", __func__); + } + if (error_status1 & BIT(16)) { + vfe_dev->stats->bf_overflow++; + pr_err("%s: status af/bf bus overflow\n", __func__); + } + if (error_status1 & BIT(17)) { + vfe_dev->stats->awb_overflow++; + pr_err("%s: status awb bus overflow\n", __func__); + } + if (error_status1 & BIT(18)) { + vfe_dev->stats->rs_overflow++; + pr_err("%s: status rs bus overflow\n", __func__); + } + if (error_status1 & BIT(19)) { + vfe_dev->stats->cs_overflow++; + pr_err("%s: status cs bus overflow\n", __func__); + } + if (error_status1 & BIT(20)) { + vfe_dev->stats->ihist_overflow++; + pr_err("%s: status ihist bus overflow\n", __func__); + } + if (error_status1 & BIT(21)) { + vfe_dev->stats->skinbhist_overflow++; + pr_err("%s: status skin bhist bus overflow\n", __func__); + } + if (error_status1 & BIT(22)) + pr_err("%s: axi error\n", __func__); +} + +static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); + *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x30); + msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x24); + msm_camera_io_w_mb(*irq_status1, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x18); + + if (*irq_status1 & BIT(0)) + vfe_dev->error_info.camif_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x204); + + if (*irq_status1 & BIT(7)) + vfe_dev->error_info.violation_status |= + msm_camera_io_r(vfe_dev->vfe_base + 0x7B4); +} + +static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + uint8_t input_src = 0x0; + if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000)) + return; + + if (irq_status0 & BIT(5)) { + msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + input_src |= (1 << VFE_PIX_0); + } + if (irq_status1 & BIT(26)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + input_src |= (1 << VFE_RAW_0); + } + if (irq_status1 & BIT(27)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + input_src |= (1 << VFE_RAW_1); + } + if (irq_status1 & BIT(28)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + input_src |= (1 << VFE_RAW_2); + } + + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->stats_data.stats_update)) + msm_isp_stats_stream_update(vfe_dev); + if (vfe_dev->axi_data.stream_update || atomic_read(&vfe_dev->stats_data.stats_update)) { + if (input_src & (1 << VFE_PIX_0)) { + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, (1 << VFE_PIX_0)); + } + } + msm_isp_update_framedrop_reg(vfe_dev); + msm_isp_update_error_frame_count(vfe_dev); + if ((input_src & (1 << VFE_RAW_0)) || (input_src & (1 << VFE_RAW_1)) || (input_src & (1 << VFE_RAW_2))) { + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, input_src); + } + return; +} + +static void msm_vfe32_reg_update( + struct vfe_device *vfe_dev, uint32_t input_src) +{ + msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x260); +} + +static uint32_t msm_vfe32_reset_values[ISP_RST_MAX] = { + 0x3FF, /* ISP_RST_HARD reset everything */ + 0x3EF /* ISP_RST_SOFT same as HARD RESET */ +}; + +static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev , + enum msm_isp_reset_type reset_type, uint32_t blocking) +{ + + uint32_t rst_val; + long rc = 0; + if (reset_type >= ISP_RST_MAX) { + pr_err("%s: Error Invalid parameter\n", __func__); + reset_type = ISP_RST_HARD; + } + rst_val = msm_vfe32_reset_values[reset_type]; + init_completion(&vfe_dev->reset_complete); + if (blocking) { + msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4); + rc = wait_for_completion_timeout( + &vfe_dev->reset_complete, msecs_to_jiffies(50)); + } else { + msm_camera_io_w_mb(0x3EF, vfe_dev->vfe_base + 0x4); + } + return rc; +} + +static void msm_vfe32_axi_reload_wm( + struct vfe_device *vfe_dev, uint32_t reload_mask) +{ + if (!vfe_dev->pdev->dev.of_node) { + /*vfe32 A-family: 8960*/ + msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38); + } else { + /*vfe32 B-family: 8610*/ + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28); + msm_camera_io_w(0x1C800000, vfe_dev->vfe_base + 0x20); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18); + msm_camera_io_w(0x9AAAAAAA , vfe_dev->vfe_base + 0x600); + msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38); + } +} + +static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable) +{ + uint32_t val = msm_camera_io_r( + vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); + if (enable) + val |= 0x1; + else + val &= ~0x1; + msm_camera_io_w_mb(val, + vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx)); +} + +static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask |= BIT(comp_mask_index + 21); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x34); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask &= ~BIT(comp_mask_index + 21); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask |= BIT(stream_info->wm[0] + 6); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask &= ~BIT(stream_info->wm[0] + 6); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); +} + +static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t framedrop_pattern = 0, framedrop_period = 0; + + if (stream_info->runtime_init_frame_drop == 0) { + framedrop_pattern = stream_info->framedrop_pattern; + framedrop_period = stream_info->framedrop_period; + } + + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_burst_frame_count == 0) { + framedrop_pattern = 0; + framedrop_period = 0; + } + + if (stream_info->stream_src == PIX_ENCODER) { + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x504); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x508); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x50C); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x510); + } else if (stream_info->stream_src == PIX_VIEWFINDER) { + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x514); + msm_camera_io_w(framedrop_period, vfe_dev->vfe_base + 0x518); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x51C); + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + 0x520); + } + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x260); +} + +static void msm_vfe32_clear_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + if (stream_info->stream_src == PIX_ENCODER) { + msm_camera_io_w(0, vfe_dev->vfe_base + 0x50C); + msm_camera_io_w(0, vfe_dev->vfe_base + 0x510); + } else if (stream_info->stream_src == PIX_VIEWFINDER) { + msm_camera_io_w(0, vfe_dev->vfe_base + 0x51C); + msm_camera_io_w(0, vfe_dev->vfe_base + 0x520); + } +} + +static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) +{ + int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0; + uint32_t io_format_reg; + bpp = msm_isp_get_bit_per_pixel(io_format); + if (bpp < 0) { + pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, + io_format, bpp); + return -EINVAL; + } + + switch (bpp) { + case 8: + bpp_reg = 0; + break; + case 10: + bpp_reg = 1 << 0; + break; + case 12: + bpp_reg = 1 << 1; + break; + default: + pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); + return -EINVAL; + } + + if (stream_src == IDEAL_RAW) { + pack_fmt = msm_isp_get_pack_format(io_format); + switch (pack_fmt) { + case QCOM: + pack_reg = 0x0; + break; + case MIPI: + pack_reg = 0x1; + break; + case DPCM6: + pack_reg = 0x2; + break; + case DPCM8: + pack_reg = 0x3; + break; + case PLAIN8: + pack_reg = 0x4; + break; + case PLAIN16: + pack_reg = 0x5; + break; + default: + pr_err("%s: invalid pack fmt!\n", __func__); + return -EINVAL; + } + } + + io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8); + switch (stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case CAMIF_RAW: + io_format_reg &= 0xFFFFCFFF; + io_format_reg |= bpp_reg << 12; + break; + case IDEAL_RAW: + io_format_reg &= 0xFFFFFFC8; + io_format_reg |= bpp_reg << 4 | pack_reg; + break; + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + default: + pr_err("%s: Invalid stream source\n", __func__); + return -EINVAL; + } + msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8); + return 0; +} + +static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg) +{ + uint16_t first_pixel, last_pixel, first_line, last_line; + struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; + uint32_t val; + + first_pixel = camif_cfg->first_pixel; + last_pixel = camif_cfg->last_pixel; + first_line = camif_cfg->first_line; + last_line = camif_cfg->last_line; + + msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, + vfe_dev->vfe_base + 0x14); + + msm_camera_io_w(camif_cfg->lines_per_frame << 16 | + camif_cfg->pixels_per_line, + vfe_dev->vfe_base + 0x1EC); + + msm_camera_io_w(first_pixel << 16 | last_pixel, + vfe_dev->vfe_base + 0x1F0); + + msm_camera_io_w(first_line << 16 | last_line, + vfe_dev->vfe_base + 0x1F4); + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x6FC); + val &= 0xFFFFFFFC; + val |= camif_cfg->camif_input; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x6FC); +} + +static void msm_vfe32_update_camif_state( + struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state) +{ + uint32_t val; + bool bus_en, vfe_en; + if (update_state == NO_UPDATE) + return; + + if (update_state == ENABLE_CAMIF) { + val = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + val |= 0x19; + msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x1C); + msm_camera_io_w_mb(0xA, vfe_dev->vfe_base + 0x200); + val = msm_camera_io_r(vfe_dev->vfe_base + 0x1E4); + bus_en = + ((vfe_dev->axi_data.src_info[ + VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); + vfe_en = + ((vfe_dev->axi_data.src_info[ + VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + val &= 0xFFFFFF3F; + val = val | bus_en << 7 | vfe_en << 6; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4); + msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x1E0); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1E0); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; + } else if (update_state == DISABLE_CAMIF) { + msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { + msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } +} + +static void msm_vfe32_cfg_rdi_reg(struct vfe_device *vfe_dev, + struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src) +{ + uint8_t rdi = input_src - VFE_RAW_0; + uint32_t rdi_reg_cfg; + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE32_RDI_BASE(0)); + rdi_reg_cfg &= ~(BIT(16 + rdi)); + rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); + msm_camera_io_w(rdi_reg_cfg, + vfe_dev->vfe_base + VFE32_RDI_BASE(0)); + + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE32_RDI_BASE(rdi)); + rdi_reg_cfg &= 0x70003; + rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; + msm_camera_io_w( + rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi)); + +} + +static void msm_vfe32_axi_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + uint32_t val; + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + + if (!stream_info->frame_based) { + /*WR_IMAGE_SIZE*/ + val = + ((msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width)+1)/2 - 1) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1); + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); + + /*WR_BUFFER_CFG*/ + val = + msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_stride) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1) << 4 | VFE32_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + } else { + msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); + val = + msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1) << 4 | VFE32_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + } + return; +} + +static void msm_vfe32_axi_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint32_t val = 0; + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + /* FRAME BASED */ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base); + /*WR_IMAGE_SIZE*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); + /*WR_BUFFER_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + return; +} + +static void msm_vfe32_axi_cfg_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + struct msm_vfe_axi_plane_cfg *plane_cfg = + &stream_info->plane_cfg[plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_cfg = 0; + uint32_t xbar_reg_cfg = 0; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: { + if (plane_cfg->output_plane_format != CRCB_PLANE && + plane_cfg->output_plane_format != CBCR_PLANE) { + /*SINGLE_STREAM_SEL*/ + xbar_cfg |= plane_cfg->output_plane_format << 5; + } else { + switch (stream_info->output_format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV16: + xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/ + break; + } + xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/ + } + if (stream_info->stream_src == PIX_VIEWFINDER) + xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ + break; + } + case CAMIF_RAW: + xbar_cfg = 0x60; + break; + case IDEAL_RAW: + xbar_cfg = 0x80; + break; + case RDI_INTF_0: + xbar_cfg = 0xA0; + break; + case RDI_INTF_1: + xbar_cfg = 0xC0; + break; + case RDI_INTF_2: + xbar_cfg = 0xE0; + break; + default: + pr_err("%s: Invalid stream src\n", __func__); + } + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm)); + xbar_reg_cfg |= (xbar_cfg << VFE32_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); + return; +} + +static void msm_vfe32_axi_clear_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_reg_cfg = 0; + + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFF << VFE32_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); +} + +static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t total_image_size = 0; + uint32_t num_used_wms = 0; + uint32_t prop_size = 0; + uint32_t wm_ub_size; + uint64_t delta; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i] > 0) { + num_used_wms++; + total_image_size += axi_data->wm_image_size[i]; + } + } + prop_size = MSM_ISP32_TOTAL_WM_UB - + axi_data->hw_info->min_wm_ub * num_used_wms; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + delta = + (uint64_t)(axi_data->wm_image_size[i] * + prop_size); + do_div(delta, total_image_size); + wm_ub_size = axi_data->hw_info->min_wm_ub + + (uint32_t)delta; + msm_camera_io_w(ub_offset << 16 | + (wm_ub_size - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += wm_ub_size; + } else { + msm_camera_io_w(0, + vfe_dev->vfe_base + VFE32_WM_BASE(i) + 0xC); + } + } +} + +static void msm_vfe32_cfg_axi_ub_equal_slicing(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + uint32_t final_ub_slice_size; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (ub_offset + VFE32_EQUAL_SLICE_UB > VFE32_AXI_SLICE_UB) { + final_ub_slice_size = VFE32_AXI_SLICE_UB - ub_offset; + msm_camera_io_w(ub_offset << 16 | + (final_ub_slice_size - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += final_ub_slice_size; + } else { + msm_camera_io_w(ub_offset << 16 | + (VFE32_EQUAL_SLICE_UB - 1), vfe_dev->vfe_base + + VFE32_WM_BASE(i) + 0xC); + ub_offset += VFE32_EQUAL_SLICE_UB; + } + } +} + +static void msm_vfe32_cfg_axi_ub(struct vfe_device *vfe_dev) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + axi_data->wm_ub_cfg_policy = MSM_WM_UB_EQUAL_SLICING; + if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) + msm_vfe32_cfg_axi_ub_equal_slicing(vfe_dev); + else + msm_vfe32_cfg_axi_ub_equal_default(vfe_dev); +} + +static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE32_PING_PONG_BASE(wm_idx, pingpong_status)); +} + +static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev, + uint32_t blocking) +{ + uint32_t halt_mask; + uint32_t axi_busy_flag = false; + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8); + if (blocking) { + axi_busy_flag = true; + } + while (axi_busy_flag) { + if (msm_camera_io_r( + vfe_dev->vfe_base + 0x1DC) & 0x1) + axi_busy_flag = false; + } + msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x1D8); + halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); + halt_mask &= 0xFEFFFFFF; + /* Disable AXI IRQ */ + msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x20); + return 0; +} + +static uint32_t msm_vfe32_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 6) & 0x7F; +} + +static uint32_t msm_vfe32_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 21) & 0x7; +} + +static uint32_t msm_vfe32_get_pingpong_status(struct vfe_device *vfe_dev) +{ + return msm_camera_io_r(vfe_dev->vfe_base + 0x180); +} + +static int msm_vfe32_get_stats_idx(enum msm_isp_stats_type stats_type) +{ + switch (stats_type) { + case MSM_ISP_STATS_AEC: + case MSM_ISP_STATS_BG: + return 0; + case MSM_ISP_STATS_AF: + case MSM_ISP_STATS_BF: + return 1; + case MSM_ISP_STATS_AWB: + return 2; + case MSM_ISP_STATS_RS: + return 3; + case MSM_ISP_STATS_CS: + return 4; + case MSM_ISP_STATS_IHIST: + return 5; + case MSM_ISP_STATS_SKIN: + case MSM_ISP_STATS_BHIST: + return 6; + default: + pr_err("%s: Invalid stats type\n", __func__); + return -EINVAL; + } +} + +static int msm_vfe32_stats_check_streams( + struct msm_vfe_stats_stream *stream_info) +{ + return 0; +} + +static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + return; +} + +static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); + return; +} + +static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + irq_mask &= ~(BIT(STATS_IDX(stream_info->stream_handle) + 13)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); + return; +} + +static void msm_vfe32_stats_cfg_wm_reg(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + /*Nothing to configure for VFE3.x*/ + return; +} + +static void msm_vfe32_stats_clear_wm_reg(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + /*Nothing to configure for VFE3.x*/ + return; +} + +static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = VFE32_UB_SIZE; + uint32_t ub_size[VFE32_NUM_STATS_TYPE] = { + 107, /*MSM_ISP_STATS_BG*/ + 92, /*MSM_ISP_STATS_BF*/ + 2, /*MSM_ISP_STATS_AWB*/ + 7, /*MSM_ISP_STATS_RS*/ + 16, /*MSM_ISP_STATS_CS*/ + 2, /*MSM_ISP_STATS_IHIST*/ + 7, /*MSM_ISP_STATS_BHIST*/ + }; + + for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) { + ub_offset -= ub_size[i]; + msm_camera_io_w(ub_offset << 16 | (ub_size[i] - 1), + vfe_dev->vfe_base + VFE32_STATS_BASE(i) + 0x8); + } + return; +} + +static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + int i; + uint32_t module_cfg, module_cfg_mask = 0; + + for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) { + if ((stats_mask >> i) & 0x1) { + switch (i) { + case 0: + case 1: + case 2: + case 3: + case 4: + module_cfg_mask |= 1 << (5 + i); + break; + case 5: + module_cfg_mask |= 1 << 16; + break; + case 6: + module_cfg_mask |= 1 << 19; + break; + default: + pr_err("%s: Invalid stats mask\n", __func__); + return; + } + } + } + + module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x10); + if (enable) + module_cfg |= module_cfg_mask; + else + module_cfg &= ~module_cfg_mask; + msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x10); +} + +static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, + dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + int stats_idx = STATS_IDX(stream_info->stream_handle); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); +} + +static uint32_t msm_vfe32_stats_get_wm_mask(uint32_t irq_status0, + uint32_t irq_status1) +{ + return (irq_status0 >> 13) & 0x7F; +} + +static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask) +{ + *overflow_mask = 0x002FFF7E; +} + +static void msm_vfe32_get_irq_mask(struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask) +{ + *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); + *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20); +} + +static void msm_vfe32_restore_irq_mask(struct vfe_device *vfe_dev) +{ + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0, + vfe_dev->vfe_base + 0x1C); + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1, + vfe_dev->vfe_base + 0x20); +} + +static void msm_vfe32_get_halt_restart_mask(uint32_t *irq0_mask, + uint32_t *irq1_mask) +{ + *irq0_mask = 0x0; + *irq1_mask = 0x01800000; +} + +static uint32_t msm_vfe32_stats_get_comp_mask(uint32_t irq_status0, + uint32_t irq_status1) +{ + return (irq_status0 >> 24) & 0x1; +} + +static uint32_t msm_vfe32_stats_get_frame_id(struct vfe_device *vfe_dev) +{ + uint32_t session_id = 0; + session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + return vfe_dev->axi_data.frame_id[session_id]; +} + +static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev) +{ + int rc = 0; + vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_MEM, "vfe"); + if (!vfe_dev->vfe_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_IRQ, "vfe"); + if (!vfe_dev->vfe_irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); + if (IS_ERR(vfe_dev->fs_vfe)) { + pr_err("%s: Regulator get failed %ld\n", __func__, + PTR_ERR(vfe_dev->fs_vfe)); + vfe_dev->fs_vfe = NULL; + rc = -ENODEV; + goto vfe_no_resource; + } + + if (!vfe_dev->pdev->dev.of_node) + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr"); + else + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0"); + + if (!vfe_dev->iommu_ctx[0]) { + pr_err("%s: no iommux ctx resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + if (!vfe_dev->pdev->dev.of_node) + vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc"); + else + vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe0"); + + if (!vfe_dev->iommu_ctx[1]) { + pr_err("%s: no iommux ctx resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + +vfe_no_resource: + return rc; +} + +static void msm_vfe32_get_error_mask(uint32_t *error_mask0, + uint32_t *error_mask1) +{ + *error_mask0 = 0x00000000; + *error_mask1 = 0x007FFFFF; +} + +struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = { + .num_wm = 5, + .num_comp_mask = 3, + .num_rdi = 3, + .num_rdi_master = 3, + .min_wm_ub = 64, +}; + +static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = { + .stats_capability_mask = + 1 << MSM_ISP_STATS_AEC | 1 << MSM_ISP_STATS_BG | + 1 << MSM_ISP_STATS_AF | 1 << MSM_ISP_STATS_BF | + 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | + 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | + 1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST, + .stats_ping_pong_offset = stats_pingpong_offset_map, + .num_stats_type = VFE32_NUM_STATS_TYPE, + .num_stats_comp_mask = 0, +}; + +static struct v4l2_subdev_core_ops msm_vfe32_subdev_core_ops = { + .ioctl = msm_isp_ioctl, + .subscribe_event = msm_isp_subscribe_event, + .unsubscribe_event = msm_isp_unsubscribe_event, +}; + +static struct v4l2_subdev_ops msm_vfe32_subdev_ops = { + .core = &msm_vfe32_subdev_core_ops, +}; + +static struct v4l2_subdev_internal_ops msm_vfe32_internal_ops = { + .open = msm_isp_open_node, + .close = msm_isp_close_node, +}; + +struct msm_vfe_hardware_info vfe32_hw_info = { + .num_iommu_ctx = 2, + .vfe_clk_idx = VFE32_CLK_IDX, + .vfe_ops = { + .irq_ops = { + .read_irq_status = msm_vfe32_read_irq_status, + .process_camif_irq = msm_vfe32_process_camif_irq, + .process_reset_irq = msm_vfe32_process_reset_irq, + .process_halt_irq = msm_vfe32_process_halt_irq, + .process_reg_update = msm_vfe32_process_reg_update, + .process_epoch_irq = msm_vfe32_process_epoch_irq, + .process_axi_irq = msm_isp_process_axi_irq, + .process_stats_irq = msm_isp_process_stats_irq, + }, + .axi_ops = { + .reload_wm = msm_vfe32_axi_reload_wm, + .enable_wm = msm_vfe32_axi_enable_wm, + .cfg_io_format = msm_vfe32_cfg_io_format, + .cfg_comp_mask = msm_vfe32_axi_cfg_comp_mask, + .clear_comp_mask = msm_vfe32_axi_clear_comp_mask, + .cfg_wm_irq_mask = msm_vfe32_axi_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe32_axi_clear_wm_irq_mask, + .cfg_framedrop = msm_vfe32_cfg_framedrop, + .clear_framedrop = msm_vfe32_clear_framedrop, + .cfg_wm_reg = msm_vfe32_axi_cfg_wm_reg, + .clear_wm_reg = msm_vfe32_axi_clear_wm_reg, + .cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg, + .clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg, + .cfg_ub = msm_vfe32_cfg_axi_ub, + .update_ping_pong_addr = + msm_vfe32_update_ping_pong_addr, + .get_comp_mask = msm_vfe32_get_comp_mask, + .get_wm_mask = msm_vfe32_get_wm_mask, + .get_pingpong_status = msm_vfe32_get_pingpong_status, + .halt = msm_vfe32_axi_halt, + }, + .core_ops = { + .reg_update = msm_vfe32_reg_update, + .cfg_camif = msm_vfe32_cfg_camif, + .update_camif_state = msm_vfe32_update_camif_state, + .cfg_rdi_reg = msm_vfe32_cfg_rdi_reg, + .reset_hw = msm_vfe32_reset_hardware, + .init_hw = msm_vfe32_init_hardware, + .init_hw_reg = msm_vfe32_init_hardware_reg, + .release_hw = msm_vfe32_release_hardware, + .get_platform_data = msm_vfe32_get_platform_data, + .get_error_mask = msm_vfe32_get_error_mask, + .get_overflow_mask = msm_vfe32_get_overflow_mask, + .get_irq_mask = msm_vfe32_get_irq_mask, + .restore_irq_mask = msm_vfe32_restore_irq_mask, + .get_halt_restart_mask = + msm_vfe32_get_halt_restart_mask, + .process_error_status = msm_vfe32_process_error_status, + }, + .stats_ops = { + .get_stats_idx = msm_vfe32_get_stats_idx, + .check_streams = msm_vfe32_stats_check_streams, + .cfg_comp_mask = msm_vfe32_stats_cfg_comp_mask, + .cfg_wm_irq_mask = msm_vfe32_stats_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe32_stats_clear_wm_irq_mask, + .cfg_wm_reg = msm_vfe32_stats_cfg_wm_reg, + .clear_wm_reg = msm_vfe32_stats_clear_wm_reg, + .cfg_ub = msm_vfe32_stats_cfg_ub, + .enable_module = msm_vfe32_stats_enable_module, + .update_ping_pong_addr = + msm_vfe32_stats_update_ping_pong_addr, + .get_comp_mask = msm_vfe32_stats_get_comp_mask, + .get_wm_mask = msm_vfe32_stats_get_wm_mask, + .get_frame_id = msm_vfe32_stats_get_frame_id, + .get_pingpong_status = msm_vfe32_get_pingpong_status, + }, + }, + .dmi_reg_offset = 0x5A0, + .axi_hw_info = &msm_vfe32_axi_hw_info, + .stats_hw_info = &msm_vfe32_stats_hw_info, + .subdev_ops = &msm_vfe32_subdev_ops, + .subdev_internal_ops = &msm_vfe32_internal_ops, +}; +EXPORT_SYMBOL(vfe32_hw_info); diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp32.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp32.h new file mode 100644 index 0000000000000000000000000000000000000000..05350486271dbe33ab24ec52f947763f35d2f5ca --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp32.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_ISP32_H__ +#define __MSM_ISP32_H__ + +extern struct msm_vfe_hardware_info vfe32_hw_info; +#endif /* __MSM_ISP32_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp40.c new file mode 100644 index 0000000000000000000000000000000000000000..fbebeadda9e4c7f84cbd1370808942ae523f820b --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp40.c @@ -0,0 +1,1862 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include "msm_isp40.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_isp.h" +#include "msm.h" +#include "msm_camera_io_util.h" + +/*#define CONFIG_MSM_ISP_DBG*/ +#undef CDBG +#ifdef CONFIG_MSM_ISP_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +#define VFE40_BURST_LEN 1 +#define VFE40_BURST_LEN_8916_VERSION 2 +#define VFE40_STATS_BURST_LEN 1 +#define VFE40_STATS_BURST_LEN_8916_VERSION 2 +#define VFE40_UB_SIZE 1536 /* 1536 * 128 bits = 24KB */ +#define VFE40_UB_SIZE_8916 2048 /* 2048 * 128 bits = 32KB */ +#define VFE40_EQUAL_SLICE_UB 190 /* (UB_SIZE - STATS SIZE)/6 */ +#define VFE40_EQUAL_SLICE_UB_8916 276 +#define VFE40_TOTAL_WM_UB 1144 /* UB_SIZE - STATS SIZE */ +#define VFE40_TOTAL_WM_UB_8916 1656 + + +/* STATS_SIZE (BE + BG + BF+ RS + CS + IHIST + BHIST ) = 392 */ +#define VFE40_STATS_SIZE 392 +#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx) +#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx) +#define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2)) +#define VFE40_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0) +#define VFE40_PING_PONG_BASE(wm, ping_pong) \ + (VFE40_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) + +static uint8_t stats_pingpong_offset_map[] = { + 8, 9, 10, 11, 12, 13, 14, 15}; + +#define VFE40_NUM_STATS_TYPE 8 +#define VFE40_STATS_BASE(idx) (0x168 + 0x18 * idx) +#define VFE40_STATS_PING_PONG_BASE(idx, ping_pong) \ + (VFE40_STATS_BASE(idx) + 0x4 * \ + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) + +#define VFE40_VBIF_CLKON 0x4 +#define VFE40_VBIF_FIXED_SORT_EN 0x30 +#define VFE40_VBIF_FIXED_SORT_SEL0 0x34 +#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0 +#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4 +#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8 +#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0 +#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4 +#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8 +#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0 +#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4 +#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8 +#define VFE40_VBIF_OCMEM_OUT_MAX_BURST 0xDC +#define VFE40_VBIF_ARB_CTL 0xF0 +#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124 +#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 +#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 +#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178 +#define VFE40_VBIF_OUT_AXI_AOOO 0x17C + +#define VFE40_BUS_BDG_QOS_CFG_0 0x000002C4 +#define VFE40_BUS_BDG_QOS_CFG_1 0x000002C8 +#define VFE40_BUS_BDG_QOS_CFG_2 0x000002CC +#define VFE40_BUS_BDG_QOS_CFG_3 0x000002D0 +#define VFE40_BUS_BDG_QOS_CFG_4 0x000002D4 +#define VFE40_BUS_BDG_QOS_CFG_5 0x000002D8 +#define VFE40_BUS_BDG_QOS_CFG_6 0x000002DC +#define VFE40_BUS_BDG_QOS_CFG_7 0x000002E0 + +#define VFE40_CLK_IDX 1 +/*Iterations for averaging outstanding writes counts*/ +#define MAX_NUM_FRAMES 10 +/* Maximum outstanding writes to avoid image master bus +overflows*/ +#define MAX_OUT_WRITES_LEVEL 4000000 + +static struct msm_cam_clk_info msm_vfe40_clk_info[VFE_CLK_INFO_MAX]; + +static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev) +{ + void __iomem *vfebase = vfe_dev->vfe_base; + + if (vfe_dev->vfe_hw_version == VFE40_8974V1_VERSION || + vfe_dev->vfe_hw_version == VFE40_8x26_VERSION || + vfe_dev->vfe_hw_version == VFE40_8x26V2_VERSION) { + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7); + } else if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION || + vfe_dev->vfe_hw_version == VFE40_8974V3_VERSION) { + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7); + } else if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION || + vfe_dev->vfe_hw_version == VFE40_8939_VERSION) { + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xAAA5AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0001AAA5, vfebase + VFE40_BUS_BDG_QOS_CFG_7); + } else { + BUG(); + pr_err("%s: QOS is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + } +} + +static void msm_vfe40_init_vbif_parms_8974_v1(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x1, + vfe_vbif_base + VFE40_VBIF_CLKON); + msm_camera_io_w(0x01010101, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x01010101, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10010110, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2); + msm_camera_io_w(0x00001010, + vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); + msm_camera_io_w(0x00001010, + vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST); + msm_camera_io_w(0x00000030, + vfe_vbif_base + VFE40_VBIF_ARB_CTL); + msm_camera_io_w(0x00000FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); + msm_camera_io_w(0x0FFF0FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); + msm_camera_io_w(0x00000001, + vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); + msm_camera_io_w(0x22222222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); + msm_camera_io_w(0x00002222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1); + return; +} + +static void msm_vfe40_init_vbif_parms_8974_v2(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x1, + vfe_vbif_base + VFE40_VBIF_CLKON); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_ARB_CTL); + msm_camera_io_w(0x00000FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); + msm_camera_io_w(0x0FFF0FFF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); + msm_camera_io_w(0x00000003, + vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); + msm_camera_io_w(0x22222222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); + msm_camera_io_w(0x00002222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1); + return; +} + +static void msm_vfe40_init_vbif_parms_8x26(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10101010, + vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0); + msm_camera_io_w(0x00000010, + vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0); + msm_camera_io_w(0x00000707, + vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST); + msm_camera_io_w(0x000000FF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN); + msm_camera_io_w(0x00FF00FF, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO); + msm_camera_io_w(0x00000003, + vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB); + msm_camera_io_w(0x22222222, + vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0); + return; +} + +static void msm_vfe40_init_vbif_parms_8939(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x00000fff, + vfe_vbif_base + VFE40_VBIF_FIXED_SORT_EN); + msm_camera_io_w(0x00555000, + vfe_vbif_base + VFE40_VBIF_FIXED_SORT_SEL0); + return; +} + +static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE40_8974V1_VERSION: + msm_vfe40_init_vbif_parms_8974_v1(vfe_dev); + break; + case VFE40_8974V2_VERSION: + case VFE40_8974V3_VERSION: + msm_vfe40_init_vbif_parms_8974_v2(vfe_dev); + break; + case VFE40_8x26_VERSION: + case VFE40_8x26V2_VERSION: + msm_vfe40_init_vbif_parms_8x26(vfe_dev); + break; + case VFE40_8916_VERSION: + /*Reset hardware values are correct vbif values. + So no need to set*/ + break; + case VFE40_8939_VERSION: + msm_vfe40_init_vbif_parms_8939(vfe_dev); + break; + default: + BUG(); + pr_err("%s: VBIF is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + } + +} + +static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev) +{ + int rc = -1; + rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (vfe_dev->fs_vfe) { + rc = regulator_enable(vfe_dev->fs_vfe); + if (rc) { + pr_err("%s: Regulator enable failed\n", __func__); + goto fs_failed; + } + } + + rc = msm_isp_get_clk_info(vfe_dev, vfe_dev->pdev, + &msm_vfe40_clk_info[0]); + if (rc < 0) { + pr_err("msm_isp_get_clk_info() failed\n"); + goto fs_failed; + } + + if (vfe_dev->num_clk <= 0) { + pr_err("%s: Invalid num of clock\n", __func__); + goto fs_failed; + } else { + vfe_dev->vfe_clk = + kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, + GFP_KERNEL); + if (!vfe_dev->vfe_clk) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + } + + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 1); + if (rc < 0) + goto clk_enable_failed; + + vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, + resource_size(vfe_dev->vfe_mem)); + if (!vfe_dev->vfe_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vfe_remap_failed; + } + + vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start, + resource_size(vfe_dev->vfe_vbif_mem)); + if (!vfe_dev->vfe_vbif_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vbif_remap_failed; + } + + rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, + IRQF_TRIGGER_RISING, "vfe", vfe_dev); + if (rc < 0) { + pr_err("%s: irq request failed\n", __func__); + goto irq_req_failed; + } + return rc; +irq_req_failed: + iounmap(vfe_dev->vfe_vbif_base); +vbif_remap_failed: + iounmap(vfe_dev->vfe_base); +vfe_remap_failed: + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); +clk_enable_failed: + if (vfe_dev->fs_vfe) + regulator_disable(vfe_dev->fs_vfe); + kfree(vfe_dev->vfe_clk); +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +bus_scale_register_failed: + return rc; +} + +static void msm_vfe40_release_hardware(struct vfe_device *vfe_dev) +{ + free_irq(vfe_dev->vfe_irq->start, vfe_dev); + tasklet_kill(&vfe_dev->vfe_tasklet); + iounmap(vfe_dev->vfe_vbif_base); + iounmap(vfe_dev->vfe_base); + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); + kfree(vfe_dev->vfe_clk); + regulator_disable(vfe_dev->fs_vfe); + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +} + +static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + msm_vfe40_init_qos_parms(vfe_dev); + msm_vfe40_init_vbif_parms(vfe_dev); + /* CGC_OVERRIDE */ + msm_camera_io_w(0x3FFFFFFF, vfe_dev->vfe_base + 0x14); + msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974); + /* BUS_CFG */ + msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); + msm_camera_io_w(0xE00000F3, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x2C); + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); + msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34); + /* Enable EPOCH IRQ for 100 frame lines*/ + irq_mask |= BIT(3); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); + msm_camera_io_w(0x64, vfe_dev->vfe_base + 0x318); + msm_camera_io_w(vfe_dev->stats_data.stats_mask, + vfe_dev->vfe_base + 0x44); + +} + +static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status0 & (1 << 31)) + complete(&vfe_dev->reset_complete); +} + +static void msm_vfe40_process_halt_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status1 & (1 << 8)) + complete(&vfe_dev->halt_complete); +} + +static void msm_vfe40_process_epoch_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0xc)) + return; + if (irq_status0 & (1 << 2)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); +} + +static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int cnt; + + if (!(irq_status0 & 0xF)) + return; + + if (irq_status0 & (1 << 0)) { + ISP_DBG("%s: SOF IRQ\n", __func__); + cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count; + if (cnt > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0].pix_stream_count == 0) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + } + } + if (irq_status0 & (1 << 1)) + ISP_DBG("%s: EOF IRQ\n", __func__); + if (irq_status0 & (1 << 2)) + ISP_DBG("%s: EPOCH0 IRQ\n", __func__); + if (irq_status0 & (1 << 3)) { + ISP_DBG("%s: EPOCH1 IRQ\n", __func__); + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { + vfe_dev->hw_info->vfe_ops.core_ops. + vbif_read_counters(vfe_dev); + } + } +} + +static void msm_vfe40_process_violation_status( + struct vfe_device *vfe_dev) +{ + uint32_t violation_status = vfe_dev->error_info.violation_status; + if (!violation_status) + return; + + if (violation_status & (1 << 0)) + pr_err("%s: camif violation\n", __func__); + if (violation_status & (1 << 1)) + pr_err("%s: black violation\n", __func__); + if (violation_status & (1 << 2)) + pr_err("%s: rolloff violation\n", __func__); + if (violation_status & (1 << 3)) + pr_err("%s: demux violation\n", __func__); + if (violation_status & (1 << 4)) + pr_err("%s: demosaic violation\n", __func__); + if (violation_status & (1 << 5)) + pr_err("%s: wb violation\n", __func__); + if (violation_status & (1 << 6)) + pr_err("%s: clf violation\n", __func__); + if (violation_status & (1 << 7)) + pr_err("%s: color correct violation\n", __func__); + if (violation_status & (1 << 8)) + pr_err("%s: rgb lut violation\n", __func__); + if (violation_status & (1 << 9)) + pr_err("%s: la violation\n", __func__); + if (violation_status & (1 << 10)) + pr_err("%s: chroma enhance violation\n", __func__); + if (violation_status & (1 << 11)) + pr_err("%s: chroma supress mce violation\n", __func__); + if (violation_status & (1 << 12)) + pr_err("%s: skin enhance violation\n", __func__); + if (violation_status & (1 << 13)) + pr_err("%s: color tranform enc violation\n", __func__); + if (violation_status & (1 << 14)) + pr_err("%s: color tranform view violation\n", __func__); + if (violation_status & (1 << 15)) + pr_err("%s: scale enc y violation\n", __func__); + if (violation_status & (1 << 16)) + pr_err("%s: scale enc cbcr violation\n", __func__); + if (violation_status & (1 << 17)) + pr_err("%s: scale view y violation\n", __func__); + if (violation_status & (1 << 18)) + pr_err("%s: scale view cbcr violation\n", __func__); + if (violation_status & (1 << 19)) + pr_err("%s: asf enc violation\n", __func__); + if (violation_status & (1 << 20)) + pr_err("%s: asf view violation\n", __func__); + if (violation_status & (1 << 21)) + pr_err("%s: crop enc y violation\n", __func__); + if (violation_status & (1 << 22)) + pr_err("%s: crop enc cbcr violation\n", __func__); + if (violation_status & (1 << 23)) + pr_err("%s: crop view y violation\n", __func__); + if (violation_status & (1 << 24)) + pr_err("%s: crop view cbcr violation\n", __func__); + if (violation_status & (1 << 25)) + pr_err("%s: realign buf y violation\n", __func__); + if (violation_status & (1 << 26)) + pr_err("%s: realign buf cb violation\n", __func__); + if (violation_status & (1 << 27)) + pr_err("%s: realign buf cr violation\n", __func__); +} + +static void msm_vfe40_process_error_status(struct vfe_device *vfe_dev) +{ + uint32_t error_status1 = vfe_dev->error_info.error_mask1; + if (error_status1 & (1 << 0)) + pr_err_ratelimited("%s: camif error status: 0x%x\n", + __func__, vfe_dev->error_info.camif_status); + if (error_status1 & (1 << 1)) + pr_err_ratelimited("%s: stats bhist overwrite\n", __func__); + if (error_status1 & (1 << 2)) + pr_err_ratelimited("%s: stats cs overwrite\n", __func__); + if (error_status1 & (1 << 3)) + pr_err_ratelimited("%s: stats ihist overwrite\n", __func__); + if (error_status1 & (1 << 4)) + pr_err_ratelimited("%s: realign buf y overflow\n", __func__); + if (error_status1 & (1 << 5)) + pr_err_ratelimited("%s: realign buf cb overflow\n", __func__); + if (error_status1 & (1 << 6)) + pr_err_ratelimited("%s: realign buf cr overflow\n", __func__); + if (error_status1 & (1 << 7)) { + pr_err_ratelimited("%s: violation\n", __func__); + msm_vfe40_process_violation_status(vfe_dev); + } + if (error_status1 & (1 << 9)) { + vfe_dev->stats->imagemaster0_overflow++; + pr_err_ratelimited("%s: image master 0 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 10)) { + vfe_dev->stats->imagemaster1_overflow++; + pr_err_ratelimited("%s: image master 1 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 11)) { + vfe_dev->stats->imagemaster2_overflow++; + pr_err_ratelimited("%s: image master 2 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 12)) { + vfe_dev->stats->imagemaster3_overflow++; + pr_err_ratelimited("%s: image master 3 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 13)) { + vfe_dev->stats->imagemaster4_overflow++; + pr_err_ratelimited("%s: image master 4 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 14)) { + vfe_dev->stats->imagemaster5_overflow++; + pr_err_ratelimited("%s: image master 5 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 15)) { + vfe_dev->stats->imagemaster6_overflow++; + pr_err_ratelimited("%s: image master 6 bus overflow\n", + __func__); + } + if (error_status1 & (1 << 16)) { + vfe_dev->stats->be_overflow++; + pr_err_ratelimited("%s: status be bus overflow\n", __func__); + } + if (error_status1 & (1 << 17)) { + vfe_dev->stats->bg_overflow++; + pr_err_ratelimited("%s: status bg bus overflow\n", __func__); + } + if (error_status1 & (1 << 18)) { + vfe_dev->stats->bf_overflow++; + pr_err_ratelimited("%s: status bf bus overflow\n", __func__); + } + if (error_status1 & (1 << 19)) { + vfe_dev->stats->awb_overflow++; + pr_err_ratelimited("%s: status awb bus overflow\n", __func__); + } + if (error_status1 & (1 << 20)) { + vfe_dev->stats->rs_overflow++; + pr_err_ratelimited("%s: status rs bus overflow\n", __func__); + } + if (error_status1 & (1 << 21)) { + vfe_dev->stats->cs_overflow++; + pr_err_ratelimited("%s: status cs bus overflow\n", __func__); + } + if (error_status1 & (1 << 22)) { + vfe_dev->stats->ihist_overflow++; + pr_err_ratelimited("%s: status ihist bus overflow\n", __func__); + } + if (error_status1 & (1 << 23)) { + vfe_dev->stats->skinbhist_overflow++; + pr_err_ratelimited("%s: status skin bhist bus overflow\n", + __func__); + } +} + +static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38); + *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C); + /* + * Ignore composite 2/3 irq which is used for dual VFE only + */ + + if (*irq_status0 & 0x6000000) + *irq_status0 &= ~(0x18000000); + msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30); + msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34); + msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24); + if (*irq_status0 & 0x18000000) { + pr_err_ratelimited("%s: Protection triggered\n", __func__); + *irq_status0 &= ~(0x18000000); + } + + if (*irq_status1 & (1 << 0)) + vfe_dev->error_info.camif_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x31C); + + if (*irq_status1 & (1 << 7)) + vfe_dev->error_info.violation_status |= + msm_camera_io_r(vfe_dev->vfe_base + 0x48); + +} + +static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + uint8_t input_src = 0x0; + if (!(irq_status0 & 0xF0)) + return; + + if (irq_status0 & BIT(4)) { + msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + input_src |= (1 << VFE_PIX_0); + } + if (irq_status0 & BIT(5)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + input_src |= (1 << VFE_RAW_0); + } + if (irq_status0 & BIT(6)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + input_src |= (1 << VFE_RAW_1); + } + if (irq_status0 & BIT(7)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + input_src |= (1 << VFE_RAW_2); + } + + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->stats_data.stats_update)) + msm_isp_stats_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) + msm_isp_axi_cfg_update(vfe_dev); + if (vfe_dev->axi_data.stream_update || atomic_read(&vfe_dev->stats_data.stats_update) || atomic_read(&vfe_dev->axi_data.axi_cfg_update)) { + if (input_src & (1 << VFE_PIX_0)) { + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, (1 << VFE_PIX_0)); + } + } + msm_isp_update_framedrop_reg(vfe_dev); + msm_isp_update_error_frame_count(vfe_dev); + if ((input_src & (1 << VFE_RAW_0)) || (input_src & (1 << VFE_RAW_1)) || (input_src & (1 << VFE_RAW_2))) { + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, input_src); + } + return; +} + +static void msm_vfe40_reg_update(struct vfe_device *vfe_dev, uint32_t input_src) +{ + msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x378); +} + +static uint32_t msm_vfe40_reset_values[ISP_RST_MAX] = +{ + 0x1FF, /* ISP_RST_HARD reset everything */ + 0x1EF /* ISP_RST_SOFT all modules without registers */ +}; + + +static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev , + enum msm_isp_reset_type reset_type, uint32_t blocking) +{ + uint32_t rst_val; + long rc = 0; + if (reset_type >= ISP_RST_MAX) { + pr_err("%s: Error Invalid parameter\n", __func__); + reset_type = ISP_RST_HARD; + } + rst_val = msm_vfe40_reset_values[reset_type]; + init_completion(&vfe_dev->reset_complete); + if (blocking) { + msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC); + rc = wait_for_completion_timeout( + &vfe_dev->reset_complete, msecs_to_jiffies(1000)); + } else { + msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC); + } + return rc; +} + +static void msm_vfe40_axi_reload_wm( + struct vfe_device *vfe_dev, uint32_t reload_mask) +{ + msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x4C); +} + +static void msm_vfe40_axi_enable_wm(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable) +{ + uint32_t val; + val = msm_camera_io_r(vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx)); + if (enable) + val |= 0x1; + else + val &= ~0x1; + msm_camera_io_w_mb(val, + vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx)); +} + +static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << (comp_mask_index * 8)); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (comp_mask_index + 25); + + /* + * For dual VFE, composite 2/3 interrupt is used to trigger + * microcontroller to update certain VFE registers + */ + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_VIEWFINDER) { + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 16); + irq_mask |= BIT(27); + } + + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_ENCODER) { + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 24); + irq_mask |= BIT(28); + } + + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (comp_mask_index + 25)); + + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_VIEWFINDER) { + comp_mask &= ~(axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 16); + irq_mask &= ~BIT(27); + } + + if (stream_info->plane_cfg[0].plane_addr_offset && + stream_info->stream_src == PIX_ENCODER) { + comp_mask &= ~(axi_data->composite_info[comp_mask_index]. + stream_composite_mask << 24); + irq_mask &= ~BIT(28); + } + + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (stream_info->wm[0] + 8); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (stream_info->wm[0] + 8)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_init_vbif_cntrs(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE40_8916_VERSION: + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); + + msm_camera_io_w(0x15, vfe_dev->vfe_vbif_base + 0x340); + msm_camera_io_w(0x40, vfe_dev->vfe_vbif_base + 0x344); + msm_camera_io_w(0x78, vfe_dev->vfe_vbif_base + 0x348); + + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x300); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x304); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x308); + break; + default: + break; + } +} + +void msm_vfe40_vbif_clear_cnt(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE40_8916_VERSION: + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); + break; + default: + break; + } +} + +void msm_vfe40_vbif_read_cnt_epoch(struct vfe_device *vfe_dev) +{ + uint32_t vbif_cnt_0_l = 0; + uint32_t vbif_cnt_1_l = 0; + uint32_t vbif_cnt_2_l = 0; + struct msm_vbif_cntrs *vbif_cntrs = &vfe_dev->vbif_cntrs; + uint32_t session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + + if (vfe_dev->axi_data.frame_id[session_id]%2 > 0) { + /*Disable counters before reading*/ + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x300); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x304); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x308); + /*Read counters*/ + vbif_cnt_0_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x360); + vbif_cnt_1_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x364); + vbif_cnt_2_l = msm_camera_io_r(vfe_dev->vfe_vbif_base + 0x368); + /*clear counters*/ + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x320); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x324); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x328); + msm_camera_io_w(0x0, vfe_dev->vfe_vbif_base + 0x328); + /*Enable counters*/ + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x300); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x304); + msm_camera_io_w(0x1, vfe_dev->vfe_vbif_base + 0x308); + + vbif_cntrs->total_vbif_cnt_2 += vbif_cnt_2_l; + vbif_cntrs->vfe_total_iter++; + + ISP_DBG("%s: VBIF cntr0 = %d, cntr1 = %d, cntr 2 = %d", + __func__, vbif_cnt_0_l, vbif_cnt_1_l, vbif_cnt_2_l); + + if ((vbif_cnt_2_l > 0) & (vbif_cntrs->previous_write_val > 0)) { + if ((vbif_cnt_2_l > (10 * + vbif_cntrs->previous_write_val)) + | (vbif_cnt_2_l > MAX_OUT_WRITES_LEVEL)) + vbif_cntrs->fb_err_lvl = 3; + else if (vbif_cnt_2_l > (5 * + vbif_cntrs->previous_write_val)) + vbif_cntrs->fb_err_lvl = 2; + else if (vbif_cnt_2_l > (2 * + (vbif_cntrs->previous_write_val))) + vbif_cntrs->fb_err_lvl = 1; + else + vbif_cntrs->fb_err_lvl = 0; + } + if ((vbif_cntrs->previous_write_val == 0) & + (vbif_cnt_2_l > 0)) { + vbif_cntrs->previous_write_val = vbif_cnt_2_l; + } + + if (vbif_cntrs->vfe_total_iter == MAX_NUM_FRAMES) { + vbif_cntrs->previous_write_val = + (vbif_cntrs->total_vbif_cnt_2)/MAX_NUM_FRAMES; + vbif_cntrs->vfe_total_iter = 0; + vbif_cntrs->total_vbif_cnt_2 = 0; + } + } +} + +static void msm_vfe40_cfg_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i, temp; + uint32_t framedrop_pattern = 0, framedrop_period = 0; + + if (stream_info->runtime_init_frame_drop == 0) { + framedrop_pattern = stream_info->framedrop_pattern; + framedrop_period = stream_info->framedrop_period; + } + + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_burst_frame_count == 0) { + framedrop_pattern = 0; + framedrop_period = 0; + } + + for (i = 0; i < stream_info->num_planes; i++) { + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + + VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); + temp = msm_camera_io_r(vfe_dev->vfe_base + + VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + temp &= 0xFFFFFF83; + msm_camera_io_w(temp | framedrop_period << 2, + vfe_dev->vfe_base + VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + } + + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378); +} + +static void msm_vfe40_clear_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i; + for (i = 0; i < stream_info->num_planes; i++) + msm_camera_io_w(0, vfe_dev->vfe_base + + VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); +} + +static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) +{ + int bpp, bpp_reg = 0, pack_reg = 0; + enum msm_isp_pack_fmt pack_fmt = 0; + uint32_t io_format_reg; /*io format register bit*/ + bpp = msm_isp_get_bit_per_pixel(io_format); + if (bpp < 0) { + pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, + io_format, bpp); + return -EINVAL; + } + + switch (bpp) { + case 8: + bpp_reg = 0; + break; + case 10: + bpp_reg = 1 << 0; + break; + case 12: + bpp_reg = 1 << 1; + break; + default: + pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); + return -EINVAL; + } + + if (stream_src == IDEAL_RAW) { + /*use io_format(v4l2_pix_fmt) to get pack format*/ + pack_fmt = msm_isp_get_pack_format(io_format); + switch (pack_fmt) { + case QCOM: + pack_reg = 0x0; + break; + case MIPI: + pack_reg = 0x1; + break; + case DPCM6: + pack_reg = 0x2; + break; + case DPCM8: + pack_reg = 0x3; + break; + case PLAIN8: + pack_reg = 0x4; + break; + case PLAIN16: + pack_reg = 0x5; + break; + default: + pr_err("%s: invalid pack fmt!\n", __func__); + return -EINVAL; + } + } + + io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54); + switch (stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case CAMIF_RAW: + io_format_reg &= 0xFFFFCFFF; + io_format_reg |= bpp_reg << 12; + break; + case IDEAL_RAW: + io_format_reg &= 0xFFFFFFC8; + io_format_reg |= bpp_reg << 4 | pack_reg; + break; + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + default: + pr_err("%s: Invalid stream source\n", __func__); + return -EINVAL; + } + msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54); + return 0; +} + +static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg) +{ + uint16_t first_pixel, last_pixel, first_line, last_line; + struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; + uint32_t val; + + first_pixel = camif_cfg->first_pixel; + last_pixel = camif_cfg->last_pixel; + first_line = camif_cfg->first_line; + last_line = camif_cfg->last_line; + + msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, + vfe_dev->vfe_base + 0x1C); + + msm_camera_io_w(camif_cfg->lines_per_frame << 16 | + camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300); + + msm_camera_io_w(first_pixel << 16 | last_pixel, + vfe_dev->vfe_base + 0x304); + + msm_camera_io_w(first_line << 16 | last_line, + vfe_dev->vfe_base + 0x308); + + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314); + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8); + val |= camif_cfg->camif_input; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8); + + switch (pix_cfg->input_mux) { + case CAMIF: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F4); + break; + case TESTGEN: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x93C); + break; + case EXTERNAL_READ: + default: + pr_err("%s: not supported input_mux %d\n", + __func__, pix_cfg->input_mux); + break; + } +} + +static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state) +{ + uint32_t val; + bool bus_en, vfe_en; + if (update_state == NO_UPDATE) + return; + + if (update_state == ENABLE_CAMIF) { + val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + val |= 0xF7; + msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318); + + bus_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); + vfe_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); + val &= 0xFFFFFF3F; + val = val | bus_en << 7 | vfe_en << 6; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8); + msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x2F4); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; + } else if (update_state == DISABLE_CAMIF) { + msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { + msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } +} + +static void msm_vfe40_cfg_rdi_reg( + struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg, + enum msm_vfe_input_src input_src) +{ + uint8_t rdi = input_src - VFE_RAW_0; + uint32_t rdi_reg_cfg; + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE40_RDI_BASE(0)); + rdi_reg_cfg &= ~(BIT(16 + rdi)); + rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); + msm_camera_io_w(rdi_reg_cfg, + vfe_dev->vfe_base + VFE40_RDI_BASE(0)); + + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE40_RDI_BASE(rdi)); + rdi_reg_cfg &= 0x70003; + rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; + msm_camera_io_w( + rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi)); +} + +static void msm_vfe40_axi_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + uint32_t val; + uint32_t burst_len; + uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) + burst_len = VFE40_BURST_LEN_8916_VERSION; + else + burst_len = VFE40_BURST_LEN; + + if (!stream_info->frame_based) { + msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); + /*WR_IMAGE_SIZE*/ + val = + ((msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width)+1)/2 - 1) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1); + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + + /*WR_BUFFER_CFG*/ + val = + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_stride) << 16 | + (stream_info->plane_cfg[ + plane_idx].output_height - 1) << 4 | + burst_len; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } else { + msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); + val = + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_width) << 16 | + (stream_info->plane_cfg[ + plane_idx].output_height - 1) << 4 | + burst_len; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } + + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + wm_base + 0x20); + /* TD: Add IRQ subsample pattern */ + return; +} + +static void msm_vfe40_axi_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint32_t val = 0; + uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); + /*WR_IMAGE_SIZE*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + /*WR_BUFFER_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); + return; +} + +static void msm_vfe40_axi_cfg_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + struct msm_vfe_axi_plane_cfg *plane_cfg = + &stream_info->plane_cfg[plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_cfg = 0; + uint32_t xbar_reg_cfg = 0; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: { + if (plane_cfg->output_plane_format != CRCB_PLANE && + plane_cfg->output_plane_format != CBCR_PLANE) { + /*SINGLE_STREAM_SEL*/ + xbar_cfg |= plane_cfg->output_plane_format << 8; + } else { + switch (stream_info->output_format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV16: + xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/ + break; + } + xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/ + } + if (stream_info->stream_src == PIX_VIEWFINDER) + xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ + break; + } + case CAMIF_RAW: + xbar_cfg = 0x300; + break; + case IDEAL_RAW: + xbar_cfg = 0x400; + break; + case RDI_INTF_0: + xbar_cfg = 0x500; + break; + case RDI_INTF_1: + xbar_cfg = 0x600; + break; + case RDI_INTF_2: + xbar_cfg = 0x700; + break; + default: + pr_err("%s: Invalid stream src\n", __func__); + break; + } + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); + xbar_reg_cfg |= (xbar_cfg << VFE40_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); + return; +} + +static void msm_vfe40_axi_clear_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_reg_cfg = 0; + + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); +} + +static void msm_vfe40_cfg_axi_ub_equal_default( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = + &vfe_dev->axi_data; + uint32_t total_image_size = 0; + uint8_t num_used_wms = 0; + uint32_t prop_size = 0; + uint32_t wm_ub_size; + uint32_t total_wm_ub; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i] > 0) { + num_used_wms++; + total_image_size += axi_data->wm_image_size[i]; + } + } + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) + total_wm_ub = VFE40_TOTAL_WM_UB_8916; + else + total_wm_ub = VFE40_TOTAL_WM_UB; + + prop_size = total_wm_ub - + axi_data->hw_info->min_wm_ub * num_used_wms; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + uint64_t delta = 0; + uint64_t temp = (uint64_t)axi_data->wm_image_size[i] * + (uint64_t)prop_size; + do_div(temp, total_image_size); + delta = temp; + wm_ub_size = axi_data->hw_info->min_wm_ub + delta; + msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), + vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); + ub_offset += wm_ub_size; + } else + msm_camera_io_w(0, + vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); + } +} + +static void msm_vfe40_cfg_axi_ub_equal_slicing( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t equal_slice_ub; + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) + equal_slice_ub = VFE40_EQUAL_SLICE_UB_8916; + else + equal_slice_ub = VFE40_EQUAL_SLICE_UB; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + msm_camera_io_w(ub_offset << 16 | (equal_slice_ub - 1), + vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10); + ub_offset += equal_slice_ub; + } +} + +static void msm_vfe40_cfg_axi_ub(struct vfe_device *vfe_dev) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT; + if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) + msm_vfe40_cfg_axi_ub_equal_slicing(vfe_dev); + else + msm_vfe40_cfg_axi_ub_equal_default(vfe_dev); +} + +static void msm_vfe40_update_ping_pong_addr( + struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE40_PING_PONG_BASE(wm_idx, pingpong_status)); +} + +static long msm_vfe40_axi_halt(struct vfe_device *vfe_dev, + uint32_t blocking) +{ + long rc = 0; + /* Keep only restart mask and halt mask*/ + msm_camera_io_w(BIT(31), vfe_dev->vfe_base + 0x28); + msm_camera_io_w(BIT(8), vfe_dev->vfe_base + 0x2C); + /* Clear IRQ Status*/ + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); + msm_camera_io_w(0xFEFFFFFF, vfe_dev->vfe_base + 0x34); + init_completion(&vfe_dev->halt_complete); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); + if (blocking) { + atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); + rc = wait_for_completion_interruptible_timeout( + &vfe_dev->halt_complete, msecs_to_jiffies(500)); + } + return rc; +} + +static uint32_t msm_vfe40_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 8) & 0x7F; +} + +static void msm_vfe40_get_overflow_mask(uint32_t *overflow_mask) +{ + *overflow_mask = 0x00FFFE7E; +} + +static void msm_vfe40_get_irq_mask(struct vfe_device *vfe_dev, + uint32_t *irq0_mask, uint32_t *irq1_mask) +{ + *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); +} + +static void msm_vfe40_restore_irq_mask(struct vfe_device *vfe_dev) +{ + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0, + vfe_dev->vfe_base + 0x28); + msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1, + vfe_dev->vfe_base + 0x2C); +} + +static void msm_vfe40_get_halt_restart_mask(uint32_t *irq0_mask, + uint32_t *irq1_mask) +{ + *irq0_mask = BIT(31); + *irq1_mask = BIT(8); +} + +static uint32_t msm_vfe40_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 25) & 0xF; +} + +static uint32_t msm_vfe40_get_pingpong_status( + struct vfe_device *vfe_dev) +{ + return msm_camera_io_r(vfe_dev->vfe_base + 0x268); +} + +static int msm_vfe40_get_stats_idx(enum msm_isp_stats_type stats_type) +{ + switch (stats_type) { + case MSM_ISP_STATS_BE: + return 0; + case MSM_ISP_STATS_BG: + return 1; + case MSM_ISP_STATS_BF: + return 2; + case MSM_ISP_STATS_AWB: + return 3; + case MSM_ISP_STATS_RS: + return 4; + case MSM_ISP_STATS_CS: + return 5; + case MSM_ISP_STATS_IHIST: + return 6; + case MSM_ISP_STATS_BHIST: + return 7; + default: + pr_err("%s: Invalid stats type\n", __func__); + return -EINVAL; + } +} + +static int msm_vfe40_stats_check_streams( + struct msm_vfe_stats_stream *stream_info) +{ + return 0; +} + +static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + uint32_t reg_mask, comp_stats_mask; + uint32_t i = 0; + atomic_t *stats_comp; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + stats_mask = stats_mask & 0xFF; + + if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask > + MAX_NUM_STATS_COMP_MASK) { + pr_err("%s: num of comp masks %d exceed max %d\n", + __func__, + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask, + MAX_NUM_STATS_COMP_MASK); + return; + } + + for (i = 0; + i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) { + + reg_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x44); + comp_stats_mask = reg_mask & (STATS_COMP_BIT_MASK << (i*8)); + stats_comp = &stats_data->stats_comp_mask[i]; + + if (enable) { + if (comp_stats_mask) + continue; + + reg_mask |= (stats_mask << (16 + i*8)); + atomic_add(stats_mask, stats_comp); + } else { + /* + * Check if comp mask in reg is valid + * and contains this stat + */ + if (!comp_stats_mask || + !((comp_stats_mask >> (16 + i*8)) & + stats_mask)) + continue; + + atomic_sub(stats_mask, stats_comp); + reg_mask &= ~(stats_mask << (16 + i*8)); + } + ISP_DBG("%s: comp_mask: %x atomic stats[0]: %x %x\n", + __func__, reg_mask, + atomic_read(&stats_data->stats_comp_mask[0]), + atomic_read(&stats_data->stats_comp_mask[1])); + msm_camera_io_w(reg_mask, vfe_dev->vfe_base + 0x44); + vfe_dev->stats_data.stats_mask = reg_mask; + return; + } +} + +static void msm_vfe40_stats_cfg_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 16); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_stats_clear_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (STATS_IDX(stream_info->stream_handle) + 16)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe40_stats_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + + /*WR_ADDR_CFG*/ + msm_camera_io_w(stream_info->framedrop_period << 2, + vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(stream_info->framedrop_pattern, + vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe40_stats_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t val = 0; + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t ub_offset = vfe_dev->vfe_ub_size; + uint32_t stats_burst_len = stats_data->stats_burst_len; + + uint32_t ub_size[VFE40_NUM_STATS_TYPE] = { + 64, /*MSM_ISP_STATS_BE*/ + 128, /*MSM_ISP_STATS_BG*/ + 128, /*MSM_ISP_STATS_BF*/ + 16, /*MSM_ISP_STATS_AWB*/ + 8, /*MSM_ISP_STATS_RS*/ + 16, /*MSM_ISP_STATS_CS*/ + 16, /*MSM_ISP_STATS_IHIST*/ + 16, /*MSM_ISP_STATS_BHIST*/ + }; + + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { + stats_burst_len = VFE40_STATS_BURST_LEN_8916_VERSION; + ub_offset = VFE40_UB_SIZE_8916; + } else { + stats_burst_len = VFE40_STATS_BURST_LEN; + ub_offset = VFE40_UB_SIZE; + } + + for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) { + ub_offset -= ub_size[i]; + msm_camera_io_w(stats_burst_len << 30 | + ub_offset << 16 | (ub_size[i] - 1), + vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC); + } +} + +static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + int i; + uint32_t module_cfg, module_cfg_mask = 0; + + for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) { + if ((stats_mask >> i) & 0x1) { + switch (i) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + module_cfg_mask |= 1 << (5 + i); + break; + case 6: + module_cfg_mask |= 1 << 15; + break; + case 7: + module_cfg_mask |= 1 << 18; + break; + default: + pr_err("%s: Invalid stats mask\n", __func__); + return; + } + } + } + + module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18); + if (enable) + module_cfg |= module_cfg_mask; + else + module_cfg &= ~module_cfg_mask; + msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18); +} + +static void msm_vfe40_stats_update_ping_pong_addr( + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, + uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + int stats_idx = STATS_IDX(stream_info->stream_handle); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE40_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); +} + +static uint32_t msm_vfe40_stats_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 16) & 0xFF; +} + +static uint32_t msm_vfe40_stats_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 29) & 0x3; +} + +static uint32_t msm_vfe40_stats_get_frame_id( + struct vfe_device *vfe_dev) +{ + uint32_t session_id; + session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + return vfe_dev->axi_data.frame_id[session_id]; +} + +static int msm_vfe40_get_platform_data(struct vfe_device *vfe_dev) +{ + int rc = 0; + vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_MEM, "vfe"); + if (!vfe_dev->vfe_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_vbif_mem = platform_get_resource_byname( + vfe_dev->pdev, + IORESOURCE_MEM, "vfe_vbif"); + if (!vfe_dev->vfe_vbif_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_IRQ, "vfe"); + if (!vfe_dev->vfe_irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); + if (IS_ERR(vfe_dev->fs_vfe)) { + pr_err("%s: Regulator get failed %ld\n", __func__, + PTR_ERR(vfe_dev->fs_vfe)); + vfe_dev->fs_vfe = NULL; + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe"); + if (!vfe_dev->iommu_ctx[0]) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + +vfe_no_resource: + return rc; +} + +static void msm_vfe40_get_error_mask( + uint32_t *error_mask0, uint32_t *error_mask1) +{ + *error_mask0 = 0x00000000; + *error_mask1 = 0x00FFFEFF; +} + +static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = { + .num_wm = 7, + .num_comp_mask = 3, + .num_rdi = 3, + .num_rdi_master = 3, + .min_wm_ub = 64, +}; + +static struct msm_vfe_stats_hardware_info msm_vfe40_stats_hw_info = { + .stats_capability_mask = + 1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF | + 1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST | + 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | + 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS, + .stats_ping_pong_offset = stats_pingpong_offset_map, + .num_stats_type = VFE40_NUM_STATS_TYPE, + .num_stats_comp_mask = 2, +}; + +static struct v4l2_subdev_core_ops msm_vfe40_subdev_core_ops = { + .ioctl = msm_isp_ioctl, + .subscribe_event = msm_isp_subscribe_event, + .unsubscribe_event = msm_isp_unsubscribe_event, +}; + +static struct v4l2_subdev_ops msm_vfe40_subdev_ops = { + .core = &msm_vfe40_subdev_core_ops, +}; + +static struct v4l2_subdev_internal_ops msm_vfe40_internal_ops = { + .open = msm_isp_open_node, + .close = msm_isp_close_node, +}; + +struct msm_vfe_hardware_info vfe40_hw_info = { + .num_iommu_ctx = 1, + .vfe_clk_idx = VFE40_CLK_IDX, + .vfe_ops = { + .irq_ops = { + .read_irq_status = msm_vfe40_read_irq_status, + .process_camif_irq = msm_vfe40_process_camif_irq, + .process_reset_irq = msm_vfe40_process_reset_irq, + .process_halt_irq = msm_vfe40_process_halt_irq, + .process_reset_irq = msm_vfe40_process_reset_irq, + .process_reg_update = msm_vfe40_process_reg_update, + .process_epoch_irq = msm_vfe40_process_epoch_irq, + .process_axi_irq = msm_isp_process_axi_irq, + .process_stats_irq = msm_isp_process_stats_irq, + }, + .axi_ops = { + .reload_wm = msm_vfe40_axi_reload_wm, + .enable_wm = msm_vfe40_axi_enable_wm, + .cfg_io_format = msm_vfe40_cfg_io_format, + .cfg_comp_mask = msm_vfe40_axi_cfg_comp_mask, + .clear_comp_mask = msm_vfe40_axi_clear_comp_mask, + .cfg_wm_irq_mask = msm_vfe40_axi_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe40_axi_clear_wm_irq_mask, + .cfg_framedrop = msm_vfe40_cfg_framedrop, + .clear_framedrop = msm_vfe40_clear_framedrop, + .cfg_wm_reg = msm_vfe40_axi_cfg_wm_reg, + .clear_wm_reg = msm_vfe40_axi_clear_wm_reg, + .cfg_wm_xbar_reg = msm_vfe40_axi_cfg_wm_xbar_reg, + .clear_wm_xbar_reg = msm_vfe40_axi_clear_wm_xbar_reg, + .cfg_ub = msm_vfe40_cfg_axi_ub, + .update_ping_pong_addr = + msm_vfe40_update_ping_pong_addr, + .get_comp_mask = msm_vfe40_get_comp_mask, + .get_wm_mask = msm_vfe40_get_wm_mask, + .get_pingpong_status = msm_vfe40_get_pingpong_status, + .halt = msm_vfe40_axi_halt, + }, + .core_ops = { + .reg_update = msm_vfe40_reg_update, + .cfg_camif = msm_vfe40_cfg_camif, + .update_camif_state = msm_vfe40_update_camif_state, + .cfg_rdi_reg = msm_vfe40_cfg_rdi_reg, + .reset_hw = msm_vfe40_reset_hardware, + .init_hw = msm_vfe40_init_hardware, + .init_hw_reg = msm_vfe40_init_hardware_reg, + .release_hw = msm_vfe40_release_hardware, + .get_platform_data = msm_vfe40_get_platform_data, + .get_error_mask = msm_vfe40_get_error_mask, + .get_overflow_mask = msm_vfe40_get_overflow_mask, + .get_irq_mask = msm_vfe40_get_irq_mask, + .restore_irq_mask = msm_vfe40_restore_irq_mask, + .get_halt_restart_mask = + msm_vfe40_get_halt_restart_mask, + .process_error_status = msm_vfe40_process_error_status, + .init_vbif_counters = msm_vfe40_init_vbif_cntrs, + .vbif_clear_counters = msm_vfe40_vbif_clear_cnt, + .vbif_read_counters = msm_vfe40_vbif_read_cnt_epoch, + }, + .stats_ops = { + .get_stats_idx = msm_vfe40_get_stats_idx, + .check_streams = msm_vfe40_stats_check_streams, + .cfg_comp_mask = msm_vfe40_stats_cfg_comp_mask, + .cfg_wm_irq_mask = msm_vfe40_stats_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe40_stats_clear_wm_irq_mask, + .cfg_wm_reg = msm_vfe40_stats_cfg_wm_reg, + .clear_wm_reg = msm_vfe40_stats_clear_wm_reg, + .cfg_ub = msm_vfe40_stats_cfg_ub, + .enable_module = msm_vfe40_stats_enable_module, + .update_ping_pong_addr = + msm_vfe40_stats_update_ping_pong_addr, + .get_comp_mask = msm_vfe40_stats_get_comp_mask, + .get_wm_mask = msm_vfe40_stats_get_wm_mask, + .get_frame_id = msm_vfe40_stats_get_frame_id, + .get_pingpong_status = msm_vfe40_get_pingpong_status, + }, + }, + .dmi_reg_offset = 0x918, + .axi_hw_info = &msm_vfe40_axi_hw_info, + .stats_hw_info = &msm_vfe40_stats_hw_info, + .subdev_ops = &msm_vfe40_subdev_ops, + .subdev_internal_ops = &msm_vfe40_internal_ops, +}; +EXPORT_SYMBOL(vfe40_hw_info); diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp40.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp40.h new file mode 100644 index 0000000000000000000000000000000000000000..e9b151816a375fe19d0c59a2957b4c8796a3eee5 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp40.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_ISP40_H__ +#define __MSM_ISP40_H__ + +extern struct msm_vfe_hardware_info vfe40_hw_info; +#endif /* __MSM_ISP40_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp44.c new file mode 100644 index 0000000000000000000000000000000000000000..fe0b1db4858a3c49653017ba5ca45e71141aacc2 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp44.c @@ -0,0 +1,1509 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include + +#include "msm_isp44.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_isp.h" +#include "msm.h" +#include "msm_camera_io_util.h" + +/*#define CONFIG_MSM_ISP_DBG*/ +#undef CDBG +#ifdef CONFIG_MSM_ISP_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +#define STATS_IDX_BF_SCALE 0 +#define STATS_IDX_BE 1 +#define STATS_IDX_BG 2 +#define STATS_IDX_BF 3 +#define STATS_IDX_AWB 4 +#define STATS_IDX_RS 5 +#define STATS_IDX_CS 6 +#define STATS_IDX_IHIST 7 +#define STATS_IDX_BHIST 8 + +#define VFE44_8084V1_VERSION 0x4000000A + +#define VFE44_BURST_LEN 3 +#define VFE44_STATS_BURST_LEN 2 +#define VFE44_UB_SIZE 2048 +#define VFE44_EQUAL_SLICE_UB 228 +#define VFE44_WM_BASE(idx) (0x6C + 0x24 * idx) +#define VFE44_RDI_BASE(idx) (0x2E8 + 0x4 * idx) +#define VFE44_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2)) +#define VFE44_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0) +#define VFE44_PING_PONG_BASE(wm, ping_pong) \ + (VFE44_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1))) + +static uint8_t stats_pingpong_offset_map[] = { + 7, 8, 9, 10, 11, 12, 13, 14, 15}; + +#define SHIFT_BF_SCALE_BIT 1 +#define VFE44_NUM_STATS_COMP 2 +#define VFE44_NUM_STATS_TYPE 9 +#define VFE44_STATS_BASE(idx) \ + ((idx) == STATS_IDX_BF_SCALE ? 0xA0C : (0x168 + 0x18 * (idx-1))) +#define VFE44_STATS_PING_PONG_BASE(idx, ping_pong) \ + (VFE44_STATS_BASE(idx) + 0x4 * \ + (~(ping_pong >> (stats_pingpong_offset_map[idx])) & 0x1)) + +#define VFE44_VBIF_CLKON 0x4 +#define VFE44_VBIF_IN_RD_LIM_CONF0 0xB0 +#define VFE44_VBIF_IN_RD_LIM_CONF1 0xB4 +#define VFE44_VBIF_IN_RD_LIM_CONF2 0xB8 +#define VFE44_VBIF_IN_WR_LIM_CONF0 0xC0 +#define VFE44_VBIF_IN_WR_LIM_CONF1 0xC4 +#define VFE44_VBIF_IN_WR_LIM_CONF2 0xC8 +#define VFE44_VBIF_OUT_RD_LIM_CONF0 0xD0 +#define VFE44_VBIF_OUT_WR_LIM_CONF0 0xD4 +#define VFE44_VBIF_DDR_OUT_MAX_BURST 0xD8 +#define VFE44_VBIF_OCMEM_OUT_MAX_BURST 0xDC +#define VFE44_VBIF_ARB_CTL 0xF0 +#define VFE44_VBIF_ROUND_ROBIN_QOS_ARB 0x124 +#define VFE44_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 +#define VFE44_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 +#define VFE44_VBIF_OUT_AXI_AOOO_EN 0x178 +#define VFE44_VBIF_OUT_AXI_AOOO 0x17C + +#define VFE44_BUS_BDG_QOS_CFG_0 0x000002C4 +#define VFE44_BUS_BDG_QOS_CFG_1 0x000002C8 +#define VFE44_BUS_BDG_QOS_CFG_2 0x000002CC +#define VFE44_BUS_BDG_QOS_CFG_3 0x000002D0 +#define VFE44_BUS_BDG_QOS_CFG_4 0x000002D4 +#define VFE44_BUS_BDG_QOS_CFG_5 0x000002D8 +#define VFE44_BUS_BDG_QOS_CFG_6 0x000002DC +#define VFE44_BUS_BDG_QOS_CFG_7 0x000002E0 + +#define VFE44_CLK_IDX 2 +static struct msm_cam_clk_info msm_vfe44_clk_info[VFE_CLK_INFO_MAX]; + +static void msm_vfe44_init_qos_parms(struct vfe_device *vfe_dev) +{ + void __iomem *vfebase = vfe_dev->vfe_base; + + if (vfe_dev->vfe_hw_version == VFE44_8084V1_VERSION) { + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xFEA9FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0001FEA9, vfebase + VFE44_BUS_BDG_QOS_CFG_7); + } else { + BUG(); + pr_err("%s: QOS is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + } +} + +static void msm_vfe44_init_vbif_parms_8084_v1(struct vfe_device *vfe_dev) +{ + void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base; + msm_camera_io_w(0x1, + vfe_vbif_base + VFE44_VBIF_CLKON); + msm_camera_io_w(0x00100000, + vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF0); + msm_camera_io_w(0x00001000, + vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF1); + msm_camera_io_w(0x10000010, + vfe_vbif_base + VFE44_VBIF_IN_RD_LIM_CONF2); + msm_camera_io_w(0x10000010, + vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF0); + msm_camera_io_w(0x10100000, + vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF1); + msm_camera_io_w(0x00101000, + vfe_vbif_base + VFE44_VBIF_IN_WR_LIM_CONF2); + msm_camera_io_w(0x3, + vfe_vbif_base + VFE44_VBIF_ROUND_ROBIN_QOS_ARB); +} + +static void msm_vfe44_init_vbif_parms(struct vfe_device *vfe_dev) +{ + switch (vfe_dev->vfe_hw_version) { + case VFE44_8084V1_VERSION: + msm_vfe44_init_vbif_parms_8084_v1(vfe_dev); + break; + default: + BUG(); + pr_err("%s: VBIF is NOT configured for HW Version %x\n", + __func__, vfe_dev->vfe_hw_version); + break; + } + +} + +static int msm_vfe44_init_hardware(struct vfe_device *vfe_dev) +{ + int rc = -1; + rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (vfe_dev->fs_vfe) { + rc = regulator_enable(vfe_dev->fs_vfe); + if (rc) { + pr_err("%s: Regulator enable failed\n", __func__); + goto fs_failed; + } + } + + rc = msm_isp_get_clk_info(vfe_dev, vfe_dev->pdev, msm_vfe44_clk_info); + if (rc < 0) { + pr_err("msm_isp_get_clk_info() failed\n"); + goto fs_failed; + } + + if (vfe_dev->num_clk <= 0) { + pr_err("%s: Invalid num of clock\n", __func__); + goto fs_failed; + } else { + vfe_dev->vfe_clk = + kzalloc(sizeof(struct clk *) * vfe_dev->num_clk, + GFP_KERNEL); + if (!vfe_dev->vfe_clk) { + pr_err("%s:%d No memory\n", __func__, __LINE__); + return -ENOMEM; + } + } + + rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 1); + if (rc < 0) + goto clk_enable_failed; + + vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start, + resource_size(vfe_dev->vfe_mem)); + if (!vfe_dev->vfe_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vfe_remap_failed; + } + + vfe_dev->vfe_vbif_base = ioremap(vfe_dev->vfe_vbif_mem->start, + resource_size(vfe_dev->vfe_vbif_mem)); + if (!vfe_dev->vfe_vbif_base) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto vbif_remap_failed; + } + + rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq, + IRQF_TRIGGER_RISING, "vfe", vfe_dev); + if (rc < 0) { + pr_err("%s: irq request failed\n", __func__); + goto irq_req_failed; + } + return rc; +irq_req_failed: + iounmap(vfe_dev->vfe_vbif_base); +vbif_remap_failed: + iounmap(vfe_dev->vfe_base); +vfe_remap_failed: + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); +clk_enable_failed: + if (vfe_dev->fs_vfe) + regulator_disable(vfe_dev->fs_vfe); + kfree(vfe_dev->vfe_clk); +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +bus_scale_register_failed: + return rc; +} + +static void msm_vfe44_release_hardware(struct vfe_device *vfe_dev) +{ + free_irq(vfe_dev->vfe_irq->start, vfe_dev); + tasklet_kill(&vfe_dev->vfe_tasklet); + iounmap(vfe_dev->vfe_vbif_base); + iounmap(vfe_dev->vfe_base); + msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe44_clk_info, + vfe_dev->vfe_clk, vfe_dev->num_clk, 0); + kfree(vfe_dev->vfe_clk); + regulator_disable(vfe_dev->fs_vfe); + msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id); +} + +static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev) +{ + msm_vfe44_init_qos_parms(vfe_dev); + msm_vfe44_init_vbif_parms(vfe_dev); + /* CGC_OVERRIDE */ + msm_camera_io_w(0xFBFFFFFF, vfe_dev->vfe_base + 0x14); + msm_camera_io_w(0xC001FF7F, vfe_dev->vfe_base + 0x974); + /* BUS_CFG */ + msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); + msm_camera_io_w(0xE00000F3, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x2C); + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); + msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); +} + +static void msm_vfe44_process_reset_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status0 & (1 << 31)) + complete(&vfe_dev->reset_complete); +} + +static void msm_vfe44_process_halt_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + if (irq_status1 & (1 << 8)) + complete(&vfe_dev->halt_complete); +} + +static void msm_vfe44_process_epoch_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0xc)) + return; + if (irq_status0 & (1 << 2)) + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); +} + +static void msm_vfe44_process_camif_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + if (!(irq_status0 & 0xF)) + return; + + if (irq_status0 & (1 << 0)) { + ISP_DBG("%s: SOF IRQ\n", __func__); + if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 + && vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count == 0) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + msm_isp_update_framedrop_reg(vfe_dev); + } + } + if (irq_status0 & (1 << 1)) + ISP_DBG("%s: EOF IRQ\n", __func__); + if (irq_status0 & (1 << 2)) + ISP_DBG("%s: EPOCH0 IRQ\n", __func__); + if (irq_status0 & (1 << 3)) + ISP_DBG("%s: EPOCH1 IRQ\n", __func__); +} + +static void msm_vfe44_process_violation_status( + struct vfe_device *vfe_dev) +{ + uint32_t violation_status = vfe_dev->error_info.violation_status; + if (!violation_status) + return; + + if (violation_status == 0) + pr_err("%s: camif violation\n", __func__); + if (violation_status == 1) + pr_err("%s: black violation\n", __func__); + if (violation_status == 2) + pr_err("%s: rolloff violation\n", __func__); + if (violation_status == 3) + pr_err("%s: demux violation\n", __func__); + if (violation_status == 4) + pr_err("%s: demosaic violation\n", __func__); + if (violation_status == 5) + pr_err("%s: wb violation\n", __func__); + if (violation_status == 6) + pr_err("%s: clf violation\n", __func__); + if (violation_status == 7) + pr_err("%s: color correct violation\n", __func__); + if (violation_status == 8) + pr_err("%s: rgb lut violation\n", __func__); + if (violation_status == 9) + pr_err("%s: la violation\n", __func__); + if (violation_status == 10) + pr_err("%s: chroma enhance violation\n", __func__); + if (violation_status == 11) + pr_err("%s: chroma supress mce violation\n", __func__); + if (violation_status == 12) + pr_err("%s: skin enhance violation\n", __func__); + if (violation_status == 13) + pr_err("%s: color tranform enc violation\n", __func__); + if (violation_status == 14) + pr_err("%s: color tranform view violation\n", __func__); + if (violation_status == 15) + pr_err("%s: scale enc y violation\n", __func__); + if (violation_status == 16) + pr_err("%s: scale enc cbcr violation\n", __func__); + if (violation_status == 17) + pr_err("%s: scale view y violation\n", __func__); + if (violation_status == 18) + pr_err("%s: scale view cbcr violation\n", __func__); + if (violation_status == 21) + pr_err("%s: crop enc y violation\n", __func__); + if (violation_status == 22) + pr_err("%s: crop enc cbcr violation\n", __func__); + if (violation_status == 23) + pr_err("%s: crop view y violation\n", __func__); + if (violation_status == 24) + pr_err("%s: crop view cbcr violation\n", __func__); + if (violation_status == 25) + pr_err("%s: realign buf y violation\n", __func__); + if (violation_status == 26) + pr_err("%s: realign buf cb violation\n", __func__); + if (violation_status == 27) + pr_err("%s: realign buf cr violation\n", __func__); + if (violation_status == 28) + pr_err("%s: ltm violation\n", __func__); + if (violation_status == 29) + pr_err("%s: ltm cov violation\n", __func__); + if (violation_status == 30) + pr_err("%s: abf violation\n", __func__); + if (violation_status == 31) + pr_err("%s: bpc violation\n", __func__); +} + +static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev) +{ + uint32_t error_status1 = vfe_dev->error_info.error_mask1; + if (error_status1 & (1 << 0)) + pr_err("%s: camif error status: 0x%x\n", + __func__, vfe_dev->error_info.camif_status); + if (error_status1 & (1 << 1)) + pr_err("%s: stats bhist overwrite\n", __func__); + if (error_status1 & (1 << 2)) + pr_err("%s: stats cs overwrite\n", __func__); + if (error_status1 & (1 << 3)) + pr_err("%s: stats ihist overwrite\n", __func__); + if (error_status1 & (1 << 4)) + pr_err("%s: realign buf y overflow\n", __func__); + if (error_status1 & (1 << 5)) + pr_err("%s: realign buf cb overflow\n", __func__); + if (error_status1 & (1 << 6)) + pr_err("%s: realign buf cr overflow\n", __func__); + if (error_status1 & (1 << 7)) { + pr_err("%s: violation\n", __func__); + msm_vfe44_process_violation_status(vfe_dev); + } + if (error_status1 & (1 << 9)) + pr_err("%s: image master 0 bus overflow\n", __func__); + if (error_status1 & (1 << 10)) + pr_err("%s: image master 1 bus overflow\n", __func__); + if (error_status1 & (1 << 11)) + pr_err("%s: image master 2 bus overflow\n", __func__); + if (error_status1 & (1 << 12)) + pr_err("%s: image master 3 bus overflow\n", __func__); + if (error_status1 & (1 << 13)) + pr_err("%s: image master 4 bus overflow\n", __func__); + if (error_status1 & (1 << 14)) + pr_err("%s: image master 5 bus overflow\n", __func__); + if (error_status1 & (1 << 15)) + pr_err("%s: image master 6 bus overflow\n", __func__); + if (error_status1 & (1 << 16)) + pr_err("%s: status be bus overflow\n", __func__); + if (error_status1 & (1 << 17)) + pr_err("%s: status bg bus overflow\n", __func__); + if (error_status1 & (1 << 18)) + pr_err("%s: status bf bus overflow\n", __func__); + if (error_status1 & (1 << 19)) + pr_err("%s: status awb bus overflow\n", __func__); + if (error_status1 & (1 << 20)) + pr_err("%s: status rs bus overflow\n", __func__); + if (error_status1 & (1 << 21)) + pr_err("%s: status cs bus overflow\n", __func__); + if (error_status1 & (1 << 22)) + pr_err("%s: status ihist bus overflow\n", __func__); + if (error_status1 & (1 << 23)) + pr_err("%s: status skin bhist bus overflow\n", __func__); + if (error_status1 & (1 << 24)) + pr_err("%s: status bf scale bus overflow\n", __func__); +} + +static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + *irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38); + *irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C); + msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30); + msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34); + msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24); + if (*irq_status0 & 0x10000000) { + pr_err_ratelimited("%s: Protection triggered\n", __func__); + *irq_status0 &= ~(0x10000000); + } + + if (*irq_status1 & (1 << 0)) + vfe_dev->error_info.camif_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x31C); + + if (*irq_status1 & (1 << 7)) + vfe_dev->error_info.violation_status = + msm_camera_io_r(vfe_dev->vfe_base + 0x48); + +} + +static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + uint8_t input_src = 0x0; + if (!(irq_status0 & 0xF0)) + return; + + if (irq_status0 & BIT(4)) { + msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); + input_src |= (1 << VFE_PIX_0); + } + if (irq_status0 & BIT(5)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_0, ts); + input_src |= (1 << VFE_RAW_0); + } + if (irq_status0 & BIT(6)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_1, ts); + input_src |= (1 << VFE_RAW_1); + } + if (irq_status0 & BIT(7)) { + msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_RAW_2, ts); + input_src |= (1 << VFE_RAW_2); + } + + if (vfe_dev->axi_data.stream_update) + msm_isp_axi_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->stats_data.stats_update)) + msm_isp_stats_stream_update(vfe_dev); + if (atomic_read(&vfe_dev->axi_data.axi_cfg_update)) + msm_isp_axi_cfg_update(vfe_dev); + if (vfe_dev->axi_data.stream_update || atomic_read(&vfe_dev->stats_data.stats_update) || atomic_read(&vfe_dev->axi_data.axi_cfg_update)) { + if (input_src & (1 << VFE_PIX_0)) { + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, (1 << VFE_PIX_0)); + } + } + msm_isp_update_framedrop_reg(vfe_dev); + msm_isp_update_error_frame_count(vfe_dev); + if ((input_src & (1 << VFE_RAW_0)) || (input_src & (1 << VFE_RAW_1)) || (input_src & (1 << VFE_RAW_2))) { + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, input_src); + } + return; +} +static void msm_vfe44_reg_update(struct vfe_device *vfe_dev, uint32_t input_src) +{ + msm_camera_io_w_mb(input_src, vfe_dev->vfe_base + 0x378); +} +static uint32_t msm_vfe44_reset_values[ISP_RST_MAX] = +{ + 0x1FF, /* ISP_RST_HARD reset everything */ + 0x1EF /* ISP_RST_SOFT all modules without registers */ +}; + +static long msm_vfe44_reset_hardware(struct vfe_device *vfe_dev, + enum msm_isp_reset_type reset_type, uint32_t blocking) +{ + uint32_t rst_val; + long rc = 0; + if (reset_type >= ISP_RST_MAX) { + pr_err("%s: Error Invalid parameter\n", __func__); + reset_type = ISP_RST_HARD; + } + rst_val = msm_vfe44_reset_values[reset_type]; + init_completion(&vfe_dev->reset_complete); + if (blocking) { + msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC); + rc = wait_for_completion_interruptible_timeout( + &vfe_dev->reset_complete, msecs_to_jiffies(50)); + } else { + msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC); + } + return rc; +} + +static void msm_vfe44_axi_reload_wm( + struct vfe_device *vfe_dev, uint32_t reload_mask) +{ + msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x4C); +} + +static void msm_vfe44_axi_enable_wm(struct vfe_device *vfe_dev, + uint8_t wm_idx, uint8_t enable) +{ + uint32_t val; + val = msm_camera_io_r(vfe_dev->vfe_base + VFE44_WM_BASE(wm_idx)); + if (enable) + val |= 0x1; + else + val &= ~0x1; + msm_camera_io_w_mb(val, + vfe_dev->vfe_base + VFE44_WM_BASE(wm_idx)); +} + +static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + comp_mask |= (axi_data->composite_info[comp_mask_index]. + stream_composite_mask << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (comp_mask_index + 25); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + uint32_t irq_mask; + + comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); + comp_mask &= ~(0x7F << (comp_mask_index * 8)); + msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); + + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (comp_mask_index + 25)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (stream_info->wm[0] + 8); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (stream_info->wm[0] + 8)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_cfg_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i, temp; + uint32_t framedrop_pattern = 0, framedrop_period = 0; + + if (stream_info->runtime_init_frame_drop == 0) { + framedrop_pattern = stream_info->framedrop_pattern; + framedrop_period = stream_info->framedrop_period; + } + + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_burst_frame_count == 0) { + framedrop_pattern = 0; + framedrop_period = 0; + } + + for (i = 0; i < stream_info->num_planes; i++) { + msm_camera_io_w(framedrop_pattern, vfe_dev->vfe_base + + VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); + temp = msm_camera_io_r(vfe_dev->vfe_base + + VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + temp &= 0xFFFFFF83; + msm_camera_io_w(temp | framedrop_period << 2, + vfe_dev->vfe_base + VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + } + + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378); +} + +static void msm_vfe44_clear_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + uint32_t i; + for (i = 0; i < stream_info->num_planes; i++) + msm_camera_io_w(0, vfe_dev->vfe_base + + VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); +} + +static int32_t msm_vfe44_cfg_io_format(struct vfe_device *vfe_dev, + enum msm_vfe_axi_stream_src stream_src, uint32_t io_format) +{ + int bpp, bpp_reg = 0, pack_reg = 0; + enum msm_isp_pack_fmt pack_fmt = 0; + uint32_t io_format_reg; /*io format register bit*/ + bpp = msm_isp_get_bit_per_pixel(io_format); + if (bpp < 0) { + pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__, + io_format, bpp); + return -EINVAL; + } + + switch (bpp) { + case 8: + bpp_reg = 0; + break; + case 10: + bpp_reg = 1 << 0; + break; + case 12: + bpp_reg = 1 << 1; + break; + default: + pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp); + return -EINVAL; + } + + if (stream_src == IDEAL_RAW) { + /*use io_format(v4l2_pix_fmt) to get pack format*/ + pack_fmt = msm_isp_get_pack_format(io_format); + switch (pack_fmt) { + case QCOM: + pack_reg = 0x0; + break; + case MIPI: + pack_reg = 0x1; + break; + case DPCM6: + pack_reg = 0x2; + break; + case DPCM8: + pack_reg = 0x3; + break; + case PLAIN8: + pack_reg = 0x4; + break; + case PLAIN16: + pack_reg = 0x5; + break; + default: + pr_err("%s: invalid pack fmt!\n", __func__); + return -EINVAL; + } + } + + io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54); + switch (stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case CAMIF_RAW: + io_format_reg &= 0xFFFFCFFF; + io_format_reg |= bpp_reg << 12; + break; + case IDEAL_RAW: + io_format_reg &= 0xFFFFFFC8; + io_format_reg |= bpp_reg << 4 | pack_reg; + break; + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + default: + pr_err("%s: Invalid stream source\n", __func__); + return -EINVAL; + } + msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54); + return 0; +} + +static void msm_vfe44_cfg_camif(struct vfe_device *vfe_dev, + struct msm_vfe_pix_cfg *pix_cfg) +{ + uint16_t first_pixel, last_pixel, first_line, last_line; + struct msm_vfe_camif_cfg *camif_cfg = &pix_cfg->camif_cfg; + uint32_t val; + + first_pixel = camif_cfg->first_pixel; + last_pixel = camif_cfg->last_pixel; + first_line = camif_cfg->first_line; + last_line = camif_cfg->last_line; + + msm_camera_io_w(pix_cfg->input_mux << 16 | pix_cfg->pixel_pattern, + vfe_dev->vfe_base + 0x1C); + + msm_camera_io_w(camif_cfg->lines_per_frame << 16 | + camif_cfg->pixels_per_line, vfe_dev->vfe_base + 0x300); + + msm_camera_io_w(first_pixel << 16 | last_pixel, + vfe_dev->vfe_base + 0x304); + + msm_camera_io_w(first_line << 16 | last_line, + vfe_dev->vfe_base + 0x308); + + msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x314); + + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2E8); + val |= camif_cfg->camif_input; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2E8); + + switch (pix_cfg->input_mux) { + case CAMIF: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F4); + break; + case TESTGEN: + val = 0x01; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x93C); + break; + case EXTERNAL_READ: + default: + pr_err("%s: not supported input_mux %d\n", + __func__, pix_cfg->input_mux); + break; + } +} + +static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state update_state) +{ + uint32_t val; + bool bus_en, vfe_en; + if (update_state == NO_UPDATE) + return; + + if (update_state == ENABLE_CAMIF) { + val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + val |= 0xF5; + msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(0x200, vfe_dev->vfe_base + 0x318); + bus_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); + vfe_en = + ((vfe_dev->axi_data. + src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); + val &= 0xFFFFFF3F; + val = val | bus_en << 7 | vfe_en << 6; + msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; + } else if (update_state == DISABLE_CAMIF) { + msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) { + msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x2F4); + vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; + } +} + +static void msm_vfe44_cfg_rdi_reg( + struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg, + enum msm_vfe_input_src input_src) +{ + uint8_t rdi = input_src - VFE_RAW_0; + uint32_t rdi_reg_cfg; + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE44_RDI_BASE(0)); + rdi_reg_cfg &= ~(BIT(16 + rdi)); + rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi); + msm_camera_io_w(rdi_reg_cfg, + vfe_dev->vfe_base + VFE44_RDI_BASE(0)); + + rdi_reg_cfg = msm_camera_io_r( + vfe_dev->vfe_base + VFE44_RDI_BASE(rdi)); + rdi_reg_cfg &= 0x70003; + rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4; + msm_camera_io_w( + rdi_reg_cfg, vfe_dev->vfe_base + VFE44_RDI_BASE(rdi)); +} + +static void msm_vfe44_axi_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + uint32_t val; + uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + + if (!stream_info->frame_based) { + msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); + /*WR_IMAGE_SIZE*/ + val = + ((msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[plane_idx]. + output_width)+1)/2 - 1) << 16 | + (stream_info->plane_cfg[plane_idx]. + output_height - 1); + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + + /*WR_BUFFER_CFG*/ + val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); + val = val << 2 | + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_stride) << 16 | + VFE44_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } else { + msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); + val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); + val = val << 2 | + msm_isp_cal_word_per_line(stream_info->output_format, + stream_info->plane_cfg[ + plane_idx].output_width) << 16 | + VFE44_BURST_LEN; + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + } + + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + wm_base + 0x20); + /* TD: Add IRQ subsample pattern */ +} + +static void msm_vfe44_axi_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint32_t val = 0; + uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); + /*WR_IMAGE_SIZE*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); + /*WR_BUFFER_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); +} + +static void msm_vfe44_axi_cfg_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + uint8_t plane_idx) +{ + struct msm_vfe_axi_plane_cfg *plane_cfg = + &stream_info->plane_cfg[plane_idx]; + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_cfg = 0; + uint32_t xbar_reg_cfg = 0; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: { + if (plane_cfg->output_plane_format != CRCB_PLANE && + plane_cfg->output_plane_format != CBCR_PLANE) { + /*SINGLE_STREAM_SEL*/ + xbar_cfg |= plane_cfg->output_plane_format << 8; + } else { + switch (stream_info->output_format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV16: + xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/ + break; + } + xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/ + } + if (stream_info->stream_src == PIX_VIEWFINDER) + xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/ + break; + } + case CAMIF_RAW: + xbar_cfg = 0x300; + break; + case IDEAL_RAW: + xbar_cfg = 0x400; + break; + case RDI_INTF_0: + xbar_cfg = 0x500; + break; + case RDI_INTF_1: + xbar_cfg = 0x600; + break; + case RDI_INTF_2: + xbar_cfg = 0x700; + break; + default: + pr_err("%s: Invalid stream src\n", __func__); + break; + } + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); + xbar_reg_cfg |= (xbar_cfg << VFE44_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); +} + +static void msm_vfe44_axi_clear_wm_xbar_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) +{ + uint8_t wm = stream_info->wm[plane_idx]; + uint32_t xbar_reg_cfg = 0; + + xbar_reg_cfg = + msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); + xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); + msm_camera_io_w(xbar_reg_cfg, + vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); +} + +#define MSM_ISP44_TOTAL_WM_UB 1203 + +static void msm_vfe44_cfg_axi_ub_equal_default( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = + &vfe_dev->axi_data; + uint32_t total_image_size = 0; + uint8_t num_used_wms = 0; + uint32_t prop_size = 0; + uint32_t wm_ub_size; + uint32_t delta; + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i] > 0) { + num_used_wms++; + total_image_size += axi_data->wm_image_size[i]; + } + } + prop_size = MSM_ISP44_TOTAL_WM_UB - + axi_data->hw_info->min_wm_ub * num_used_wms; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (axi_data->free_wm[i]) { + delta = + (axi_data->wm_image_size[i] * + prop_size)/total_image_size; + wm_ub_size = axi_data->hw_info->min_wm_ub + delta; + msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1), + vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); + ub_offset += wm_ub_size; + } else + msm_camera_io_w(0, + vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); + } +} + +static void msm_vfe44_cfg_axi_ub_equal_slicing( + struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + msm_camera_io_w(ub_offset << 16 | (VFE44_EQUAL_SLICE_UB - 1), + vfe_dev->vfe_base + VFE44_WM_BASE(i) + 0x10); + ub_offset += VFE44_EQUAL_SLICE_UB; + } +} + +static void msm_vfe44_cfg_axi_ub(struct vfe_device *vfe_dev) +{ + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT; + if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING) + msm_vfe44_cfg_axi_ub_equal_slicing(vfe_dev); + else + msm_vfe44_cfg_axi_ub_equal_default(vfe_dev); +} + +static void msm_vfe44_update_ping_pong_addr( + struct vfe_device *vfe_dev, + uint8_t wm_idx, uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE44_PING_PONG_BASE(wm_idx, pingpong_status)); +} + +static long msm_vfe44_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking) +{ + uint32_t halt_mask; + halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); + halt_mask |= (1 << 8); + msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x2C); + init_completion(&vfe_dev->halt_complete); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); + return wait_for_completion_interruptible_timeout( + &vfe_dev->halt_complete, msecs_to_jiffies(500)); +} + +static uint32_t msm_vfe44_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 8) & 0x7F; +} + +static uint32_t msm_vfe44_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 25) & 0xF; +} + +static uint32_t msm_vfe44_get_pingpong_status( + struct vfe_device *vfe_dev) +{ + return msm_camera_io_r(vfe_dev->vfe_base + 0x268); +} + +static int msm_vfe44_get_stats_idx(enum msm_isp_stats_type stats_type) +{ + switch (stats_type) { + case MSM_ISP_STATS_BE: + return STATS_IDX_BE; + case MSM_ISP_STATS_BG: + return STATS_IDX_BG; + case MSM_ISP_STATS_BF: + return STATS_IDX_BF; + case MSM_ISP_STATS_AWB: + return STATS_IDX_AWB; + case MSM_ISP_STATS_RS: + return STATS_IDX_RS; + case MSM_ISP_STATS_CS: + return STATS_IDX_CS; + case MSM_ISP_STATS_IHIST: + return STATS_IDX_IHIST; + case MSM_ISP_STATS_BHIST: + return STATS_IDX_BHIST; + case MSM_ISP_STATS_BF_SCALE: + return STATS_IDX_BF_SCALE; + default: + pr_err("%s: Invalid stats type\n", __func__); + return -EINVAL; + } +} + +static int msm_vfe44_stats_check_streams( + struct msm_vfe_stats_stream *stream_info) +{ + if (stream_info[STATS_IDX_BF].state == + STATS_AVALIABLE && + stream_info[STATS_IDX_BF_SCALE].state != + STATS_AVALIABLE) { + pr_err("%s: does not support BF_SCALE while BF is disabled\n", + __func__); + return -EINVAL; + } + if (stream_info[STATS_IDX_BF].state != STATS_AVALIABLE && + stream_info[STATS_IDX_BF_SCALE].state != STATS_AVALIABLE && + stream_info[STATS_IDX_BF].composite_flag != + stream_info[STATS_IDX_BF_SCALE].composite_flag) { + pr_err("%s: Different composite flag for BF and BF_SCALE\n", + __func__); + return -EINVAL; + } + return 0; +} + +static void msm_vfe44_stats_cfg_comp_mask( + struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + uint32_t reg_mask, comp_stats_mask, mask_bf_scale; + uint32_t i = 0; + atomic_t *stats_comp; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + if (vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask > + MAX_NUM_STATS_COMP_MASK) { + pr_err("%s: num of comp masks %d exceed max %d\n", + __func__, + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask, + MAX_NUM_STATS_COMP_MASK); + return; + } + + /* BF scale is controlled by BF also so ignore bit 0 of BF scale */ + stats_mask = stats_mask & 0x1FF; + mask_bf_scale = stats_mask >> SHIFT_BF_SCALE_BIT; + + for (i = 0; + i < vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; i++) { + stats_comp = &stats_data->stats_comp_mask[i]; + reg_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x44); + comp_stats_mask = reg_mask & (STATS_COMP_BIT_MASK << (i*8)); + + if (enable) { + if (comp_stats_mask) + continue; + + reg_mask |= (mask_bf_scale << (16 + i*8)); + atomic_add(stats_mask, stats_comp); + } else { + + if (stats_mask & (1 << STATS_IDX_BF_SCALE) && + atomic_read(stats_comp) & + (1 << STATS_IDX_BF_SCALE)) + atomic_sub((1 << STATS_IDX_BF_SCALE), + stats_comp); + + /* + * Check if comp mask in reg is valid + * and contains this stat + */ + + if (!comp_stats_mask || + !((comp_stats_mask >> (16 + i*8)) & + mask_bf_scale)) + continue; + + atomic_sub(stats_mask, stats_comp); + reg_mask &= ~(mask_bf_scale << (16 + i*8)); + } + ISP_DBG("%s: comp_mask: %x atomic stats[0]: %x %x\n", + __func__, reg_mask, + atomic_read(&stats_data->stats_comp_mask[0]), + atomic_read(&stats_data->stats_comp_mask[1])); + + msm_camera_io_w(reg_mask, vfe_dev->vfe_base + 0x44); + return; + } +} + +static void msm_vfe44_stats_cfg_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 15); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_stats_clear_wm_irq_mask( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t irq_mask; + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28); + irq_mask &= ~(1 << (STATS_IDX(stream_info->stream_handle) + 15)); + msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28); +} + +static void msm_vfe44_stats_cfg_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + + /* BF_SCALE does not have its own WR_ADDR_CFG, + * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; + * it's using the same from BF */ + if (stats_idx == STATS_IDX_BF_SCALE) + return; + /*WR_ADDR_CFG*/ + msm_camera_io_w(stream_info->framedrop_period << 2, + vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(stream_info->framedrop_pattern, + vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(0xFFFFFFFF, + vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe44_stats_clear_wm_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t val = 0; + int stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + /* BF_SCALE does not have its own WR_ADDR_CFG, + * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; + * it's using the same from BF */ + if (stats_idx == STATS_IDX_BF_SCALE) + return; + + /*WR_ADDR_CFG*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); + /*WR_IRQ_FRAMEDROP_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); + /*WR_IRQ_SUBSAMPLE_PATTERN*/ + msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x14); +} + +static void msm_vfe44_stats_cfg_ub(struct vfe_device *vfe_dev) +{ + int i; + uint32_t ub_offset = VFE44_UB_SIZE; + uint32_t ub_size[VFE44_NUM_STATS_TYPE] = { + 128, /*MSM_ISP_STATS_BF_SCALE*/ + 64, /*MSM_ISP_STATS_BE*/ + 128, /*MSM_ISP_STATS_BG*/ + 128, /*MSM_ISP_STATS_BF*/ + 16, /*MSM_ISP_STATS_AWB*/ + 8, /*MSM_ISP_STATS_RS*/ + 16, /*MSM_ISP_STATS_CS*/ + 16, /*MSM_ISP_STATS_IHIST*/ + 16, /*MSM_ISP_STATS_BHIST*/ + }; + + for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) { + ub_offset -= ub_size[i]; + msm_camera_io_w(VFE44_STATS_BURST_LEN << 30 | + ub_offset << 16 | (ub_size[i] - 1), + vfe_dev->vfe_base + VFE44_STATS_BASE(i) + + ((i == STATS_IDX_BF_SCALE) ? 0x8 : 0xC)); + } +} + +static void msm_vfe44_stats_enable_module(struct vfe_device *vfe_dev, + uint32_t stats_mask, uint8_t enable) +{ + int i; + uint32_t module_cfg, module_cfg_mask = 0; + uint32_t stats_cfg, stats_cfg_mask = 0; + + for (i = 0; i < VFE44_NUM_STATS_TYPE; i++) { + if ((stats_mask >> i) & 0x1) { + switch (i) { + case STATS_IDX_BE: + case STATS_IDX_BG: + case STATS_IDX_BF: + case STATS_IDX_AWB: + case STATS_IDX_RS: + case STATS_IDX_CS: + module_cfg_mask |= 1 << (4 + i); + break; + case STATS_IDX_IHIST: + module_cfg_mask |= 1 << 15; + break; + case STATS_IDX_BHIST: + module_cfg_mask |= 1 << 18; + break; + case STATS_IDX_BF_SCALE: + stats_cfg_mask |= 1 << 2; + break; + default: + pr_err("%s: Invalid stats mask\n", __func__); + return; + } + } + } + + module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x18); + if (enable) + module_cfg |= module_cfg_mask; + else + module_cfg &= ~module_cfg_mask; + msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x18); + + stats_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x888); + if (enable) + stats_cfg |= stats_cfg_mask; + else + stats_cfg &= ~stats_cfg_mask; + msm_camera_io_w(stats_cfg, vfe_dev->vfe_base + 0x888); +} + +static void msm_vfe44_stats_update_ping_pong_addr( + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, + uint32_t pingpong_status, dma_addr_t paddr) +{ + uint32_t paddr32 = (paddr & 0xFFFFFFFF); + int stats_idx = STATS_IDX(stream_info->stream_handle); + msm_camera_io_w(paddr32, vfe_dev->vfe_base + + VFE44_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); +} + +static uint32_t msm_vfe44_stats_get_wm_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 15) & 0x1FF; +} + +static uint32_t msm_vfe44_stats_get_comp_mask( + uint32_t irq_status0, uint32_t irq_status1) +{ + return (irq_status0 >> 29) & 0x3; +} + +static uint32_t msm_vfe44_stats_get_frame_id( + struct vfe_device *vfe_dev) +{ + uint32_t session_id = 0; + session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + return vfe_dev->axi_data.frame_id[session_id]; +} + +static int msm_vfe44_get_platform_data(struct vfe_device *vfe_dev) +{ + int rc = 0; + vfe_dev->vfe_mem = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_MEM, "vfe"); + if (!vfe_dev->vfe_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_vbif_mem = platform_get_resource_byname( + vfe_dev->pdev, + IORESOURCE_MEM, "vfe_vbif"); + if (!vfe_dev->vfe_vbif_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev, + IORESOURCE_IRQ, "vfe"); + if (!vfe_dev->vfe_irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->fs_vfe = regulator_get(&vfe_dev->pdev->dev, "vdd"); + if (IS_ERR(vfe_dev->fs_vfe)) { + pr_err("%s: Regulator get failed %ld\n", __func__, + PTR_ERR(vfe_dev->fs_vfe)); + vfe_dev->fs_vfe = NULL; + rc = -ENODEV; + goto vfe_no_resource; + } + + vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe"); + if (!vfe_dev->iommu_ctx[0]) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -ENODEV; + goto vfe_no_resource; + } + +vfe_no_resource: + return rc; +} + +static void msm_vfe44_get_error_mask( + uint32_t *error_mask0, uint32_t *error_mask1) +{ + *error_mask0 = 0x00000000; + *error_mask1 = 0x01FFFEFF; +} + +static struct msm_vfe_axi_hardware_info msm_vfe44_axi_hw_info = { + .num_wm = 5, + .num_comp_mask = 3, + .num_rdi = 3, + .num_rdi_master = 3, + .min_wm_ub = 64, +}; + +static struct msm_vfe_stats_hardware_info msm_vfe44_stats_hw_info = { + .stats_capability_mask = + 1 << MSM_ISP_STATS_BE | 1 << MSM_ISP_STATS_BF | + 1 << MSM_ISP_STATS_BG | 1 << MSM_ISP_STATS_BHIST | + 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST | + 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS | + 1 << MSM_ISP_STATS_BF_SCALE, + .stats_ping_pong_offset = stats_pingpong_offset_map, + .num_stats_type = VFE44_NUM_STATS_TYPE, + .num_stats_comp_mask = VFE44_NUM_STATS_COMP, +}; + +static struct v4l2_subdev_core_ops msm_vfe44_subdev_core_ops = { + .ioctl = msm_isp_ioctl, + .subscribe_event = msm_isp_subscribe_event, + .unsubscribe_event = msm_isp_unsubscribe_event, +}; + +static struct v4l2_subdev_ops msm_vfe44_subdev_ops = { + .core = &msm_vfe44_subdev_core_ops, +}; + +static struct v4l2_subdev_internal_ops msm_vfe44_internal_ops = { + .open = msm_isp_open_node, + .close = msm_isp_close_node, +}; + +struct msm_vfe_hardware_info vfe44_hw_info = { + .num_iommu_ctx = 1, + .vfe_clk_idx = VFE44_CLK_IDX, + .vfe_ops = { + .irq_ops = { + .read_irq_status = msm_vfe44_read_irq_status, + .process_camif_irq = msm_vfe44_process_camif_irq, + .process_reset_irq = msm_vfe44_process_reset_irq, + .process_halt_irq = msm_vfe44_process_halt_irq, + .process_reset_irq = msm_vfe44_process_reset_irq, + .process_reg_update = msm_vfe44_process_reg_update, + .process_epoch_irq = msm_vfe44_process_epoch_irq, + .process_axi_irq = msm_isp_process_axi_irq, + .process_stats_irq = msm_isp_process_stats_irq, + }, + .axi_ops = { + .reload_wm = msm_vfe44_axi_reload_wm, + .enable_wm = msm_vfe44_axi_enable_wm, + .cfg_io_format = msm_vfe44_cfg_io_format, + .cfg_comp_mask = msm_vfe44_axi_cfg_comp_mask, + .clear_comp_mask = msm_vfe44_axi_clear_comp_mask, + .cfg_wm_irq_mask = msm_vfe44_axi_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe44_axi_clear_wm_irq_mask, + .cfg_framedrop = msm_vfe44_cfg_framedrop, + .clear_framedrop = msm_vfe44_clear_framedrop, + .cfg_wm_reg = msm_vfe44_axi_cfg_wm_reg, + .clear_wm_reg = msm_vfe44_axi_clear_wm_reg, + .cfg_wm_xbar_reg = msm_vfe44_axi_cfg_wm_xbar_reg, + .clear_wm_xbar_reg = msm_vfe44_axi_clear_wm_xbar_reg, + .cfg_ub = msm_vfe44_cfg_axi_ub, + .update_ping_pong_addr = + msm_vfe44_update_ping_pong_addr, + .get_comp_mask = msm_vfe44_get_comp_mask, + .get_wm_mask = msm_vfe44_get_wm_mask, + .get_pingpong_status = msm_vfe44_get_pingpong_status, + .halt = msm_vfe44_axi_halt, + }, + .core_ops = { + .reg_update = msm_vfe44_reg_update, + .cfg_camif = msm_vfe44_cfg_camif, + .update_camif_state = msm_vfe44_update_camif_state, + .cfg_rdi_reg = msm_vfe44_cfg_rdi_reg, + .reset_hw = msm_vfe44_reset_hardware, + .init_hw = msm_vfe44_init_hardware, + .init_hw_reg = msm_vfe44_init_hardware_reg, + .release_hw = msm_vfe44_release_hardware, + .get_platform_data = msm_vfe44_get_platform_data, + .get_error_mask = msm_vfe44_get_error_mask, + .process_error_status = msm_vfe44_process_error_status, + }, + .stats_ops = { + .get_stats_idx = msm_vfe44_get_stats_idx, + .check_streams = msm_vfe44_stats_check_streams, + .cfg_comp_mask = msm_vfe44_stats_cfg_comp_mask, + .cfg_wm_irq_mask = msm_vfe44_stats_cfg_wm_irq_mask, + .clear_wm_irq_mask = msm_vfe44_stats_clear_wm_irq_mask, + .cfg_wm_reg = msm_vfe44_stats_cfg_wm_reg, + .clear_wm_reg = msm_vfe44_stats_clear_wm_reg, + .cfg_ub = msm_vfe44_stats_cfg_ub, + .enable_module = msm_vfe44_stats_enable_module, + .update_ping_pong_addr = + msm_vfe44_stats_update_ping_pong_addr, + .get_comp_mask = msm_vfe44_stats_get_comp_mask, + .get_wm_mask = msm_vfe44_stats_get_wm_mask, + .get_frame_id = msm_vfe44_stats_get_frame_id, + .get_pingpong_status = msm_vfe44_get_pingpong_status, + }, + }, + .dmi_reg_offset = 0x918, + .axi_hw_info = &msm_vfe44_axi_hw_info, + .stats_hw_info = &msm_vfe44_stats_hw_info, + .subdev_ops = &msm_vfe44_subdev_ops, + .subdev_internal_ops = &msm_vfe44_internal_ops, +}; +EXPORT_SYMBOL(vfe44_hw_info); diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp44.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp44.h new file mode 100644 index 0000000000000000000000000000000000000000..7bd630d4ef4d2ffad5402e344ce9b8f441497257 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp44.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_ISP44_H__ +#define __MSM_ISP44_H__ + +extern struct msm_vfe_hardware_info vfe44_hw_info; +#endif /* __MSM_ISP44_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_axi_util.c new file mode 100644 index 0000000000000000000000000000000000000000..c77a11e47ceefc1298d7ef273ae44c04e57d876d --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_axi_util.c @@ -0,0 +1,1915 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_camera_io_util.h" + +#define SRC_TO_INTF(src) \ + ((src < RDI_INTF_0) ? VFE_PIX_0 : \ + (VFE_RAW_0 + src - RDI_INTF_0)) + +#define HANDLE_TO_IDX(handle) (handle & 0xFF) + +#define MSM_ISP_MIN_AB 450000000 +#define MSM_ISP_MIN_IB 900000000 +#define MIN_IB 1700000000 + +int msm_isp_axi_create_stream( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) +{ + int i, rc = -1; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == AVALIABLE) + break; + } + + if (i == MAX_NUM_STREAM) { + pr_err("%s: No free stream\n", __func__); + return rc; + } + + if ((axi_data->stream_handle_cnt << 8) == 0) + axi_data->stream_handle_cnt++; + + stream_cfg_cmd->axi_stream_handle = + (++axi_data->stream_handle_cnt) << 8 | i; + + memset(&axi_data->stream_info[i], 0, + sizeof(struct msm_vfe_axi_stream)); + spin_lock_init(&axi_data->stream_info[i].lock); + axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id; + axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id; + axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert; + axi_data->stream_info[i].state = INACTIVE; + axi_data->stream_info[i].stream_handle = + stream_cfg_cmd->axi_stream_handle; + return 0; +} + +void msm_isp_axi_destroy_stream( + struct msm_vfe_axi_shared_data *axi_data, int stream_idx) +{ + if (axi_data->stream_info[stream_idx].state != AVALIABLE) { + axi_data->stream_info[stream_idx].state = AVALIABLE; + axi_data->stream_info[stream_idx].stream_handle = 0; + } else { + pr_err("%s: stream does not exist\n", __func__); + } +} + +int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) +{ + int rc = -1, i; + struct msm_vfe_axi_stream *stream_info = NULL; + if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + } else { + pr_err("%s: Invalid axi_stream_handle\n", __func__); + return rc; + } + switch (stream_cfg_cmd->output_format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + 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_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + stream_info->num_planes = 1; + stream_info->format_factor = ISP_Q2; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + stream_info->num_planes = 2; + stream_info->format_factor = 1.5 * ISP_Q2; + break; + /*TD: Add more image format*/ + default: + pr_err("%s: Invalid output format\n", __func__); + return rc; + } + + if (axi_data->hw_info->num_wm - axi_data->num_used_wm < + stream_info->num_planes) { + pr_err("%s: No free write masters\n", __func__); + return rc; + } + + if ((stream_info->num_planes > 1) && + (axi_data->hw_info->num_comp_mask - + axi_data->num_used_composite_mask < 1)) { + pr_err("%s: No free composite mask\n", __func__); + return rc; + } + + if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) { + pr_err("%s: Invalid skip pattern\n", __func__); + return rc; + } + + if (stream_cfg_cmd->frame_skip_pattern >= MAX_SKIP) { + pr_err("%s: Invalid skip pattern\n", __func__); + return rc; + } + + for (i = 0; i < stream_info->num_planes; i++) { + stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i]; + stream_info->max_width = max(stream_info->max_width, + stream_cfg_cmd->plane_cfg[i].output_width); + } + + stream_info->output_format = stream_cfg_cmd->output_format; + stream_info->runtime_output_format = stream_info->output_format; + stream_info->stream_src = stream_cfg_cmd->stream_src; + stream_info->frame_based = stream_cfg_cmd->frame_base; + return 0; +} + +static uint32_t msm_isp_axi_get_plane_size( + struct msm_vfe_axi_stream *stream_info, int plane_idx) +{ + uint32_t size = 0; + struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg; + switch (stream_info->output_format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + /* TODO: fix me */ + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + /* TODO: fix me */ + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + else + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + if (plane_cfg[plane_idx].output_plane_format == Y_PLANE) + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + else + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + size = plane_cfg[plane_idx].output_height * + plane_cfg[plane_idx].output_width; + break; + /*TD: Add more image format*/ + default: + pr_err("%s: Invalid output format\n", __func__); + break; + } + return size; +} + +void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i, j; + for (i = 0; i < stream_info->num_planes; i++) { + for (j = 0; j < axi_data->hw_info->num_wm; j++) { + if (!axi_data->free_wm[j]) { + axi_data->free_wm[j] = + stream_info->stream_handle; + axi_data->wm_image_size[j] = + msm_isp_axi_get_plane_size( + stream_info, i); + axi_data->num_used_wm++; + break; + } + } + stream_info->wm[i] = j; + } +} + +void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + for (i = 0; i < stream_info->num_planes; i++) { + axi_data->free_wm[stream_info->wm[i]] = 0; + axi_data->num_used_wm--; + } +} + +void msm_isp_axi_reserve_comp_mask( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + uint8_t comp_mask = 0; + for (i = 0; i < stream_info->num_planes; i++) + comp_mask |= 1 << stream_info->wm[i]; + + for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { + if (!axi_data->composite_info[i].stream_handle) { + axi_data->composite_info[i].stream_handle = + stream_info->stream_handle; + axi_data->composite_info[i]. + stream_composite_mask = comp_mask; + axi_data->num_used_composite_mask++; + break; + } + } + stream_info->comp_mask_index = i; + return; +} + +void msm_isp_axi_free_comp_mask(struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + axi_data->composite_info[stream_info->comp_mask_index]. + stream_composite_mask = 0; + axi_data->composite_info[stream_info->comp_mask_index]. + stream_handle = 0; + axi_data->num_used_composite_mask--; +} + +int msm_isp_axi_get_bufq_handles( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int rc = 0; + + if (stream_info->stream_id & ISP_SCRATCH_BUF_BIT) { + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id & ~ISP_SCRATCH_BUF_BIT); + if (stream_info->bufq_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + + stream_info->bufq_scratch_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_scratch_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + } else { + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_handle == 0) { + pr_err("%s: Stream 0x%x has no valid buffer queue\n", + __func__, (unsigned int)stream_info->stream_id); + rc = -EINVAL; + return rc; + } + } + return rc; +} + +int msm_isp_axi_check_stream_state( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int rc = 0, i; + unsigned long flags; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + enum msm_vfe_axi_state valid_state = + (stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state != valid_state) { + if ((stream_info->state == PAUSING || + stream_info->state == PAUSED || + stream_info->state == RESUME_PENDING || + stream_info->state == RESUMING) && + (stream_cfg_cmd->cmd == STOP_STREAM || + stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { + stream_info->state = ACTIVE; + } else { + pr_err("%s: Invalid stream state: %d\n", + __func__, stream_info->state); + spin_unlock_irqrestore( + &stream_info->lock, flags); + rc = -EINVAL; + break; + } + } + spin_unlock_irqrestore(&stream_info->lock, flags); + + if (stream_cfg_cmd->cmd == START_STREAM) { + rc = msm_isp_axi_get_bufq_handles(vfe_dev, stream_info); + if (rc) + break; + } + } + return rc; +} + +void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state != ACTIVE) + continue; + + if (stream_info->runtime_framedrop_update) { + stream_info->runtime_init_frame_drop--; + if (stream_info->runtime_init_frame_drop == 0) { + stream_info->runtime_framedrop_update = 0; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + } + } + if (stream_info->stream_type == BURST_STREAM) { + stream_info->runtime_burst_frame_count--; + if (stream_info->runtime_burst_frame_count == 0) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + } + } + } +} + +static void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + stream_info->runtime_init_frame_drop = stream_info->init_frame_drop; + stream_info->runtime_burst_frame_count = + stream_info->burst_frame_count; + stream_info->runtime_num_burst_capture = + stream_info->num_burst_capture; + stream_info->runtime_framedrop_update = stream_info->framedrop_update; + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info); +} + +#if defined(CONFIG_SR200PC20) && defined(CONFIG_SR544) +void msm_isp_sof_notify(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) { + struct msm_isp_event_data sof_event; + uint32_t session_id; + unsigned long flags; + uint16_t session_mask = 0; + + session_id = vfe_dev->axi_data.src_info[frame_src].session_id; + spin_lock_irqsave(&vfe_dev->sof_lock, flags); + session_mask = vfe_dev->axi_data.session_frame_src_mask[session_id]; + spin_unlock_irqrestore(&vfe_dev->sof_lock, flags); + + if (!(session_mask & (1 << frame_src))) { + /*pr_err("%s: Ignoring the Sof for the source INTF %d\n", + __func__, (1 << frame_src));*/ + return; + } + vfe_dev->axi_data.current_frame_src_mask[session_id] |= + (1 << frame_src); + /*pr_debug("%s: current mask 0x%X , session mask 0x%X, session_id %d\n", + __func__, + vfe_dev->axi_data.current_frame_src_mask[session_id], + session_mask, + session_id);*/ + if ((vfe_dev->axi_data.current_frame_src_mask[session_id] == + session_mask)) { + vfe_dev->axi_data.current_frame_src_mask[session_id] = 0; + + vfe_dev->axi_data.frame_id[session_id]++; + if (vfe_dev->axi_data.frame_id[session_id] == 0) + vfe_dev->axi_data.frame_id[session_id] = 1; + sof_event.input_intf = session_mask; + sof_event.frame_id = vfe_dev->axi_data.frame_id[session_id]; + sof_event.timestamp = ts->event_time; + sof_event.mono_timestamp = ts->buf_time; + vfe_dev->frame_id = vfe_dev->axi_data.frame_id[session_id]; + vfe_dev->eof_event_occur = 0; + msm_isp_send_event(vfe_dev, + ISP_EVENT_SOF + frame_src, &sof_event); + /*pr_debug("%s: frame id %d\n", __func__, + vfe_dev->axi_data.frame_id[session_id]);*/ + } +} +#else +void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) { + struct msm_isp_event_data event_data; + uint32_t session_id; + + session_id = vfe_dev->axi_data.src_info[frame_src].session_id; + if (!(vfe_dev->axi_data.session_frame_src_mask[session_id] + & (1 << frame_src))) { + pr_err("%s: Ignoring the Sof for the sourece INTF %d\n", + __func__, (1 << frame_src)); + return; + } + vfe_dev->axi_data.current_frame_src_mask[session_id] |= + (1 << frame_src); + pr_debug("%s: current mask 0x%X , session mask 0x%X, session_id %d\n", + __func__, + vfe_dev->axi_data.current_frame_src_mask[session_id], + vfe_dev->axi_data.session_frame_src_mask[session_id], + session_id); + if ((vfe_dev->axi_data.current_frame_src_mask[session_id] == + vfe_dev->axi_data.session_frame_src_mask[session_id])) { + vfe_dev->axi_data.current_frame_src_mask[session_id] = 0; + switch (event_type) { + case ISP_EVENT_SOF: + vfe_dev->axi_data.frame_id[session_id]++; + if (vfe_dev->axi_data.frame_id[session_id] == 0) + vfe_dev->axi_data.frame_id[session_id] = 1; + break; + default: + break; + } + event_data.input_intf = vfe_dev->axi_data.session_frame_src_mask[session_id]; + event_data.frame_id = vfe_dev->axi_data.frame_id[session_id]; + event_data.timestamp = ts->event_time; + event_data.mono_timestamp = ts->buf_time; + + //pr_err("%s: AAAAA SOF frame id = %u\n", + // __func__, vfe_dev->axi_data.frame_id[session_id]); + vfe_dev->frame_id = vfe_dev->axi_data.frame_id[session_id]; + vfe_dev->eof_event_occur = 0; + msm_isp_send_event(vfe_dev, event_type | frame_src, &event_data); + pr_debug("%s: frame id %d\n", __func__, + vfe_dev->axi_data.frame_id[session_id]); + } +} + +#endif + +void msm_isp_calculate_framedrop( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) +{ + uint32_t framedrop_period = 0; + struct msm_vfe_axi_stream *stream_info = NULL; + if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < MAX_NUM_STREAM) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + } else { + pr_err("%s: Invalid stream handle",__func__); + return; + } + + framedrop_period = msm_isp_get_framedrop_period( + stream_cfg_cmd->frame_skip_pattern); + + stream_info->frame_skip_pattern = + stream_cfg_cmd->frame_skip_pattern; + if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + + if (stream_cfg_cmd->init_frame_drop < framedrop_period) { + stream_info->framedrop_pattern <<= + stream_cfg_cmd->init_frame_drop; + stream_info->init_frame_drop = 0; + stream_info->framedrop_update = 0; + } else { + stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop; + stream_info->framedrop_update = 1; + } + + if (stream_cfg_cmd->burst_count > 0) { + stream_info->stream_type = BURST_STREAM; + stream_info->num_burst_capture = + stream_cfg_cmd->burst_count; + stream_info->burst_frame_count = + stream_cfg_cmd->init_frame_drop + + (stream_cfg_cmd->burst_count - 1) * + framedrop_period + 1; + } else { + stream_info->stream_type = CONTINUOUS_STREAM; + stream_info->burst_frame_count = 0; + stream_info->num_burst_capture = 0; + } +} + +void msm_isp_calculate_bandwidth( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info) +{ + if (stream_info->stream_src < RDI_INTF_0) { + stream_info->bandwidth = + (axi_data->src_info[VFE_PIX_0].pixel_clock / + axi_data->src_info[VFE_PIX_0].width) * + stream_info->max_width; + stream_info->bandwidth = stream_info->bandwidth * + stream_info->format_factor / ISP_Q2; + } else { + int rdi = SRC_TO_INTF(stream_info->stream_src); + stream_info->bandwidth = axi_data->src_info[rdi].pixel_clock; + } +} + +#if 0 //CONFIG_MSM_AVTIMER +void msm_isp_start_avtimer(void) +{ + avcs_core_open(); + avcs_core_disable_power_collapse(1); +} +#else +void msm_isp_start_avtimer(void) +{ + pr_err("AV Timer is not supported\n"); +} +#endif + +int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + uint32_t io_format = 0, avtimer_scaler = 0; + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + rc = msm_isp_axi_create_stream( + &vfe_dev->axi_data, stream_cfg_cmd); + if (rc) { + pr_err("%s: create stream failed\n", __func__); + return rc; + } + + rc = msm_isp_validate_axi_request( + &vfe_dev->axi_data, stream_cfg_cmd); + if (rc) { + pr_err("%s: Request validation failed\n", __func__); + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); + return rc; + } + stream_info = &vfe_dev->axi_data. + stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info); + + if (stream_info->stream_src < RDI_INTF_0) { + io_format = vfe_dev->axi_data.src_info[VFE_PIX_0].input_format; + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + if (stream_info->stream_src == CAMIF_RAW && + io_format != stream_info->output_format) + pr_warn("%s: Overriding input format\n", + __func__); + + io_format = stream_info->output_format; + } + rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format( + vfe_dev, stream_info->stream_src, io_format); + if (rc) { + pr_err("%s: cfg io format failed\n", __func__); + msm_isp_axi_free_wm(&vfe_dev->axi_data, + stream_info); + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX( + stream_cfg_cmd->axi_stream_handle)); + return rc; + } + } + + msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd); + stream_info->vt_enable = stream_cfg_cmd->vt_enable; + axi_data->burst_len = stream_cfg_cmd->burst_len; + + if (stream_info->vt_enable) { + vfe_dev->vt_enable = stream_info->vt_enable; + msm_isp_start_avtimer(); + if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION) { + vfe_dev->p_avtimer_lsw = + ioremap(AVTIMER_LSW_PHY_ADDR_8916, 4); + vfe_dev->p_avtimer_msw = + ioremap(AVTIMER_MSW_PHY_ADDR_8916, 4); + vfe_dev->p_avtimer_ctl = + ioremap(AVTIMER_MODE_CTL_PHY_ADDR_8916, 4); + if (vfe_dev->p_avtimer_ctl) { + avtimer_scaler = + msm_camera_io_r(vfe_dev->p_avtimer_ctl); + /*If bit 2 is set, it indicates AVTimer + ticks are scaled*/ + if (avtimer_scaler & 0x00000002) + vfe_dev->avtimer_scaler = + AVTIMER_TICK_SCALER_8916; + } + } else { + vfe_dev->p_avtimer_lsw = + ioremap(AVTIMER_LSW_PHY_ADDR, 4); + vfe_dev->p_avtimer_msw = + ioremap(AVTIMER_MSW_PHY_ADDR, 4); + } + } + if (stream_info->num_planes > 1) { + msm_isp_axi_reserve_comp_mask( + &vfe_dev->axi_data, stream_info); + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_comp_mask(vfe_dev, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + } + + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, i); + + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_xbar_reg(vfe_dev, stream_info, i); + } + return rc; +} + +int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_release_cmd->stream_handle)]; + struct msm_vfe_axi_stream_cfg_cmd stream_cfg; + + if (stream_info->state == AVALIABLE) { + pr_err("%s: Stream already released\n", __func__); + return -EINVAL; + } else if (stream_info->state != INACTIVE) { + stream_cfg.cmd = STOP_STREAM; + stream_cfg.num_streams = 1; + stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle; + msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg); + } + + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_reg(vfe_dev, stream_info, i); + + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_xbar_reg(vfe_dev, stream_info, i); + } + + if (stream_info->num_planes > 1) { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_comp_mask(vfe_dev, stream_info); + msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + } + + vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info); + msm_isp_axi_free_wm(axi_data, stream_info); + + msm_isp_axi_destroy_stream(&vfe_dev->axi_data, + HANDLE_TO_IDX(stream_release_cmd->stream_handle)); + + return rc; +} + +static void msm_isp_axi_stream_enable_cfg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + if (stream_info->state == INACTIVE) + return; + for (i = 0; i < stream_info->num_planes; i++) { + if (stream_info->state == START_PENDING || + stream_info->state == RESUME_PENDING) + vfe_dev->hw_info->vfe_ops.axi_ops. + enable_wm(vfe_dev, stream_info->wm[i], 1); + else { + vfe_dev->hw_info->vfe_ops.axi_ops. + enable_wm(vfe_dev, stream_info->wm[i], 0); + /* Issue a reg update for Raw Snapshot Case + * since we dont have reg update ack + */ + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, (1 << VFE_PIX_0)); + } + } + } + + if (stream_info->state == START_PENDING) + axi_data->num_active_stream++; + else if (stream_info->state == STOP_PENDING) + axi_data->num_active_stream--; +} + +void msm_isp_axi_stream_update(struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == START_PENDING || + axi_data->stream_info[i].state == + STOP_PENDING) { + msm_isp_axi_stream_enable_cfg( + vfe_dev, &axi_data->stream_info[i]); + axi_data->stream_info[i].state = + axi_data->stream_info[i].state == + START_PENDING ? STARTING : STOPPING; + } else if (axi_data->stream_info[i].state == STARTING || + axi_data->stream_info[i].state == STOPPING) { + axi_data->stream_info[i].state = + axi_data->stream_info[i].state == STARTING ? + ACTIVE : INACTIVE; + } + } + + if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF || + (vfe_dev->axi_data.pipeline_update == + DISABLE_CAMIF_IMMEDIATELY)) { + vfe_dev->hw_info->vfe_ops.stats_ops. + enable_module(vfe_dev, 0xFF, 0); + vfe_dev->axi_data.pipeline_update = NO_UPDATE; + } + + vfe_dev->axi_data.stream_update--; + if (vfe_dev->axi_data.stream_update == 0) + complete(&vfe_dev->stream_config_complete); +} + +static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i, j; + uint32_t flag; + struct msm_isp_buffer *buf; + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + flag = i ? VFE_PONG_FLAG : VFE_PING_FLAG; + for (j = 0; j < stream_info->num_planes; j++) { + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[j], flag, + buf->mapped_info[j].paddr + + stream_info->plane_cfg[j].plane_addr_offset); + } + } +} + +void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev) +{ + int i, j; + uint32_t update_state; + unsigned long flags; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->stream_type == BURST_STREAM || + stream_info->state == AVALIABLE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state == PAUSING) { + /*AXI Stopped, apply update*/ + stream_info->state = PAUSED; + msm_isp_reload_ping_pong_offset(vfe_dev, stream_info); + for (j = 0; j < stream_info->num_planes; j++) + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + /*Resume AXI*/ + stream_info->state = RESUME_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, &axi_data->stream_info[i]); + stream_info->state = RESUMING; + } else if (stream_info->state == RESUMING) { + stream_info->runtime_output_format = + stream_info->output_format; + stream_info->state = ACTIVE; + } + spin_unlock_irqrestore(&stream_info->lock, flags); + } + + update_state = atomic_dec_return(&axi_data->axi_cfg_update); +} + +static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + struct msm_isp_buffer *buf = stream_info->buf[0]; + for (i = 0; i < stream_info->num_planes; i++) + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[i], + VFE_PONG_FLAG, buf->mapped_info[i].paddr + + stream_info->plane_cfg[i].plane_addr_offset); + stream_info->buf[1] = buf; +} + +static void msm_isp_get_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, + struct msm_isp_buffer **done_buf) +{ + uint32_t pingpong_bit = 0, i; + pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + for (i = 0; i < stream_info->num_planes; i++) { + if (pingpong_bit != + (~(pingpong_status >> stream_info->wm[i]) & 0x1)) { + pr_warn("%s: Write master ping pong mismatch. Status: 0x%x\n", + __func__, pingpong_status); + } + } + *done_buf = stream_info->buf[pingpong_bit]; +} + +static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) +{ + int i, rc = -1; + struct msm_isp_buffer *buf = NULL; + uint32_t pingpong_bit = 0; + uint32_t bufq_handle = 0; + uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + if (stream_idx >= MAX_NUM_STREAM) { + pr_err("%s: Invalid stream_idx",__func__); + return rc; + } + if (stream_info->bufq_scratch_handle && !stream_info->request_frm_num) + bufq_handle = stream_info->bufq_scratch_handle; + else + bufq_handle = stream_info->bufq_handle; + + rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, + vfe_dev->pdev->id, bufq_handle, &buf); + + if (rc < 0) { + vfe_dev->error_info.stream_framedrop_count[stream_idx]++; + return rc; + } + + if (stream_info->bufq_scratch_handle && + bufq_handle == stream_info->bufq_handle) + stream_info->request_frm_num--; + + if (buf->num_planes != stream_info->num_planes) { + pr_err("%s: Invalid buffer\n", __func__); + rc = -EINVAL; + goto buf_error; + } + + for (i = 0; i < stream_info->num_planes; i++) + vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( + vfe_dev, stream_info->wm[i], + pingpong_status, buf->mapped_info[i].paddr + + stream_info->plane_cfg[i].plane_addr_offset); + pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + stream_info->buf[pingpong_bit] = buf; + return 0; +buf_error: + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + return rc; +} + +static inline void msm_isp_get_vt_tstamp(struct vfe_device *vfe_dev, + struct msm_isp_timestamp *time_stamp) +{ + uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0; + uint32_t avtimer_msw_2nd = 0; + uint64_t av_timer_tick = 0; + + if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) { + pr_err("%s: ioremap failed\n", __func__); + return; + } + + do { + avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw); + avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw); + avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw); + } while (avtimer_msw_1st != avtimer_msw_2nd); + av_timer_tick = ((uint64_t)avtimer_msw_1st << 32) | avtimer_lsw; + do_div(av_timer_tick, vfe_dev->avtimer_scaler); + avtimer_lsw = do_div(av_timer_tick, USEC_PER_SEC); + time_stamp->vt_time.tv_sec = (uint32_t)(av_timer_tick); + time_stamp->vt_time.tv_usec = avtimer_lsw; +} + +static void msm_isp_process_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf, + struct msm_isp_timestamp *ts) +{ + int rc; + struct msm_isp_event_data buf_event; + struct timeval *time_stamp; + uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + uint32_t session_id = vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)].session_id; + uint32_t frame_id = vfe_dev->axi_data.frame_id[session_id]; + uint32_t buf_src; + memset(&buf_event, 0, sizeof(buf_event)); + + if (buf && ts) { + if (vfe_dev->vt_enable) { + msm_isp_get_vt_tstamp(vfe_dev, ts); + time_stamp = &ts->vt_time; + } + else + time_stamp = &ts->buf_time; + + rc = vfe_dev->buf_mgr->ops->get_buf_src(vfe_dev->buf_mgr, + buf->bufq_handle, &buf_src); + if (stream_info->buf_divert && rc == 0 && + buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) { + rc = vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id); + /* Buf divert return value represent whether the buf + * can be diverted. A positive return value means + * other ISP hardware is still processing the frame. + */ + if (rc == 0) { + buf_event.input_intf = + SRC_TO_INTF(stream_info->stream_src); + buf_event.frame_id = frame_id; + buf_event.timestamp = *time_stamp; + buf_event.u.buf_done.session_id = + stream_info->session_id; + buf_event.u.buf_done.stream_id = + stream_info->stream_id; + buf_event.u.buf_done.handle = + stream_info->bufq_handle; + buf_event.u.buf_done.buf_idx = buf->buf_idx; + buf_event.u.buf_done.output_format = + stream_info->runtime_output_format; + msm_isp_send_event(vfe_dev, + ISP_EVENT_BUF_DIVERT + stream_idx, + &buf_event); + } + } else { + buf_event.input_intf = + SRC_TO_INTF(stream_info->stream_src); + buf_event.frame_id = frame_id; + buf_event.timestamp = ts->buf_time; + buf_event.u.buf_done.session_id = + stream_info->session_id; + buf_event.u.buf_done.stream_id = + stream_info->stream_id; + buf_event.u.buf_done.output_format = + stream_info->runtime_output_format; + msm_isp_send_event(vfe_dev, + ISP_EVENT_BUF_DONE, &buf_event); + vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id, + stream_info->runtime_output_format); + } + } +} + +static enum msm_isp_camif_update_state + msm_isp_get_camif_update_state(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt; + cur_pix_stream_cnt = + axi_data->src_info[VFE_PIX_0].pix_stream_count + + axi_data->src_info[VFE_PIX_0].raw_stream_count; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src < RDI_INTF_0) + pix_stream_cnt++; + } + + if (pix_stream_cnt) { + if (cur_pix_stream_cnt == 0 && pix_stream_cnt && + stream_cfg_cmd->cmd == START_STREAM) + return ENABLE_CAMIF; + else if (cur_pix_stream_cnt && + (cur_pix_stream_cnt - pix_stream_cnt) == 0 && + stream_cfg_cmd->cmd == STOP_STREAM) + return DISABLE_CAMIF; + else if (cur_pix_stream_cnt && + (cur_pix_stream_cnt - pix_stream_cnt) == 0 && + stream_cfg_cmd->cmd == STOP_IMMEDIATELY) + return DISABLE_CAMIF_IMMEDIATELY; + } + return NO_UPDATE; +} + +static void msm_isp_update_camif_output_count( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return; + } + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src >= RDI_INTF_0) + continue; + if (stream_info->stream_src == PIX_ENCODER || + stream_info->stream_src == PIX_VIEWFINDER || + stream_info->stream_src == IDEAL_RAW) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count--; + } else if (stream_info->stream_src == CAMIF_RAW) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count--; + } + } +} + +static void msm_isp_update_rdi_output_count( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return; + } + stream_info = + &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + if (stream_info->stream_src < RDI_INTF_0) + continue; + if (stream_info->stream_src == RDI_INTF_0) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count--; + } else if (stream_info->stream_src == RDI_INTF_1) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count--; + } else if (stream_info->stream_src == RDI_INTF_2) { + if (stream_cfg_cmd->cmd == START_STREAM) + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count++; + else + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count--; + } + + } +} + +uint8_t msm_isp_get_curr_stream_cnt( + struct vfe_device *vfe_dev) +{ + uint8_t curr_stream_cnt = 0; + curr_stream_cnt = vfe_dev->axi_data.src_info[VFE_RAW_0]. + raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_1]. + raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_2]. + raw_stream_count + vfe_dev->axi_data.src_info[VFE_PIX_0]. + pix_stream_count + vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count; + + return curr_stream_cnt; +} + +void msm_camera_io_dump_2(void __iomem *addr, int size) +{ + char line_str[128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + ISP_DBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08x: ", (u32) p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + ISP_DBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + ISP_DBG("%s\n", line_str); +} + +/*Factor in Q2 format*/ +#define ISP_DEFAULT_FORMAT_FACTOR 6 +#define ISP_BUS_UTILIZATION_FACTOR 6 +static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) +{ + int i, rc = 0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; + uint32_t num_pix_streams = 0; + uint32_t num_rdi_streams = 0; + uint32_t total_streams = 0; + uint64_t total_bandwidth = 0; + uint64_t ib_total_bandwidth = 0; + + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state == ACTIVE || + stream_info->state == START_PENDING) { + if (stream_info->stream_src < RDI_INTF_0) { + total_pix_bandwidth += stream_info->bandwidth; + num_pix_streams++; + } else { + total_rdi_bandwidth += stream_info->bandwidth; + num_rdi_streams++; + } + } + } + if (num_pix_streams > 0) + total_pix_bandwidth = total_pix_bandwidth / + num_pix_streams * (num_pix_streams - 1) + + ((unsigned long)axi_data->src_info[VFE_PIX_0]. + pixel_clock) * ISP_DEFAULT_FORMAT_FACTOR / ISP_Q2; + total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; + total_streams = num_pix_streams + num_rdi_streams; + if (total_streams == 1) { + ib_total_bandwidth = total_bandwidth * + ISP_BUS_UTILIZATION_FACTOR / ISP_Q2 - MSM_ISP_MIN_IB; + if(ib_total_bandwidth < MIN_IB) + ib_total_bandwidth = MIN_IB; + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + (total_bandwidth - MSM_ISP_MIN_AB) , ib_total_bandwidth); + } + else { + ib_total_bandwidth = total_bandwidth * + ISP_BUS_UTILIZATION_FACTOR / ISP_Q2; + if(ib_total_bandwidth < MIN_IB) + ib_total_bandwidth = MIN_IB; + rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, + total_bandwidth, ib_total_bandwidth); + } + if (rc < 0) + pr_err("%s: update failed\n", __func__); + + return rc; +} + +static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev, + enum msm_isp_camif_update_state camif_update) +{ + int rc; + unsigned long flags; + spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); + init_completion(&vfe_dev->stream_config_complete); + vfe_dev->axi_data.pipeline_update = camif_update; + vfe_dev->axi_data.stream_update = 2; + spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); + rc = wait_for_completion_timeout( + &vfe_dev->stream_config_complete, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + if (rc == 0) { + pr_err("%s: wait timeout\n", __func__); + rc = -1; + } else { + rc = 0; + } + return rc; +} + +static int msm_isp_init_stream_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int rc = 0; + /*Set address for both PING & PONG register */ + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PING_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", + __func__); + return rc; + } + + /* For burst stream of one capture, only one buffer + * is allocated. Duplicate ping buffer address to pong + * buffer to ensure hardware write to a valid address + */ + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture <= 1) { + msm_isp_cfg_pong_address(vfe_dev, stream_info); + } else { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PONG_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", + __func__); + return rc; + } + } + return rc; +} + +static void msm_isp_deinit_stream_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int i; + for (i = 0; i < 2; i++) { + struct msm_isp_buffer *buf; + buf = stream_info->buf[i]; + if (buf) + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + } +} + +static void msm_isp_get_stream_wm_mask( + struct msm_vfe_axi_stream *stream_info, + uint32_t *wm_reload_mask) +{ + int i; + for (i = 0; i < stream_info->num_planes; i++) + *wm_reload_mask |= (1 << stream_info->wm[i]); +} + +static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + enum msm_isp_camif_update_state camif_update) +{ + int i, rc = 0; + uint8_t src_state, wait_for_complete = 0; + uint32_t wm_reload_mask = 0x0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info->frame_id = 0; + src_state = axi_data->src_info[ + SRC_TO_INTF(stream_info->stream_src)].active; + + msm_isp_calculate_bandwidth(axi_data, stream_info); + msm_isp_reset_framedrop(vfe_dev, stream_info); + msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); + rc = msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); + if (rc < 0) { + pr_err("%s: No buffer for stream%d\n", __func__, + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])); + return rc; + } + + stream_info->state = START_PENDING; + if (src_state) { + wait_for_complete = 1; + } else { + if (vfe_dev->dump_reg) + msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900); + + /*Configure AXI start bits to start immediately*/ + msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); + stream_info->state = ACTIVE; + } + vfe_dev->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)].session_id = + stream_info->session_id; + vfe_dev->axi_data. + session_frame_src_mask[stream_info->session_id] |= + (1 << SRC_TO_INTF(stream_info->stream_src)); + vfe_dev->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)].frame_id = 0; + } + msm_isp_update_stream_bandwidth(vfe_dev); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + + vfe_dev->hw_info->vfe_ops.core_ops.init_vbif_counters(vfe_dev); + + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + if (camif_update == ENABLE_CAMIF) { + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0; + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, camif_update); + } + if (vfe_dev->axi_data.src_info[VFE_RAW_0].raw_stream_count > 0) + vfe_dev->axi_data.src_info[VFE_RAW_0].frame_id = 0; + else if (vfe_dev->axi_data.src_info[VFE_RAW_1].raw_stream_count > 0) + vfe_dev->axi_data.src_info[VFE_RAW_1].frame_id = 0; + else if (vfe_dev->axi_data.src_info[VFE_RAW_2].raw_stream_count > 0) + vfe_dev->axi_data.src_info[VFE_RAW_2].frame_id = 0; + + if (wait_for_complete) + rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); + + return rc; +} + +#if defined(CONFIG_SR200PC20) && defined(CONFIG_SR544) +static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + enum msm_isp_camif_update_state camif_update) +{ + int i, rc = 0; + uint8_t wait_for_complete = 0, cur_stream_cnt = 0; + struct msm_vfe_axi_stream *stream_info = NULL; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint16_t session_mask = 0; + uint32_t session_id = 0; + uint8_t skip_session_mask_update = 0; + unsigned long flags; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM || + stream_cfg_cmd->num_streams == 0) + return -EINVAL; + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + + stream_info->state = STOP_PENDING; + session_id = stream_info->session_id; + if (!session_mask) + session_mask = vfe_dev->axi_data. + session_frame_src_mask[session_id]; + if (cur_stream_cnt > 0) + wait_for_complete = 1; + if (SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) { + if ((vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)]. + pix_stream_count + vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)]. + raw_stream_count) >= 1) + skip_session_mask_update = 1; + else + session_mask &= + ~(1 << SRC_TO_INTF( + stream_info->stream_src)); + } else { + session_mask &= + ~(1 << SRC_TO_INTF(stream_info->stream_src)); + } + } + + if (wait_for_complete) { + rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); + if (rc < 0) { + pr_err("%s: wait for config done failed\n", __func__); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])]; + stream_info->state = STOP_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = INACTIVE; + } + } + } else { + pr_err("%s: Stop Immediately! stream_id=%d\n", __func__, + stream_info->stream_id); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])]; + stream_info->state = STOP_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = INACTIVE; + } + } + if (!skip_session_mask_update) { + if (session_mask == 0) + vfe_dev->axi_data.frame_id[session_id] = 0; + spin_lock_irqsave(&vfe_dev->sof_lock, flags); + vfe_dev->axi_data. + session_frame_src_mask[session_id] = session_mask; + spin_unlock_irqrestore(&vfe_dev->sof_lock, flags); + } + msm_isp_update_stream_bandwidth(vfe_dev); + if (camif_update == DISABLE_CAMIF) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF); + else if (camif_update == DISABLE_CAMIF_IMMEDIATELY) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + + if (cur_stream_cnt == 0) { + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.core_ops. + reset_hw(vfe_dev, ISP_RST_HARD, 1); + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + } + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info); + } + return rc; +} +#else +static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, + enum msm_isp_camif_update_state camif_update) +{ + int i, rc = 0; + uint8_t wait_for_complete = 0, cur_stream_cnt = 0; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint16_t session_mask = 0; + uint32_t session_id = 0; + uint8_t skip_session_mask_update = 0; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + + stream_info->state = STOP_PENDING; + if (stream_info->stream_src == CAMIF_RAW || + stream_info->stream_src == IDEAL_RAW) { + /* We dont get reg update IRQ for raw snapshot + * so frame skip cant be ocnfigured + */ + wait_for_complete = 1; + } else if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture == 0) { + /* Configure AXI writemasters to stop immediately + * since for burst case, write masters already skip + * all frames. + */ + if (stream_info->stream_src == RDI_INTF_0 || + stream_info->stream_src == RDI_INTF_1 || + stream_info->stream_src == RDI_INTF_2) + wait_for_complete = 1; + else { + msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); + stream_info->state = INACTIVE; + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + } + } else { + wait_for_complete = 1; + } + session_id = stream_info->session_id; + if (!session_mask) + session_mask = vfe_dev->axi_data. + session_frame_src_mask[session_id]; + if (SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) { + if ((vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)]. + pix_stream_count <= 1) && (vfe_dev->axi_data. + src_info[SRC_TO_INTF(stream_info->stream_src)]. + raw_stream_count <= 1)) { + session_mask &= + ~(1 << SRC_TO_INTF( + stream_info->stream_src)); + if (stream_info->stream_type == + BURST_STREAM) + skip_session_mask_update = 1; + } + } else { + session_mask &= + ~(1 << SRC_TO_INTF(stream_info->stream_src)); + } + + } + if (wait_for_complete) { + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update); + if (rc < 0) { + pr_err("%s: wait for config done failed\n", __func__); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX( + stream_cfg_cmd->stream_handle[i])]; + stream_info->state = STOP_PENDING; + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, 0xF); + msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info); + stream_info->state = INACTIVE; + } + } + } + if (!skip_session_mask_update) { + if (session_mask == 0) + vfe_dev->axi_data.frame_id[session_id] = 0; + vfe_dev->axi_data. + session_frame_src_mask[session_id] = session_mask; + } + msm_isp_update_stream_bandwidth(vfe_dev); + if (camif_update == DISABLE_CAMIF) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF); + else if (camif_update == DISABLE_CAMIF_IMMEDIATELY) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); + msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd); + cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + if (cur_stream_cnt == 0) { + if (camif_update == DISABLE_CAMIF_IMMEDIATELY) + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.core_ops. + reset_hw(vfe_dev, ISP_RST_HARD, 1); + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + } + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info); + } + return rc; +} +#endif + + +int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + enum msm_isp_camif_update_state camif_update; + + rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd); + if (rc < 0) { + pr_err("%s: Invalid stream state\n", __func__); + return rc; + } + + if (axi_data->num_active_stream == 0) { + /*Configure UB*/ + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); + } + camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd); + + if (stream_cfg_cmd->cmd == START_STREAM) + rc = msm_isp_start_axi_stream( + vfe_dev, stream_cfg_cmd, camif_update); + else + rc = msm_isp_stop_axi_stream( + vfe_dev, stream_cfg_cmd, camif_update); + + if (rc < 0) + pr_err("%s: start/stop stream failed\n", __func__); + return rc; +} + +int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i, j; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; + struct msm_vfe_axi_stream_cfg_update_info *update_info; + + if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG && + atomic_read(&axi_data->axi_cfg_update)) { + pr_err("%s: AXI stream config updating\n", __func__); + return -EBUSY; + } + + /*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/ + if (update_cmd->num_streams > MAX_NUM_STREAM) + return -EINVAL; + + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + /*check array reference bounds*/ + if (HANDLE_TO_IDX(update_info->stream_handle) + > MAX_NUM_STREAM) { + return -EINVAL; + } + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(update_info->stream_handle)]; + if (stream_info->state != ACTIVE && + stream_info->state != INACTIVE) { + pr_err("%s: Invalid stream state\n", __func__); + return -EINVAL; + } + if (stream_info->state == ACTIVE && + stream_info->stream_type == BURST_STREAM && + (1 != update_cmd->num_streams || + UPDATE_STREAM_FRAMEDROP_PATTERN != + update_cmd->update_type)) { + pr_err("%s: Cannot update active burst stream\n", + __func__); + return -EINVAL; + } + } + + for (i = 0; i < update_cmd->num_streams; i++) { + update_info = &update_cmd->update_info[i]; + stream_info = &axi_data->stream_info[ + HANDLE_TO_IDX(update_info->stream_handle)]; + + switch (update_cmd->update_type) { + case ENABLE_STREAM_BUF_DIVERT: + stream_info->buf_divert = 1; + break; + case DISABLE_STREAM_BUF_DIVERT: + stream_info->buf_divert = 0; + vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_DIVERTED); + break; + case UPDATE_STREAM_FRAMEDROP_PATTERN: { + uint32_t framedrop_period = + msm_isp_get_framedrop_period( + update_info->skip_pattern); + stream_info->runtime_init_frame_drop = 0; + if (update_info->skip_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_framedrop(vfe_dev, stream_info); + break; + } + case UPDATE_STREAM_AXI_CONFIG: { + for (j = 0; j < stream_info->num_planes; j++) { + stream_info->plane_cfg[j] = + update_info->plane_cfg[j]; + } + stream_info->output_format = update_info->output_format; + if (stream_info->state == ACTIVE) { + stream_info->state = PAUSE_PENDING; + msm_isp_axi_stream_enable_cfg( + vfe_dev, stream_info); + stream_info->state = PAUSING; + atomic_set(&axi_data->axi_cfg_update, + UPDATE_REQUESTED); + } else { + for (j = 0; j < stream_info->num_planes; j++) + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + stream_info->runtime_output_format = + stream_info->output_format; + } + break; + } + case UPDATE_STREAM_REQUEST_FRAMES: { + stream_info->request_frm_num += + update_info->request_frm_num; + break; + } + default: + pr_err("%s: Invalid update type\n", __func__); + return -EINVAL; + } + } + return rc; +} + +void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int i, rc = 0; + struct msm_isp_buffer *done_buf = NULL; + uint32_t comp_mask = 0, wm_mask = 0; + uint32_t pingpong_status, stream_idx; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_composite_info *comp_info; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + uint32_t frame_id = 0; + + comp_mask = vfe_dev->hw_info->vfe_ops.axi_ops. + get_comp_mask(irq_status0, irq_status1); + wm_mask = vfe_dev->hw_info->vfe_ops.axi_ops. + get_wm_mask(irq_status0, irq_status1); + if (!(comp_mask || wm_mask)) + return; + + ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); + pingpong_status = + vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev); + for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { + rc = 0; + comp_info = &axi_data->composite_info[i]; + if (comp_mask & (1 << i)) { + if (!comp_info->stream_handle) { + pr_err("%s: Invalid handle for composite irq\n", + __func__); + } else { + stream_idx = + HANDLE_TO_IDX(comp_info->stream_handle); + stream_info = + &axi_data->stream_info[stream_idx]; + ISP_DBG("%s: stream%d frame id: 0x%x\n", + __func__, + stream_idx, stream_info->frame_id); + frame_id = vfe_dev->axi_data. + frame_id[stream_info->session_id]; + if (stream_info->frame_id >= frame_id) { + pr_err("%s: Session frm id %d cur frm id %d\n", + __func__, frame_id, + stream_info->frame_id); + return; + } + stream_info->frame_id = frame_id; + + if (stream_info->stream_type == BURST_STREAM) + stream_info-> + runtime_num_burst_capture--; + + msm_isp_get_done_buf(vfe_dev, stream_info, + pingpong_status, &done_buf); + if (stream_info->stream_type == + CONTINUOUS_STREAM || + stream_info-> + runtime_num_burst_capture >= 1) { + rc = msm_isp_cfg_ping_pong_address( + vfe_dev, stream_info, + pingpong_status); + } + if (done_buf && !rc) + msm_isp_process_done_buf(vfe_dev, + stream_info, done_buf, ts); + } + } + wm_mask &= ~(comp_info->stream_composite_mask); + } + + for (i = 0; i < axi_data->hw_info->num_wm; i++) { + if (wm_mask & (1 << i)) { + if (!axi_data->free_wm[i]) { + pr_err("%s: Invalid handle for wm irq\n", + __func__); + continue; + } + stream_idx = HANDLE_TO_IDX(axi_data->free_wm[i]); + stream_info = &axi_data->stream_info[stream_idx]; + frame_id = vfe_dev->axi_data. + frame_id[stream_info->session_id]; + ISP_DBG("%s: stream%d frame id: 0x%x\n", + __func__, + stream_idx, stream_info->frame_id); + if (stream_info->frame_id >= frame_id) { + pr_err("%s: Session frm id %d cur frm id %d\n", + __func__, frame_id, stream_info->frame_id); + return; + } + + if (stream_info->stream_type == BURST_STREAM) + stream_info->runtime_num_burst_capture--; + + msm_isp_get_done_buf(vfe_dev, stream_info, + pingpong_status, &done_buf); + if (stream_info->stream_type == CONTINUOUS_STREAM || + stream_info->runtime_num_burst_capture > 1) { + rc = msm_isp_cfg_ping_pong_address(vfe_dev, + stream_info, pingpong_status); + } + if (done_buf && !rc) + msm_isp_process_done_buf(vfe_dev, + stream_info, done_buf, ts); + } + } + return; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_axi_util.h new file mode 100644 index 0000000000000000000000000000000000000000..8ef7583af592eb7a1e4d4657fe6e16c9b7be161d --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_axi_util.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ +#ifndef __MSM_ISP_AXI_UTIL_H__ +#define __MSM_ISP_AXI_UTIL_H__ + +#include "msm_isp.h" + +int msm_isp_axi_create_stream( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); + +void msm_isp_axi_destroy_stream( + struct msm_vfe_axi_shared_data *axi_data, int stream_idx); + +int msm_isp_validate_axi_request( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); + +void msm_isp_axi_reserve_wm( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info); + +void msm_isp_axi_reserve_comp_mask( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream *stream_info); + +int msm_isp_axi_check_stream_state( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd); + +void msm_isp_calculate_framedrop( + struct msm_vfe_axi_shared_data *axi_data, + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); + +int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg); +void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev); + +void msm_isp_axi_stream_update(struct vfe_device *vfe_dev); + +void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev); +void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, + enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); +void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +#if defined(CONFIG_SR200PC20) && defined(CONFIG_SR544) +uint8_t msm_isp_get_curr_stream_cnt(struct vfe_device *vfe_dev); +#endif +#endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_stats_util.c new file mode 100644 index 0000000000000000000000000000000000000000..50b1940fc34c6f16b2b6ffd191dfcaffaaa4ce7b --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_stats_util.c @@ -0,0 +1,575 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include "msm_isp_util.h" +#include "msm_isp_stats_util.h" + +static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, + struct msm_isp_buffer **done_buf) +{ + int rc = -1; + struct msm_isp_buffer *buf; + uint32_t pingpong_bit = 0; + uint32_t bufq_handle = stream_info->bufq_handle; + uint32_t stats_pingpong_offset; + + if (STATS_IDX(stream_info->stream_handle) >= + vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, + STATS_IDX(stream_info->stream_handle)); + return -EINVAL; + } + + stats_pingpong_offset = + vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ + STATS_IDX(stream_info->stream_handle)]; + + pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); + rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, + vfe_dev->pdev->id, bufq_handle, &buf); + if (rc < 0) { + vfe_dev->error_info.stats_framedrop_count[ + STATS_IDX(stream_info->stream_handle)]++; + return rc; + } + + if (buf->num_planes != 1) { + pr_err("%s: Invalid buffer\n", __func__); + rc = -EINVAL; + goto buf_error; + } + + vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( + vfe_dev, stream_info, + pingpong_status, buf->mapped_info[0].paddr + + stream_info->buffer_offset); + + if (stream_info->buf[pingpong_bit] && done_buf) + *done_buf = stream_info->buf[pingpong_bit]; + + stream_info->buf[pingpong_bit] = buf; + return 0; +buf_error: + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + return rc; +} + +void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts) +{ + int i, j, rc; + struct msm_isp_event_data buf_event; + struct msm_isp_stats_event *stats_event = &buf_event.u.stats; + struct msm_isp_buffer *done_buf; + struct msm_vfe_stats_stream *stream_info = NULL; + uint32_t session_id = vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + uint32_t pingpong_status; + uint32_t comp_stats_type_mask = 0, atomic_stats_mask = 0; + uint32_t stats_comp_mask = 0, stats_irq_mask = 0; + uint32_t num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + stats_comp_mask = vfe_dev->hw_info->vfe_ops.stats_ops. + get_comp_mask(irq_status0, irq_status1); + stats_irq_mask = vfe_dev->hw_info->vfe_ops.stats_ops. + get_wm_mask(irq_status0, irq_status1); + if (!(stats_comp_mask || stats_irq_mask)) + return; + ISP_DBG("%s: status: 0x%x\n", __func__, irq_status0); + + /* + * If any of composite mask is set, clear irq bits from mask, + * they will be restored by comp mask + */ + if (stats_comp_mask) { + for (j = 0; j < num_stats_comp_mask; j++) { + stats_irq_mask &= ~atomic_read( + &vfe_dev->stats_data.stats_comp_mask[j]); + } + } + + for (j = 0; j < num_stats_comp_mask; j++) { + atomic_stats_mask = atomic_read( + &vfe_dev->stats_data.stats_comp_mask[j]); + if (!stats_comp_mask) { + stats_irq_mask &= ~atomic_stats_mask; + } else { + /* restore irq bits from composite mask */ + if (stats_comp_mask & (1 << j)) + stats_irq_mask |= atomic_stats_mask; + } + /* if no irq bits set from this composite mask continue*/ + if (!stats_irq_mask) + continue; + memset(&buf_event, 0, sizeof(struct msm_isp_event_data)); + buf_event.timestamp = ts->event_time; + buf_event.frame_id = + vfe_dev->axi_data.frame_id[session_id]; + buf_event.input_intf = VFE_PIX_0; + pingpong_status = vfe_dev->hw_info-> + vfe_ops.stats_ops.get_pingpong_status(vfe_dev); + + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; + i++) { + if (!(stats_irq_mask & (1 << i))) + continue; + stream_info = &vfe_dev->stats_data.stream_info[i]; + done_buf = NULL; + msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, pingpong_status, &done_buf); + if (done_buf) { + rc = vfe_dev->buf_mgr->ops->buf_divert( + vfe_dev->buf_mgr, done_buf->bufq_handle, + done_buf->buf_idx, &ts->buf_time, + vfe_dev->axi_data. + frame_id[session_id]); + if (rc != 0) + continue; + + stats_event->stats_buf_idxs + [stream_info->stats_type] = + done_buf->buf_idx; + if (!stream_info->composite_flag) { + stats_event->stats_mask = + 1 << stream_info->stats_type; + ISP_DBG("%s: stats frameid: 0x%x %d\n", + __func__, buf_event.frame_id, + stream_info->stats_type); + msm_isp_send_event(vfe_dev, + ISP_EVENT_STATS_NOTIFY + + stream_info->stats_type, + &buf_event); + } else { + comp_stats_type_mask |= + 1 << stream_info->stats_type; + } + } + stats_irq_mask &= ~(1 << i); + } + + if (comp_stats_type_mask) { + ISP_DBG("%s: comp_stats frameid: 0x%x, 0x%x\n", + __func__, buf_event.frame_id, + comp_stats_type_mask); + stats_event->stats_mask = comp_stats_type_mask; + msm_isp_send_event(vfe_dev, + ISP_EVENT_COMP_STATS_NOTIFY, &buf_event); + comp_stats_type_mask = 0; + } + } +} + +int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd) +{ + int rc = -1; + struct msm_vfe_stats_stream *stream_info = NULL; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t stats_idx; + + if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask & + (1 << stream_req_cmd->stats_type))) { + pr_err("%s: Stats type not supported\n", __func__); + return rc; + } + + stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. + get_stats_idx(stream_req_cmd->stats_type); + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + if (stream_info->state != STATS_AVALIABLE) { + pr_err("%s: Stats already requested\n", __func__); + return rc; + } + + if (stream_req_cmd->framedrop_pattern >= MAX_SKIP) { + pr_err("%s: Invalid framedrop pattern\n", __func__); + return rc; + } + + if (stream_req_cmd->irq_subsample_pattern >= MAX_SKIP) { + pr_err("%s: Invalid irq subsample pattern\n", __func__); + return rc; + } + + stream_info->session_id = stream_req_cmd->session_id; + stream_info->stream_id = stream_req_cmd->stream_id; + stream_info->composite_flag = stream_req_cmd->composite_flag; + stream_info->stats_type = stream_req_cmd->stats_type; + stream_info->buffer_offset = stream_req_cmd->buffer_offset; + stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern; + stream_info->irq_subsample_pattern = + stream_req_cmd->irq_subsample_pattern; + stream_info->state = STATS_INACTIVE; + + if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0) + vfe_dev->stats_data.stream_handle_cnt++; + + stream_req_cmd->stream_handle = + (++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx; + + stream_info->stream_handle = stream_req_cmd->stream_handle; + return 0; +} + +int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = -1; + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg; + struct msm_vfe_stats_stream *stream_info = NULL; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + uint32_t framedrop_period; + uint32_t stats_idx; + + rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd); + if (rc < 0) { + pr_err("%s: create stream failed\n", __func__); + return rc; + } + + stats_idx = STATS_IDX(stream_req_cmd->stream_handle); + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + + framedrop_period = msm_isp_get_framedrop_period( + stream_req_cmd->framedrop_pattern); + + if (stream_req_cmd->framedrop_pattern == SKIP_ALL) + stream_info->framedrop_pattern = 0x0; + else + stream_info->framedrop_pattern = 0x1; + stream_info->framedrop_period = framedrop_period - 1; + + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, stream_info); + return rc; +} + +int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = -1; + struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; + struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + int stats_idx = STATS_IDX(stream_release_cmd->stream_handle); + struct msm_vfe_stats_stream *stream_info = NULL; + + if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, stats_idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[stats_idx]; + if (stream_info->state == STATS_AVALIABLE) { + pr_err("%s: stream already release\n", __func__); + return rc; + } else if (stream_info->state != STATS_INACTIVE) { + stream_cfg_cmd.enable = 0; + stream_cfg_cmd.num_streams = 1; + stream_cfg_cmd.stream_handle[0] = + stream_release_cmd->stream_handle; + rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + } + + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + + vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); + memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream)); + return 0; +} + +static int msm_isp_init_stats_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int rc = 0; + stream_info->bufq_handle = + vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, stream_info->session_id, + stream_info->stream_id); + if (stream_info->bufq_handle == 0) { + pr_err("%s: no buf configured for stream: 0x%x\n", + __func__, stream_info->stream_handle); + return -EINVAL; + } + + rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PING_FLAG, NULL); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", __func__); + return rc; + } + rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, + stream_info, VFE_PONG_FLAG, NULL); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", __func__); + return rc; + } + return rc; +} + +static void msm_isp_deinit_stats_ping_pong_reg( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int i; + struct msm_isp_buffer *buf; + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + if (buf) + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + } +} + +void msm_isp_stats_stream_update(struct vfe_device *vfe_dev) +{ + int i; + uint32_t stats_mask = 0, comp_stats_mask = 0; + uint32_t enable = 0; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { + if (stats_data->stream_info[i].state == STATS_START_PENDING || + stats_data->stream_info[i].state == + STATS_STOP_PENDING) { + stats_mask |= i; + enable = stats_data->stream_info[i].state == + STATS_START_PENDING ? 1 : 0; + stats_data->stream_info[i].state = + stats_data->stream_info[i].state == + STATS_START_PENDING ? + STATS_STARTING : STATS_STOPPING; + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, BIT(i), enable); + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, BIT(i), enable); + } else if (stats_data->stream_info[i].state == STATS_STARTING || + stats_data->stream_info[i].state == STATS_STOPPING) { + if (stats_data->stream_info[i].composite_flag) + comp_stats_mask |= i; + stats_data->stream_info[i].state = + stats_data->stream_info[i].state == + STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE; + } + } + atomic_sub(1, &stats_data->stats_update); + if (!atomic_read(&stats_data->stats_update)) + complete(&vfe_dev->stats_config_complete); +} + +static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev) +{ + int rc; + init_completion(&vfe_dev->stats_config_complete); + atomic_set(&vfe_dev->stats_data.stats_update, 2); + rc = wait_for_completion_timeout( + &vfe_dev->stats_config_complete, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + if (rc == 0) { + pr_err("%s: wait timeout\n", __func__); + rc = -1; + } else { + rc = 0; + } + return rc; +} + +static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t stats_mask = 0, idx; + uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams( + stats_data->stream_info); + if (rc < 0) + return rc; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + if (stream_info->stream_handle != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received\n", + __func__, stream_cfg_cmd->stream_handle[i]); + continue; + } + + if (stream_info->composite_flag > num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_info->composite_flag, + num_stats_comp_mask); + return -EINVAL; + } + rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); + if (rc < 0) { + pr_err("%s: No buffer for stream%d\n", __func__, idx); + return rc; + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) + stream_info->state = STATS_START_PENDING; + else + stream_info->state = STATS_ACTIVE; + + stats_data->num_active_stream++; + stats_mask |= 1 << idx; + + if (stream_info->composite_flag > 0) + comp_stats_mask[stream_info->composite_flag-1] |= + 1 << idx; + + ISP_DBG("%s: stats_mask %x %x active streams %d\n", + __func__, comp_stats_mask[0], + comp_stats_mask[1], + stats_data->num_active_stream); + + } + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); + } else { + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (i = 0; i < num_stats_comp_mask; i++) { + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, comp_stats_mask[i], 1); + } + } + return rc; +} + +static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t stats_mask = 0, idx; + uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + if (stream_info->stream_handle != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received\n", + __func__, stream_cfg_cmd->stream_handle[i]); + continue; + } + + if (stream_info->composite_flag > num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_info->composite_flag, + num_stats_comp_mask); + return -EINVAL; + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) + stream_info->state = STATS_STOP_PENDING; + else + stream_info->state = STATS_INACTIVE; + + stats_data->num_active_stream--; + stats_mask |= 1 << idx; + + if (stream_info->composite_flag > 0) + comp_stats_mask[stream_info->composite_flag-1] |= + 1 << idx; + + ISP_DBG("%s: stats_mask %x %x active streams %d\n", + __func__, comp_stats_mask[0], + comp_stats_mask[1], + stats_data->num_active_stream); + } + + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); + } else { + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (i = 0; i < num_stats_comp_mask; i++) { + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( + vfe_dev, comp_stats_mask[i], 0); + } + } + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); + + if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { + pr_err("%s Invalid stats index %d", __func__, idx); + return -EINVAL; + } + + stream_info = &stats_data->stream_info[idx]; + msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info); + } + return rc; +} + +int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg; + struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + stats_data->stats_burst_len = stream_cfg_cmd->stats_burst_len; + + if (vfe_dev->stats_data.num_active_stream == 0) + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); + + if (stream_cfg_cmd->enable) + rc = msm_isp_start_stats_stream(vfe_dev, stream_cfg_cmd); + else + rc = msm_isp_stop_stats_stream(vfe_dev, stream_cfg_cmd); + + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_stats_util.h new file mode 100644 index 0000000000000000000000000000000000000000..7b4c4b4eb0dc6a75d5fd87153fc031b377902c85 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_stats_util.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ +#ifndef __MSM_ISP_STATS_UTIL_H__ +#define __MSM_ISP_STATS_UTIL_H__ + +#include "msm_isp.h" +#define STATS_IDX(idx) (idx & 0xFF) + +void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1, + struct msm_isp_timestamp *ts); +void msm_isp_stats_stream_update(struct vfe_device *vfe_dev); +int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg); +int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg); +#endif /* __MSM_ISP_STATS_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_util.c new file mode 100644 index 0000000000000000000000000000000000000000..3383b0b471353d43443df9469c4f23df796fd8a7 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_util.c @@ -0,0 +1,1660 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include + +#include "msm.h" +#include "msm_isp_util.h" +#include "msm_isp_axi_util.h" +#include "msm_isp_stats_util.h" +#include "msm_camera_io_util.h" + +#define MAX_ISP_V4l2_EVENTS 100 +static DEFINE_MUTEX(bandwidth_mgr_mutex); +static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr; + +#define MSM_ISP_MIN_AB 450000000 +#define MSM_ISP_MIN_IB 900000000 +#define MSM_MIN_REQ_VFE_CPP_BW 1700000000 + +#define VFE40_8974V2_VERSION 0x1001001A + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) +#define CAMERA_BOOST +#endif + +#ifdef CAMERA_BOOST +#define MBYTE (1ULL << 20) + +#define BW_MBPS(_bw) \ +{ \ + .vectors = &(struct msm_bus_vectors){ \ + .src = 1, \ + .dst = 512, \ + .ib = (_bw) * MBYTE, \ + .ab = 0, \ + }, \ + .num_paths = 1, \ +} + +static struct msm_bus_paths bw_level_tbl[] = { + [0] = BW_MBPS(381), /* At least 50 MHz on bus. */ + [1] = BW_MBPS(4066), /* At least 533 MHz on bus. */ +}; + +static struct msm_bus_scale_pdata bus_client_pdata = { + .usecase = bw_level_tbl, + .num_usecases = ARRAY_SIZE(bw_level_tbl), + .active_only = 1, + .name = "Camera_boost", +}; + +static u32 bus_client; +#endif + +static struct msm_bus_vectors msm_isp_init_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors msm_isp_ping_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = MSM_ISP_MIN_AB, + .ib = MSM_ISP_MIN_IB, + }, +}; + +static struct msm_bus_vectors msm_isp_pong_vectors[] = { + { + .src = MSM_BUS_MASTER_VFE, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = MSM_ISP_MIN_AB, + .ib = MSM_ISP_MIN_IB, + }, +}; + +static struct msm_bus_paths msm_isp_bus_client_config[] = { + { + ARRAY_SIZE(msm_isp_init_vectors), + msm_isp_init_vectors, + }, + { + ARRAY_SIZE(msm_isp_ping_vectors), + msm_isp_ping_vectors, + }, + { + ARRAY_SIZE(msm_isp_pong_vectors), + msm_isp_pong_vectors, + }, +}; + +static struct msm_bus_scale_pdata msm_isp_bus_client_pdata = { + msm_isp_bus_client_config, + ARRAY_SIZE(msm_isp_bus_client_config), + .name = "msm_camera_isp", +}; + +static void msm_isp_print_fourcc_error(const char *origin, + uint32_t fourcc_format) +{ + int i; + char text[5]; + text[4] = '\0'; + for (i = 0; i < 4; i++) { + text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF); + if ((text[i] < '0') || (text[i] > 'z')) { + pr_err("%s: Invalid output format %d (unprintable)\n", + origin, fourcc_format); + return; + } + } + pr_err("%s: Invalid output format %s\n", + origin, text); + return; +} + +#ifdef CONFIG_COMPAT +struct msm_vfe_cfg_cmd2_32 { + uint16_t num_cfg; + uint16_t cmd_len; + compat_caddr_t cfg_data; + compat_caddr_t cfg_cmd; +}; + +#define VIDIOC_MSM_VFE_REG_CFG_COMPAT \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2_32) +#endif /* CONFIG_COMPAT */ + +int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client) +{ + int rc = 0; + mutex_lock(&bandwidth_mgr_mutex); + isp_bandwidth_mgr.client_info[client].active = 1; + if (isp_bandwidth_mgr.use_count++) { + mutex_unlock(&bandwidth_mgr_mutex); + return rc; + } + isp_bandwidth_mgr.bus_client = + msm_bus_scale_register_client(&msm_isp_bus_client_pdata); + if (!isp_bandwidth_mgr.bus_client) { + pr_err("%s: client register failed\n", __func__); + mutex_unlock(&bandwidth_mgr_mutex); + return -EINVAL; + } + + isp_bandwidth_mgr.bus_vector_active_idx = 1; + msm_bus_scale_client_update_request( + isp_bandwidth_mgr.bus_client, + isp_bandwidth_mgr.bus_vector_active_idx); + +#ifdef CAMERA_BOOST + if (!bus_client) { + bus_client = msm_bus_scale_register_client(&bus_client_pdata); + msm_bus_scale_client_update_request(bus_client, 1); + } +#endif + + mutex_unlock(&bandwidth_mgr_mutex); + return 0; +} + +int msm_isp_update_bandwidth(enum msm_isp_hw_client client, + uint64_t ab, uint64_t ib) +{ + int i; + struct msm_bus_paths *path; + mutex_lock(&bandwidth_mgr_mutex); + if (!isp_bandwidth_mgr.use_count || + !isp_bandwidth_mgr.bus_client) { + pr_err("%s:error bandwidth manager inactive use_cnt:%d bus_clnt:%d\n", + __func__, isp_bandwidth_mgr.use_count, + isp_bandwidth_mgr.bus_client); + return -EINVAL; + } + + isp_bandwidth_mgr.client_info[client].ab = ab; + isp_bandwidth_mgr.client_info[client].ib = ib; + ALT_VECTOR_IDX(isp_bandwidth_mgr.bus_vector_active_idx); + path = + &(msm_isp_bus_client_pdata.usecase[ + isp_bandwidth_mgr.bus_vector_active_idx]); + path->vectors[0].ab = MSM_ISP_MIN_AB; + path->vectors[0].ib = MSM_ISP_MIN_IB; + for (i = 0; i < MAX_ISP_CLIENT; i++) { + if (isp_bandwidth_mgr.client_info[i].active) { + path->vectors[0].ab += + isp_bandwidth_mgr.client_info[i].ab; + path->vectors[0].ib += + isp_bandwidth_mgr.client_info[i].ib; + } + } + /* All the clients combined i.e. VFE + CPP should use at least + minimum recommended bandwidth */ + if (path->vectors[0].ib < MSM_MIN_REQ_VFE_CPP_BW) + path->vectors[0].ib = MSM_MIN_REQ_VFE_CPP_BW; + msm_bus_scale_client_update_request(isp_bandwidth_mgr.bus_client, + isp_bandwidth_mgr.bus_vector_active_idx); + mutex_unlock(&bandwidth_mgr_mutex); + return 0; +} + +void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client) +{ + mutex_lock(&bandwidth_mgr_mutex); + memset(&isp_bandwidth_mgr.client_info[client], 0, + sizeof(struct msm_isp_bandwidth_info)); + if (--isp_bandwidth_mgr.use_count) { + mutex_unlock(&bandwidth_mgr_mutex); + return; + } + + if (!isp_bandwidth_mgr.bus_client) { + pr_err("%s:%d error: bus client invalid\n", __func__, __LINE__); + mutex_unlock(&bandwidth_mgr_mutex); + return; + } + + msm_bus_scale_client_update_request( + isp_bandwidth_mgr.bus_client, 0); + msm_bus_scale_unregister_client(isp_bandwidth_mgr.bus_client); + +#ifdef CAMERA_BOOST + msm_bus_scale_client_update_request(bus_client, 0); + msm_bus_scale_unregister_client(bus_client); + bus_client = 0; +#endif + + isp_bandwidth_mgr.bus_client = 0; + mutex_unlock(&bandwidth_mgr_mutex); +} + +uint32_t msm_isp_get_framedrop_period( + enum msm_vfe_frame_skip_pattern frame_skip_pattern) +{ + switch (frame_skip_pattern) { + case NO_SKIP: + case EVERY_2FRAME: + case EVERY_3FRAME: + case EVERY_4FRAME: + case EVERY_5FRAME: + case EVERY_6FRAME: + case EVERY_7FRAME: + case EVERY_8FRAME: + return frame_skip_pattern + 1; + case EVERY_16FRAME: + return 16; + break; + case EVERY_32FRAME: + return 32; + break; + case SKIP_ALL: + return 1; + default: + return 1; + } + return 1; +} + +int msm_isp_get_clk_info(struct vfe_device *vfe_dev, + struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info) +{ + uint32_t count; + int i, rc; + uint32_t rates[VFE_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + ISP_DBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > VFE_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + VFE_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(vfe_clk_info[i].clk_name)); + ISP_DBG("clock-names[%d] = %s\n", i, vfe_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + vfe_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + ISP_DBG("clk_rate[%d] = %ld\n", i, vfe_clk_info[i].clk_rate); + } + vfe_dev->num_clk = count; + return 0; +} + +static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp) +{ + struct timespec ts; + ktime_get_ts(&ts); + time_stamp->buf_time.tv_sec = ts.tv_sec; + time_stamp->buf_time.tv_usec = ts.tv_nsec/1000; + do_gettimeofday(&(time_stamp->event_time)); +} + +int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + int rc = 0; + rc = v4l2_event_subscribe(fh, sub, MAX_ISP_V4l2_EVENTS, NULL); + if (rc == 0) { + if (sub->type == V4L2_EVENT_ALL) { + int i; + + vfe_dev->axi_data.event_mask = 0; + for (i = 0; i < ISP_EVENT_MAX; i++) + vfe_dev->axi_data.event_mask |= (1 << i); + } else { + int event_idx = sub->type - ISP_EVENT_BASE; + + vfe_dev->axi_data.event_mask |= (1 << event_idx); + } + } + return rc; +} + +int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + rc = v4l2_event_unsubscribe(fh, sub); + if (sub->type == V4L2_EVENT_ALL) { + vfe_dev->axi_data.event_mask = 0; + } else { + int event_idx = sub->type - ISP_EVENT_BASE; + + vfe_dev->axi_data.event_mask &= ~(1 << event_idx); + } + return rc; +} + +static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate) +{ + int clk_idx = 0; + unsigned long max_value = ~0; + long round_rate = 0; + + if (!vfe_dev || !rate) { + pr_err("%s:%d failed: vfe_dev %p rate %p\n", __func__, __LINE__, + vfe_dev, rate); + return -EINVAL; + } + + *rate = 0; + if (!vfe_dev->hw_info) { + pr_err("%s:%d failed: vfe_dev->hw_info %p\n", __func__, + __LINE__, vfe_dev->hw_info); + return -EINVAL; + } + + clk_idx = vfe_dev->hw_info->vfe_clk_idx; + if (clk_idx >= vfe_dev->num_clk) { + pr_err("%s:%d failed: clk_idx %d max array size %d\n", + __func__, __LINE__, clk_idx, + vfe_dev->num_clk); + return -EINVAL; + } + + round_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], max_value); + if (round_rate < 0) { + pr_err("%s: Invalid vfe clock rate\n", __func__); + return -EINVAL; + } + + *rate = round_rate; + return 0; +} + +static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate) +{ + int rc = 0; + int clk_idx = vfe_dev->hw_info->vfe_clk_idx; + long round_rate = + clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); + if (round_rate < 0) { + pr_err("%s: Invalid vfe clock rate\n", __func__); + return round_rate; + } + + rc = clk_set_rate(vfe_dev->vfe_clk[clk_idx], round_rate); + if (rc < 0) { + pr_err("%s: Vfe set rate error\n", __func__); + return rc; + } + *rate = round_rate; + return 0; +} + +int msm_isp_cfg_pix(struct vfe_device *vfe_dev, + struct msm_vfe_input_cfg *input_cfg) +{ + int rc = 0; + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { + pr_err("%s: pixel path is active\n", __func__); + return -EINVAL; + } + + vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock = + input_cfg->input_pix_clk; + vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux = + input_cfg->d.pix_cfg.input_mux; + vfe_dev->axi_data.src_info[VFE_PIX_0].width = + input_cfg->d.pix_cfg.camif_cfg.pixels_per_line; + + rc = msm_isp_set_clk_rate(vfe_dev, + &vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock); + if (rc < 0) { + pr_err("%s: clock set rate failed\n", __func__); + return rc; + } + + vfe_dev->axi_data.src_info[VFE_PIX_0].input_format = + input_cfg->d.pix_cfg.input_format; + + vfe_dev->hw_info->vfe_ops.core_ops.cfg_camif( + vfe_dev, &input_cfg->d.pix_cfg); + return rc; +} + +int msm_isp_cfg_rdi(struct vfe_device *vfe_dev, + struct msm_vfe_input_cfg *input_cfg) +{ + int rc = 0; + if (vfe_dev->axi_data.src_info[input_cfg->input_src].active) { + pr_err("%s: RAW%d path is active\n", __func__, + input_cfg->input_src - VFE_RAW_0); + return -EINVAL; + } + + vfe_dev->axi_data.src_info[input_cfg->input_src].pixel_clock = + input_cfg->input_pix_clk; + vfe_dev->hw_info->vfe_ops.core_ops.cfg_rdi_reg( + vfe_dev, &input_cfg->d.rdi_cfg, input_cfg->input_src); + return rc; +} + +int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_input_cfg *input_cfg = arg; + + switch (input_cfg->input_src) { + case VFE_PIX_0: + rc = msm_isp_cfg_pix(vfe_dev, input_cfg); + break; + case VFE_RAW_0: + case VFE_RAW_1: + case VFE_RAW_2: + rc = msm_isp_cfg_rdi(vfe_dev, input_cfg); + break; + default: + pr_err("%s: Invalid input source\n", __func__); + rc = -EINVAL; + } + return rc; +} + +static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + long rc = 0; + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + + /* use real time mutex for hard real-time ioctls such as + * buffer operations and register updates. + * Use core mutex for other ioctls that could take + * longer time to complete such as start/stop ISP streams + * which blocks until the hardware start/stop streaming + */ + ISP_DBG("%s cmd: %d\n", __func__, _IOC_TYPE(cmd)); + switch (cmd) { + case VIDIOC_MSM_VFE_REG_CFG: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_cmd(vfe_dev, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_VFE_REG_LIST_CFG: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_cmd_list(vfe_dev, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_ISP_REQUEST_BUF: + case VIDIOC_MSM_ISP_ENQUEUE_BUF: + case VIDIOC_MSM_ISP_RELEASE_BUF: { + mutex_lock(&vfe_dev->realtime_mutex); + rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + case VIDIOC_MSM_ISP_REQUEST_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_request_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_RELEASE_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_release_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_CFG_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_INPUT_CFG: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_input(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_REG_UPDATE_CMD: + if (arg) { + enum msm_vfe_input_src frame_src = *((enum msm_vfe_input_src *)arg); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, (1 << frame_src)); + } + break; + case VIDIOC_MSM_ISP_SET_SRC_STATE: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_set_src_state(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_request_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_release_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_CFG_STATS_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_cfg_stats_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case VIDIOC_MSM_ISP_UPDATE_STREAM: + mutex_lock(&vfe_dev->core_mutex); + rc = msm_isp_update_axi_stream(vfe_dev, arg); + mutex_unlock(&vfe_dev->core_mutex); + break; + case MSM_SD_SHUTDOWN: + while (vfe_dev->vfe_open_cnt != 0) + msm_isp_close_node(sd, NULL); + break; + + default: + pr_err_ratelimited("%s: Invalid ISP command\n", __func__); + rc = -EINVAL; + } + return rc; +} + +#ifdef CONFIG_COMPAT +static long msm_isp_ioctl_compat(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + long rc = 0; + void __user *up; + if (is_compat_task()) { + up = compat_ptr((unsigned long)arg); + arg = up; + } + + switch (cmd) { + case VIDIOC_MSM_VFE_REG_CFG_COMPAT: { + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + struct msm_vfe_cfg_cmd2 proc_cmd; + struct msm_vfe_cfg_cmd2_32 *proc_cmd_ptr32; + mutex_lock(&vfe_dev->realtime_mutex); + proc_cmd_ptr32 = (struct msm_vfe_cfg_cmd2_32 *) + compat_ptr((unsigned long)arg); + proc_cmd.num_cfg = proc_cmd_ptr32->num_cfg; + proc_cmd.cmd_len = proc_cmd_ptr32->cmd_len; + proc_cmd.cfg_data = compat_ptr(proc_cmd_ptr32->cfg_data); + proc_cmd.cfg_cmd = compat_ptr(proc_cmd_ptr32->cfg_cmd); + rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd); + mutex_unlock(&vfe_dev->realtime_mutex); + break; + } + default: + return msm_isp_ioctl_unlocked(sd, cmd, arg); + } + + return rc; +} + +long msm_isp_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_isp_ioctl_compat(sd, cmd, arg); +} +#else /* CONFIG_COMPAT */ +long msm_isp_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_isp_ioctl_unlocked(sd, cmd, arg); +} +#endif /* CONFIG_COMPAT */ + +static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, + struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd, + uint32_t *cfg_data, uint32_t cmd_len) +{ + if (!vfe_dev || !reg_cfg_cmd) { + pr_err("%s:%d failed: vfe_dev %p reg_cfg_cmd %p\n", __func__, + __LINE__, vfe_dev, reg_cfg_cmd); + return -EINVAL; + } + if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) && + (!cfg_data || !cmd_len)) { + pr_err("%s:%d failed: cmd type %d cfg_data %p cmd_len %d\n", + __func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data, + cmd_len); + return -EINVAL; + } + + /* Validate input parameters */ + switch (reg_cfg_cmd->cmd_type) { + case VFE_WRITE: + case VFE_READ: + case VFE_WRITE_MB: { + if ((reg_cfg_cmd->u.rw_info.reg_offset > + (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) || + ((reg_cfg_cmd->u.rw_info.reg_offset + + reg_cfg_cmd->u.rw_info.len) > + resource_size(vfe_dev->vfe_mem))) { + pr_err("%s:%d reg_offset %d len %d res %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.rw_info.reg_offset, + reg_cfg_cmd->u.rw_info.len, + (uint32_t)resource_size(vfe_dev->vfe_mem)); + return -EINVAL; + } + + if ((reg_cfg_cmd->u.rw_info.cmd_data_offset > + (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) || + ((reg_cfg_cmd->u.rw_info.cmd_data_offset + + reg_cfg_cmd->u.rw_info.len) > cmd_len)) { + pr_err("%s:%d cmd_data_offset %d len %d cmd_len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.rw_info.cmd_data_offset, + reg_cfg_cmd->u.rw_info.len, cmd_len); + return -EINVAL; + } + break; + } + + case VFE_WRITE_DMI_16BIT: + case VFE_WRITE_DMI_32BIT: + case VFE_WRITE_DMI_64BIT: + case VFE_READ_DMI_16BIT: + case VFE_READ_DMI_32BIT: + case VFE_READ_DMI_64BIT: { + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { + if ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset <= + reg_cfg_cmd->u.dmi_info.lo_tbl_offset) || + (reg_cfg_cmd->u.dmi_info.hi_tbl_offset - + reg_cfg_cmd->u.dmi_info.lo_tbl_offset != + (sizeof(uint32_t)))) { + pr_err("%s:%d hi %d lo %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset); + return -EINVAL; + } + if (reg_cfg_cmd->u.dmi_info.len <= sizeof(uint32_t)) { + pr_err("%s:%d len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.len); + return -EINVAL; + } + if (((UINT_MAX - + reg_cfg_cmd->u.dmi_info.hi_tbl_offset) < + (reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t))) || + ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset + + reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t)) > cmd_len)) { + pr_err("%s:%d hi_tbl_offset %d len %d cmd %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); + return -EINVAL; + } + } + if ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset > + (UINT_MAX - reg_cfg_cmd->u.dmi_info.len)) || + ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset + + reg_cfg_cmd->u.dmi_info.len) > cmd_len)) { + pr_err("%s:%d lo_tbl_offset %d len %d cmd_len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.lo_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); + return -EINVAL; + } + break; + } + + default: + break; + } + + switch (reg_cfg_cmd->cmd_type) { + case VFE_WRITE: { + msm_camera_io_memcpy(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset, + cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, + reg_cfg_cmd->u.rw_info.len); + break; + } + case VFE_WRITE_MB: { + msm_camera_io_memcpy_mb(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset, + cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, + reg_cfg_cmd->u.rw_info.len); + break; + } + case VFE_CFG_MASK: { + uint32_t temp; + if ((UINT_MAX - sizeof(temp) < + reg_cfg_cmd->u.mask_info.reg_offset) || + (resource_size(vfe_dev->vfe_mem) < + reg_cfg_cmd->u.mask_info.reg_offset + + sizeof(temp))) { + pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__); + return -EINVAL; + } + temp = msm_camera_io_r(vfe_dev->vfe_base + + reg_cfg_cmd->u.mask_info.reg_offset); + + temp &= ~reg_cfg_cmd->u.mask_info.mask; + temp |= reg_cfg_cmd->u.mask_info.val; + msm_camera_io_w(temp, vfe_dev->vfe_base + + reg_cfg_cmd->u.mask_info.reg_offset); + break; + } + case VFE_WRITE_DMI_16BIT: + case VFE_WRITE_DMI_32BIT: + case VFE_WRITE_DMI_64BIT: { + int i; + uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; + uint32_t hi_val, lo_val, lo_val1; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { + hi_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; + } + lo_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) + reg_cfg_cmd->u.dmi_info.len = + reg_cfg_cmd->u.dmi_info.len / 2; + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { + lo_val = *lo_tbl_ptr++; + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) { + lo_val1 = lo_val & 0x0000FFFF; + lo_val = (lo_val & 0xFFFF0000)>>16; + msm_camera_io_w(lo_val1, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + } else if (reg_cfg_cmd->cmd_type == + VFE_WRITE_DMI_64BIT) { + lo_tbl_ptr++; + hi_val = *hi_tbl_ptr; + hi_tbl_ptr = hi_tbl_ptr + 2; + msm_camera_io_w(hi_val, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + } + msm_camera_io_w(lo_val, vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + } + break; + } + case VFE_READ_DMI_16BIT: + case VFE_READ_DMI_32BIT: + case VFE_READ_DMI_64BIT: { + int i; + uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; + uint32_t hi_val, lo_val, lo_val1; + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + hi_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; + } + lo_tbl_ptr = cfg_data + + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; + + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) + reg_cfg_cmd->u.dmi_info.len = + reg_cfg_cmd->u.dmi_info.len / 2; + + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { + lo_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_16BIT) { + lo_val1 = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset + 0x4); + lo_val |= lo_val1 << 16; + } + *lo_tbl_ptr++ = lo_val; + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + hi_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + *hi_tbl_ptr = hi_val; + hi_tbl_ptr += 2; + lo_tbl_ptr++; + } + } + break; + } + case VFE_HW_UPDATE_LOCK: { + uint32_t session_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + uint32_t update_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id; + if (vfe_dev->axi_data.frame_id[session_id] != *cfg_data + || update_id == *cfg_data) { + pr_err("hw update lock failed,acquire id %u\n", + *cfg_data); + pr_err("hw update lock failed,current id %u\n", + vfe_dev->axi_data.frame_id[session_id]); + pr_err("hw update lock failed,last id %u\n", + update_id); + return -EINVAL; + } + break; + } + case VFE_HW_UPDATE_UNLOCK: { + uint32_t session_id = + vfe_dev->axi_data.src_info[VFE_PIX_0].session_id; + if (vfe_dev->axi_data.frame_id[session_id] + != *cfg_data) { + pr_err("hw update across frame boundary,begin id %u\n", + *cfg_data); + pr_err("hw update across frame boundary,end id %u\n", + vfe_dev->axi_data.frame_id[session_id]); + } + vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id = + vfe_dev->axi_data.frame_id[session_id]; + break; + } + case VFE_READ: { + int i; + uint32_t *data_ptr = cfg_data + + reg_cfg_cmd->u.rw_info.cmd_data_offset/4; + for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) { + if ((data_ptr < cfg_data) || + (UINT_MAX / sizeof(*data_ptr) < + (data_ptr - cfg_data)) || + (sizeof(*data_ptr) * (data_ptr - cfg_data) >= + cmd_len)) + return -EINVAL; + *data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset); + reg_cfg_cmd->u.rw_info.reg_offset += 4; + } + break; + } + case GET_MAX_CLK_RATE: { + int rc = 0; + + if (cmd_len < sizeof(unsigned long)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(unsigned long)); + return -EINVAL; + } + rc = msm_isp_get_max_clk_rate(vfe_dev, + (unsigned long *)cfg_data); + if (rc < 0) { + pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc); + return -EINVAL; + } + break; + } + case GET_ISP_ID: { + uint32_t *isp_id = NULL; + + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %u\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } + + isp_id = (uint32_t *)cfg_data; + *isp_id = vfe_dev->pdev->id; + break; + } + case SET_WM_UB_SIZE: { + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } + vfe_dev->vfe_ub_size = *cfg_data; + break; + } + } + return 0; +} + +int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0, i; + struct msm_vfe_cfg_cmd2 *proc_cmd = arg; + struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd; + uint32_t *cfg_data = NULL; + + if (!proc_cmd->num_cfg) { + pr_err("%s: Passed num_cfg as 0\n", __func__); + return -EINVAL; + } + + reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)* + proc_cmd->num_cfg, GFP_KERNEL); + if (!reg_cfg_cmd) { + pr_err("%s: reg_cfg alloc failed\n", __func__); + rc = -ENOMEM; + goto reg_cfg_failed; + } + + if (copy_from_user(reg_cfg_cmd, + (void __user *)(proc_cmd->cfg_cmd), + sizeof(struct msm_vfe_reg_cfg_cmd) * proc_cmd->num_cfg)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + + if (proc_cmd->cmd_len > 0) { + cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL); + if (!cfg_data) { + pr_err("%s: cfg_data alloc failed\n", __func__); + rc = -ENOMEM; + goto cfg_data_failed; + } + + if (copy_from_user(cfg_data, + (void __user *)(proc_cmd->cfg_data), + proc_cmd->cmd_len)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + } + + //pr_err("%s: platform_id=%u, kernel_id=%u\n", __func__,proc_cmd->frame_id, vfe_dev->frame_id); + if( (vfe_dev->frame_id == proc_cmd->frame_id && vfe_dev->eof_event_occur != 1) + || proc_cmd->frame_id == 0) { + for (i = 0; i < proc_cmd->num_cfg; i++) + msm_isp_send_hw_cmd(vfe_dev, ®_cfg_cmd[i], cfg_data, proc_cmd->cmd_len); + } else{ + rc = MSM_VFE_REG_CFG_FRAME_ID_NOT_MATCH_ERROR; + pr_err("%s: skip hw update, platform_id=%u, kernel_id=%u, eof_event_occur=%u\n", + __func__,proc_cmd->frame_id, vfe_dev->frame_id, vfe_dev->eof_event_occur); + } + + if (copy_to_user(proc_cmd->cfg_data, + cfg_data, proc_cmd->cmd_len)) { + rc = -EFAULT; + goto copy_cmd_failed; + } + +copy_cmd_failed: + kfree(cfg_data); +cfg_data_failed: + kfree(reg_cfg_cmd); +reg_cfg_failed: + return rc; +} + +int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg) +{ + int rc = 0; + struct msm_vfe_cfg_cmd_list *proc_cmd = + (struct msm_vfe_cfg_cmd_list *)arg; + struct msm_vfe_cfg_cmd_list cmd, cmd_next; + + if (!vfe_dev || !arg) { + pr_err("%s:%d failed: vfe_dev %p arg %p", __func__, __LINE__, + vfe_dev, arg); + return -EINVAL; + } + + rc = msm_isp_proc_cmd(vfe_dev, &proc_cmd->cfg_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = *proc_cmd; + + while (cmd.next) { + if (cmd.next_size != sizeof(struct msm_vfe_cfg_cmd_list)) { + pr_err("%s:%d failed: next size %u != expected %zu\n", + __func__, __LINE__, cmd.next_size, + sizeof(struct msm_vfe_cfg_cmd_list)); + break; + } + if (copy_from_user(&cmd_next, (void __user *)cmd.next, + sizeof(struct msm_vfe_cfg_cmd_list))) { + rc = -EFAULT; + continue; + } + + rc = msm_isp_proc_cmd(vfe_dev, &cmd_next.cfg_cmd); + if (rc < 0) + pr_err("%s:%d failed: rc %d", __func__, __LINE__, rc); + + cmd = cmd_next; + } + return rc; +} + +int msm_isp_send_event(struct vfe_device *vfe_dev, + uint32_t event_type, + struct msm_isp_event_data *event_data) +{ + struct v4l2_event isp_event; + memset(&isp_event, 0, sizeof(struct v4l2_event)); + isp_event.id = 0; + isp_event.type = event_type; + memcpy(&isp_event.u.data[0], event_data, + sizeof(struct msm_isp_event_data)); + v4l2_event_queue(vfe_dev->subdev.sd.devnode, &isp_event); + return 0; +} + +#define CAL_WORD(width, M, N) ((width * M + N - 1) / N) + +int msm_isp_cal_word_per_line(uint32_t output_format, + uint32_t pixel_per_line) +{ + int val = -1; + switch (output_format) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + val = CAL_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + val = CAL_WORD(pixel_per_line, 5, 32); + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + val = CAL_WORD(pixel_per_line, 3, 16); + break; + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + val = CAL_WORD(pixel_per_line, 1, 6); + break; + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + val = CAL_WORD(pixel_per_line, 1, 5); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + val = CAL_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + val = CAL_WORD(pixel_per_line, 2, 8); + break; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, output_format); + break; + } + return val; +} + +enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format) +{ + switch (output_format) { + 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: + return MIPI; + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + return QCOM; + default: + msm_isp_print_fourcc_error(__func__, output_format); + break; + } + return -EINVAL; +} + +int msm_isp_get_bit_per_pixel(uint32_t output_format) +{ + switch (output_format) { + case V4L2_PIX_FMT_Y4: + return 4; + case V4L2_PIX_FMT_Y6: + return 6; + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_QBGGR8: + case V4L2_PIX_FMT_QGBRG8: + case V4L2_PIX_FMT_QGRBG8: + case V4L2_PIX_FMT_QRGGB8: + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_META: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV14: + case V4L2_PIX_FMT_NV41: + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YYUV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV411P: + case V4L2_PIX_FMT_Y41P: + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_PAL8: + case V4L2_PIX_FMT_UV8: + case MSM_V4L2_PIX_FMT_META: + return 8; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_QBGGR10: + case V4L2_PIX_FMT_QGBRG10: + case V4L2_PIX_FMT_QGRBG10: + case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y10BPACK: + return 10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_QBGGR12: + case V4L2_PIX_FMT_QGBRG12: + case V4L2_PIX_FMT_QGRBG12: + case V4L2_PIX_FMT_QRGGB12: + case V4L2_PIX_FMT_Y12: + return 12; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_Y16: + return 16; + /*TD: Add more image format*/ + default: + msm_isp_print_fourcc_error(__func__, output_format); +#if defined(CONFIG_SR200PC20) + return 8; +#else + return -EINVAL; +#endif + } +} + +void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev) +{ + struct msm_vfe_error_info *error_info = &vfe_dev->error_info; + error_info->info_dump_frame_count++; + if (error_info->info_dump_frame_count == 0) + error_info->info_dump_frame_count++; +} + +void msm_isp_process_error_info(struct vfe_device *vfe_dev) +{ + int i; + uint8_t num_stats_type = + vfe_dev->hw_info->stats_hw_info->num_stats_type; + struct msm_vfe_error_info *error_info = &vfe_dev->error_info; + static DEFINE_RATELIMIT_STATE(rs, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + static DEFINE_RATELIMIT_STATE(rs_stats, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + + if (error_info->error_count == 1 || + !(error_info->info_dump_frame_count % 100)) { + vfe_dev->hw_info->vfe_ops.core_ops. + process_error_status(vfe_dev); + error_info->error_mask0 = 0; + error_info->error_mask1 = 0; + error_info->camif_status = 0; + error_info->violation_status = 0; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (error_info->stream_framedrop_count[i] != 0 && + __ratelimit(&rs)) { + pr_err("%s: Stream[%d]: dropped %d frames\n", + __func__, i, + error_info->stream_framedrop_count[i]); + error_info->stream_framedrop_count[i] = 0; + } + } + for (i = 0; i < num_stats_type; i++) { + if (error_info->stats_framedrop_count[i] != 0 && + __ratelimit(&rs_stats)) { + pr_err("%s: Stats stream[%d]: dropped %d frames\n", + __func__, i, + error_info->stats_framedrop_count[i]); + error_info->stats_framedrop_count[i] = 0; + } + } + } +} + +static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev, + uint32_t error_mask0, uint32_t error_mask1) +{ + vfe_dev->error_info.error_mask0 |= error_mask0; + vfe_dev->error_info.error_mask1 |= error_mask1; + vfe_dev->error_info.error_count++; +} + +static inline void msm_isp_process_overflow_irq( + struct vfe_device *vfe_dev, + uint32_t *irq_status0, uint32_t *irq_status1) +{ + uint32_t overflow_mask; + uint32_t halt_restart_mask0, halt_restart_mask1; +#if defined(CONFIG_SR200PC20) && defined(CONFIG_SR544) + uint8_t cur_stream_cnt = 0; +#endif + /*Mask out all other irqs if recovery is started*/ + if (atomic_read(&vfe_dev->error_info.overflow_state) != + NO_OVERFLOW) { + vfe_dev->hw_info->vfe_ops.core_ops. + get_halt_restart_mask(&halt_restart_mask0, + &halt_restart_mask1); + *irq_status0 &= halt_restart_mask0; + *irq_status1 &= halt_restart_mask1; + return; + } + + /*Check if any overflow bit is set*/ + vfe_dev->hw_info->vfe_ops.core_ops. + get_overflow_mask(&overflow_mask); + overflow_mask &= *irq_status1; + if (overflow_mask) { +#if defined(CONFIG_SR200PC20) && defined(CONFIG_SR544) + cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev); + if (cur_stream_cnt == 0) { + /* When immediate stop is issued during streamoff and + AXI bridge is halted, if write masters are still + active, then it's possible to get overflow Irq + because WM is still writing pixels into UB, but UB + has no way to write into bus. Since everything is + being stopped anyway, skip the overflow recovery */ + return; + } +#endif + pr_err("%s: Bus overflow detected: 0x%x\n", + __func__, overflow_mask); + atomic_set(&vfe_dev->error_info.overflow_state, + OVERFLOW_DETECTED); + pr_err("%s: Start bus overflow recovery\n", __func__); + /*Store current IRQ mask*/ + vfe_dev->hw_info->vfe_ops.core_ops.get_irq_mask(vfe_dev, + &vfe_dev->error_info.overflow_recover_irq_mask0, + &vfe_dev->error_info.overflow_recover_irq_mask1); + /*Stop CAMIF Immediately*/ + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + /*Halt the hardware & Clear all other IRQ mask*/ + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0); + /*Update overflow state*/ + atomic_set(&vfe_dev->error_info.overflow_state, HALT_REQUESTED); + *irq_status0 = 0; + *irq_status1 = 0; + } +} + +static inline void msm_isp_reset_burst_count( + struct vfe_device *vfe_dev) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; + struct msm_vfe_axi_stream_request_cmd framedrop_info; + memset(&framedrop_info, 0, sizeof(struct msm_vfe_axi_stream_request_cmd)); + for (i = 0; i < MAX_NUM_STREAM; i++) { + stream_info = &axi_data->stream_info[i]; + if (stream_info->state != ACTIVE) + continue; + if (stream_info->stream_type == BURST_STREAM && + stream_info->num_burst_capture != 0) { + framedrop_info.axi_stream_handle = i; + framedrop_info.burst_count = + stream_info->num_burst_capture; + framedrop_info.frame_skip_pattern = + stream_info->frame_skip_pattern; + framedrop_info.init_frame_drop = 0; + msm_isp_calculate_framedrop(&vfe_dev->axi_data, + &framedrop_info); + } + } +} + +static void msm_isp_process_overflow_recovery( + struct vfe_device *vfe_dev, + uint32_t irq_status0, uint32_t irq_status1) +{ + uint32_t halt_restart_mask0, halt_restart_mask1; + vfe_dev->hw_info->vfe_ops.core_ops. + get_halt_restart_mask(&halt_restart_mask0, + &halt_restart_mask1); + irq_status0 &= halt_restart_mask0; + irq_status1 &= halt_restart_mask1; + if (irq_status0 == 0 && irq_status1 == 0) + return; + + switch (atomic_read(&vfe_dev->error_info.overflow_state)) { + case HALT_REQUESTED: { + pr_err("%s: Halt done, Restart Pending\n", __func__); + /*Reset the hardware*/ + vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, + ISP_RST_SOFT, 0); + /*Update overflow state*/ + atomic_set(&vfe_dev->error_info.overflow_state, + RESTART_REQUESTED); + } + break; + case RESTART_REQUESTED: { + pr_err("%s: Restart done, Resuming\n", __func__); + /*Reset the burst stream frame drop pattern, in the + *case where bus overflow happens during the burstshot, + *the framedrop pattern might be updated after reg update + *to skip all the frames after the burst shot. The burst shot + *might not be completed due to the overflow, so the framedrop + *pattern need to change back to the original settings in order + *to recovr from overflow. + */ + msm_isp_reset_burst_count(vfe_dev); + vfe_dev->hw_info->vfe_ops.axi_ops. + reload_wm(vfe_dev, 0xFFFFFFFF); + vfe_dev->hw_info->vfe_ops.core_ops.restore_irq_mask(vfe_dev); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, (1 << VFE_PIX_0)); + memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); + atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW); + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, ENABLE_CAMIF); + } + break; + case NO_OVERFLOW: + case OVERFLOW_DETECTED: + default: + break; + } +} + +irqreturn_t msm_isp_process_irq(int irq_num, void *data) +{ + unsigned long flags; + struct msm_vfe_tasklet_queue_cmd *queue_cmd; + struct vfe_device *vfe_dev = (struct vfe_device *) data; + uint32_t irq_status0, irq_status1; + uint32_t error_mask0, error_mask1; + + vfe_dev->hw_info->vfe_ops.irq_ops. + read_irq_status(vfe_dev, &irq_status0, &irq_status1); + if ((irq_status0 == 0) && (irq_status1 == 0)) { + pr_err_ratelimited("%s: irq_status0 & 1 are both 0\n", + __func__); + return IRQ_HANDLED; + } + msm_isp_process_overflow_irq(vfe_dev, + &irq_status0, &irq_status1); + vfe_dev->hw_info->vfe_ops.core_ops. + get_error_mask(&error_mask0, &error_mask1); + error_mask0 &= irq_status0; + error_mask1 &= irq_status1; + irq_status0 &= ~error_mask0; + irq_status1 &= ~error_mask1; + if (!vfe_dev->ignore_error && + ((error_mask0 != 0) || (error_mask1 != 0))) + msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1); + + if ((irq_status0 == 0) && (irq_status1 == 0) && + (!(((error_mask0 != 0) || (error_mask1 != 0)) && + vfe_dev->error_info.error_count == 1))) { + ISP_DBG("%s: irq status 0 and 1 = 0, also error irq hadnled!\n", + __func__); + return IRQ_HANDLED; + } + + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx]; + if (queue_cmd->cmd_used) { + pr_err_ratelimited("%s: Tasklet queue overflow: %d\n", + __func__, vfe_dev->pdev->id); + list_del(&queue_cmd->list); + } else { + atomic_add(1, &vfe_dev->irq_cnt); + } + queue_cmd->vfeInterruptStatus0 = irq_status0; + queue_cmd->vfeInterruptStatus1 = irq_status1; + msm_isp_get_timestamp(&queue_cmd->ts); + queue_cmd->cmd_used = 1; + vfe_dev->taskletq_idx = + (vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE; + list_add_tail(&queue_cmd->list, &vfe_dev->tasklet_q); + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + tasklet_schedule(&vfe_dev->vfe_tasklet); + return IRQ_HANDLED; +} + +void msm_isp_do_tasklet(unsigned long data) +{ + unsigned long flags; + struct vfe_device *vfe_dev = (struct vfe_device *) data; + struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; + struct msm_vfe_tasklet_queue_cmd *queue_cmd; + struct msm_isp_timestamp ts; + uint32_t irq_status0, irq_status1; + while (atomic_read(&vfe_dev->irq_cnt)) { + spin_lock_irqsave(&vfe_dev->tasklet_lock, flags); + queue_cmd = list_first_entry(&vfe_dev->tasklet_q, + struct msm_vfe_tasklet_queue_cmd, list); + if (!queue_cmd) { + atomic_set(&vfe_dev->irq_cnt, 0); + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + return; + } + atomic_sub(1, &vfe_dev->irq_cnt); + list_del(&queue_cmd->list); + queue_cmd->cmd_used = 0; + irq_status0 = queue_cmd->vfeInterruptStatus0; + irq_status1 = queue_cmd->vfeInterruptStatus1; + ts = queue_cmd->ts; + spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags); + if (atomic_read(&vfe_dev->error_info.overflow_state) != + NO_OVERFLOW) { + pr_err_ratelimited("There is Overflow, kicking up recovery !!!!"); + msm_isp_process_overflow_recovery(vfe_dev, + irq_status0, irq_status1); + continue; + } + ISP_DBG("%s: status0: 0x%x status1: 0x%x\n", + __func__, irq_status0, irq_status1); + irq_ops->process_reset_irq(vfe_dev, + irq_status0, irq_status1); + irq_ops->process_halt_irq(vfe_dev, + irq_status0, irq_status1); + irq_ops->process_camif_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_axi_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_stats_irq(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_reg_update(vfe_dev, + irq_status0, irq_status1, &ts); + irq_ops->process_epoch_irq(vfe_dev, + irq_status0, irq_status1, &ts); + msm_isp_process_error_info(vfe_dev); + } +} + +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg) +{ + struct msm_vfe_axi_src_state *src_state = arg; + if (src_state->input_src >= VFE_SRC_MAX) + return -EINVAL; + vfe_dev->axi_data.src_info[src_state->input_src].active = + src_state->src_active; + return 0; +} + +int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + long rc; + ISP_DBG("%s\n", __func__); + + mutex_lock(&vfe_dev->realtime_mutex); + mutex_lock(&vfe_dev->core_mutex); + + if (vfe_dev->vfe_open_cnt++) { + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; + } + + if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) { + pr_err("%s: init hardware failed\n", __func__); + vfe_dev->vfe_open_cnt--; + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EBUSY; + } + + rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, + ISP_RST_HARD, 1); + if (rc <= 0) { + pr_err("%s: reset timeout\n", __func__); + vfe_dev->vfe_open_cnt--; + vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EINVAL; + } + vfe_dev->vfe_hw_version = msm_camera_io_r(vfe_dev->vfe_base); + ISP_DBG("%s: HW Version: 0x%x\n", __func__, vfe_dev->vfe_hw_version); + + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + + vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 28); + + memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data)); + memset(&vfe_dev->stats_data, 0, + sizeof(struct msm_vfe_stats_shared_data)); + memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info)); + vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info; + vfe_dev->taskletq_idx = 0; + vfe_dev->vt_enable = 0; + vfe_dev->p_avtimer_lsw = NULL; + vfe_dev->p_avtimer_msw = NULL; + vfe_dev->p_avtimer_ctl = NULL; + vfe_dev->avtimer_scaler = 1; /*No scaling*/ + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; +} + +#if 0 //CONFIG_MSM_AVTIMER +void msm_isp_end_avtimer(void) +{ + avcs_core_disable_power_collapse(0); +} +#else +void msm_isp_end_avtimer(void) +{ + pr_err("AV Timer is not supported\n"); +} +#endif + +int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + long rc; + struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + ISP_DBG("%s\n", __func__); + mutex_lock(&vfe_dev->realtime_mutex); + mutex_lock(&vfe_dev->core_mutex); + + if (!vfe_dev->vfe_open_cnt) { + pr_err("%s invalid state open cnt %d\n", __func__, + vfe_dev->vfe_open_cnt); + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return -EINVAL; + } + + if (--vfe_dev->vfe_open_cnt) { + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; + } + + rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + if (rc <= 0) + pr_err("%s: halt timeout rc=%ld\n", __func__, rc); + + vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr); + vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev); + if (vfe_dev->vt_enable) { + iounmap(vfe_dev->p_avtimer_lsw); + iounmap(vfe_dev->p_avtimer_msw); + iounmap(vfe_dev->p_avtimer_ctl); + msm_isp_end_avtimer(); + vfe_dev->vt_enable = 0; + vfe_dev->avtimer_scaler = 1; + } + mutex_unlock(&vfe_dev->core_mutex); + mutex_unlock(&vfe_dev->realtime_mutex); + return 0; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_util.h new file mode 100644 index 0000000000000000000000000000000000000000..da1a968d8be68fae8b84182334ececd736d2b9c4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/isp/msm_isp_util.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ +#ifndef __MSM_ISP_UTIL_H__ +#define __MSM_ISP_UTIL_H__ + +#include "msm_isp.h" +#include "../include/soc/qcom/camera2.h" + +/* #define CONFIG_MSM_ISP_DBG 1 */ + +#ifdef CONFIG_MSM_ISP_DBG +#define ISP_DBG(fmt, args...) printk(fmt, ##args) +#else +#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define ALT_VECTOR_IDX(x) {x = 3 - x; } +struct msm_isp_bandwidth_info { + uint32_t active; + uint64_t ab; + uint64_t ib; +}; + +enum msm_isp_hw_client { + ISP_VFE0, + ISP_VFE1, + ISP_CPP, + MAX_ISP_CLIENT, +}; + +struct msm_isp_bandwidth_mgr { + uint32_t bus_client; + uint32_t bus_vector_active_idx; + uint32_t use_count; + struct msm_isp_bandwidth_info client_info[MAX_ISP_CLIENT]; +}; + +uint32_t msm_isp_get_framedrop_period( + enum msm_vfe_frame_skip_pattern frame_skip_pattern); + +int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client); +int msm_isp_update_bandwidth(enum msm_isp_hw_client client, + uint64_t ab, uint64_t ib); +void msm_isp_deinit_bandwidth_mgr(enum msm_isp_hw_client client); + +int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + +int msm_isp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + +int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg); +int msm_isp_send_event(struct vfe_device *vfe_dev, + uint32_t type, struct msm_isp_event_data *event_data); +int msm_isp_cal_word_per_line(uint32_t output_format, + uint32_t pixel_per_line); +int msm_isp_get_bit_per_pixel(uint32_t output_format); +enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format); +irqreturn_t msm_isp_process_irq(int irq_num, void *data); +int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); +void msm_isp_do_tasklet(unsigned long data); +void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev); +void msm_isp_process_error_info(struct vfe_device *vfe_dev); +int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg); +int msm_isp_proc_cmd_list(struct vfe_device *vfe_dev, void *arg); +int msm_isp_get_clk_info(struct vfe_device *vfe_dev, + struct platform_device *pdev, struct msm_cam_clk_info *vfe_clk_info); + +#endif /* __MSM_ISP_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/ispif/Makefile b/drivers/media/platform/msm/camera_v2_j5/ispif/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..640aefc8c6538c189e4fee3996d32a3eb7b7e834 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/ispif/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSM_CSID) += msm_ispif.o diff --git a/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif.c new file mode 100644 index 0000000000000000000000000000000000000000..705f49268f8d956d1249ca939fc420c28dc2c6bd --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif.c @@ -0,0 +1,1368 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/media/msmb_isp.h" + +#include "msm_ispif.h" +#include "msm.h" +#include "msm_sd.h" +#include "msm_camera_io_util.h" + +#ifdef CONFIG_MSM_ISPIF_V1 +#include "msm_ispif_hwreg_v1.h" +#else +#include "msm_ispif_hwreg_v2.h" +#endif + +#define V4L2_IDENT_ISPIF 50001 +#define MSM_ISPIF_DRV_NAME "msm_ispif" + +#define ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY 0x00 +#define ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY 0x01 +#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02 + +#define ISPIF_TIMEOUT_SLEEP_US 1000 +#define ISPIF_TIMEOUT_ALL_US 1000000 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static void msm_ispif_io_dump_reg(struct ispif_device *ispif) +{ + if (!ispif->enb_dump_reg) + return; + msm_camera_io_dump(ispif->base, 0x250); +} + + +static inline int msm_ispif_is_intf_valid(uint32_t csid_version, + uint8_t intf_type) +{ + return ((csid_version <= CSID_VERSION_V22 && intf_type != VFE0) || + (intf_type >= VFE_MAX)) ? false : true; +} + +static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { + {"ispif_ahb_clk", NO_SET_RATE}, + {"camss_top_ahb_clk", NO_SET_RATE}, + {"csi0_ahb_clk", NO_SET_RATE}, + {"csi0_src_clk", NO_SET_RATE}, + {"csi0_phy_clk", NO_SET_RATE}, + {"csi0_clk", NO_SET_RATE}, + {"csi0_pix_clk", NO_SET_RATE}, + {"csi0_rdi_clk", NO_SET_RATE}, + {"csi1_ahb_clk", NO_SET_RATE}, + {"csi1_src_clk", NO_SET_RATE}, + {"csi1_phy_clk", NO_SET_RATE}, + {"csi1_clk", NO_SET_RATE}, + {"csi1_pix_clk", NO_SET_RATE}, + {"csi1_rdi_clk", NO_SET_RATE}, + {"camss_vfe_vfe_clk", NO_SET_RATE}, + {"camss_csi_vfe_clk", NO_SET_RATE}, +}; + +static struct msm_cam_clk_info ispif_8974_ahb_clk_info[ISPIF_CLK_INFO_MAX]; + +static struct msm_cam_clk_info ispif_8974_reset_clk_info[] = { + {"csi0_src_clk", INIT_RATE}, + {"csi0_clk", NO_SET_RATE}, + {"csi0_pix_clk", NO_SET_RATE}, + {"csi0_rdi_clk", NO_SET_RATE}, + {"csi1_src_clk", INIT_RATE}, + {"csi1_clk", NO_SET_RATE}, + {"csi1_pix_clk", NO_SET_RATE}, + {"csi1_rdi_clk", NO_SET_RATE}, + {"csi2_src_clk", INIT_RATE}, + {"csi2_clk", NO_SET_RATE}, + {"csi2_pix_clk", NO_SET_RATE}, + {"csi2_rdi_clk", NO_SET_RATE}, + {"csi3_src_clk", INIT_RATE}, + {"csi3_clk", NO_SET_RATE}, + {"csi3_pix_clk", NO_SET_RATE}, + {"csi3_rdi_clk", NO_SET_RATE}, + {"vfe0_clk_src", INIT_RATE}, + {"camss_vfe_vfe0_clk", NO_SET_RATE}, + {"camss_csi_vfe0_clk", NO_SET_RATE}, + {"vfe1_clk_src", INIT_RATE}, + {"camss_vfe_vfe1_clk", NO_SET_RATE}, + {"camss_csi_vfe1_clk", NO_SET_RATE}, +}; + +static int msm_ispif_reset_hw(struct ispif_device *ispif) +{ + int rc = 0; + long timeout = 0; + struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)]; + struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)]; + ispif->clk_idx = 0; + + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 1); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 1); + if (rc < 0) { + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } else { + /* This is set when device is 8x26 */ + ispif->clk_idx = 2; + } + } else { + /* This is set when device is 8974 */ + ispif->clk_idx = 1; + } + + init_completion(&ispif->reset_complete[VFE0]); + if (ispif->hw_num_isps > 1) + init_completion(&ispif->reset_complete[VFE1]); + + /* initiate reset of ISPIF */ + msm_camera_io_w(ISPIF_RST_CMD_MASK, + ispif->base + ISPIF_RST_CMD_ADDR); + if (ispif->hw_num_isps > 1) + msm_camera_io_w(ISPIF_RST_CMD_1_MASK, + ispif->base + ISPIF_RST_CMD_1_ADDR); + + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE0], msecs_to_jiffies(500)); + CDBG("%s: VFE0 done\n", __func__); + + if (timeout <= 0) { + pr_err("%s: VFE0 reset wait timeout\n", __func__); + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) + pr_err("%s: VFE0 reset wait timeout\n", + __func__); + } + return -ETIMEDOUT; + } + + if (ispif->hw_num_isps > 1) { + timeout = wait_for_completion_timeout( + &ispif->reset_complete[VFE1], + msecs_to_jiffies(500)); + CDBG("%s: VFE1 done\n", __func__); + if (timeout <= 0) { + pr_err("%s: VFE1 reset wait timeout\n", __func__); + msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + return -ETIMEDOUT; + } + } + + if (ispif->clk_idx == 1) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_reset_clk_info, reset_clk, + ARRAY_SIZE(ispif_8974_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + } + } + + if (ispif->clk_idx == 2) { + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8626_reset_clk_info, reset_clk1, + ARRAY_SIZE(ispif_8626_reset_clk_info), 0); + if (rc < 0) { + pr_err("%s: cannot disable clock, error = %d", + __func__, rc); + } + } + + return rc; +} + +int msm_ispif_get_ahb_clk_info(struct ispif_device *ispif_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[ISPIF_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + CDBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + count = ISPIF_AHB_CLK_INFO; + if (count > ISPIF_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + ISPIF_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(ispif_8974_ahb_clk_info[i].clk_name)); + CDBG("clock-names[%d] = %s\n", + i, ispif_8974_ahb_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + ispif_8974_ahb_clk_info[i].clk_rate = + (rates[i] == 0) ? -1 : rates[i]; + CDBG("clk_rate[%d] = %ld\n", i, + ispif_8974_ahb_clk_info[i].clk_rate); + } + ispif_dev->num_clk = count; + return 0; +} + +static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable) +{ + int rc = 0; + + if (ispif->csid_version < CSID_VERSION_V30) { + /* Older ISPIF versiond don't need ahb clokc */ + return 0; + } + + rc = msm_ispif_get_ahb_clk_info(ispif, ispif->pdev); + if (rc < 0) { + pr_err("%s: msm_isp_get_clk_info() failed", __func__); + return -EFAULT; + } + + rc = msm_cam_clk_enable(&ispif->pdev->dev, + ispif_8974_ahb_clk_info, ispif->ahb_clk, + ispif->num_clk, enable); + if (rc < 0) { + pr_err("%s: cannot enable clock, error = %d", + __func__, rc); + } + + return rc; +} + +static int msm_ispif_reset(struct ispif_device *ispif) +{ + int rc = 0; + int i; + + BUG_ON(!ispif); + + memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); + for (i = 0; i < ispif->vfe_info.num_vfe; i++) { + + msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT, + ispif->base + ISPIF_VFE_m_CTRL_0(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i)); + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_0(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_1(i)); + msm_camera_io_w(0xFFFFFFFF, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_2(i)); + + msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i)); + + msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, + ispif->base + ISPIF_VFE_m_INTF_CMD_0(i)); + msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY, + ispif->base + ISPIF_VFE_m_INTF_CMD_1(i)); + pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2)); + + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0)); + msm_camera_io_w(0, ispif->base + + ISPIF_VFE_m_PIX_INTF_n_CROP(i, 1)); + } + + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + return rc; +} + +static int msm_ispif_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_ISPIF; + chip->revision = 0; + return 0; +} + +static void msm_ispif_sel_csid_core(struct ispif_device *ispif, + uint8_t intftype, uint8_t csid, uint8_t vfe_intf) +{ + uint32_t data; + + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); + switch (intftype) { + case PIX0: + data &= ~(BIT(1) | BIT(0)); + data |= csid; + break; + case RDI0: + data &= ~(BIT(5) | BIT(4)); + data |= (csid << 4); + break; + case PIX1: + data &= ~(BIT(9) | BIT(8)); + data |= (csid << 8); + break; + case RDI1: + data &= ~(BIT(13) | BIT(12)); + data |= (csid << 12); + break; + case RDI2: + data &= ~(BIT(21) | BIT(20)); + data |= (csid << 20); + break; + } + + msm_camera_io_w_mb(data, ispif->base + + ISPIF_VFE_m_INPUT_SEL(vfe_intf)); +} + +static void msm_ispif_enable_crop(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint16_t start_pixel, + uint16_t end_pixel) +{ + uint32_t data; + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + data = msm_camera_io_r(ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); + data |= (1 << (intftype + 7)); + if (intftype == PIX0) + data |= 1 << PIX0_LINE_BUF_EN_BIT; + msm_camera_io_w(data, + ispif->base + ISPIF_VFE_m_CTRL_0(vfe_intf)); + + if (intftype == PIX0) + msm_camera_io_w_mb(start_pixel | (end_pixel << 16), + ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 0)); + else if (intftype == PIX1) + msm_camera_io_w_mb(start_pixel | (end_pixel << 16), + ispif->base + ISPIF_VFE_m_PIX_INTF_n_CROP(vfe_intf, 1)); + else { + pr_err("%s: invalid intftype=%d\n", __func__, intftype); + BUG_ON(1); + return; + } +} + +static void msm_ispif_enable_intf_cids(struct ispif_device *ispif, + uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf, uint8_t enable) +{ + uint32_t intf_addr, data; + + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + + switch (intftype) { + case PIX0: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 0); + break; + case RDI0: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 0); + break; + case PIX1: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe_intf, 1); + break; + case RDI1: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 1); + break; + case RDI2: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe_intf, 2); + break; + default: + pr_err("%s: invalid intftype=%d\n", __func__, intftype); + BUG_ON(1); + return; + } + + data = msm_camera_io_r(ispif->base + intf_addr); + if (enable) + data |= cid_mask; + else + data &= ~cid_mask; + msm_camera_io_w_mb(data, ispif->base + intf_addr); +} + +static int msm_ispif_validate_intf_status(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf) +{ + int rc = 0; + uint32_t data = 0; + + BUG_ON(!ispif); + + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return -EINVAL; + } + + switch (intftype) { + case PIX0: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0)); + break; + case RDI0: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0)); + break; + case PIX1: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1)); + break; + case RDI1: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1)); + break; + case RDI2: + data = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2)); + break; + } + if ((data & 0xf) != 0xf) + rc = -EBUSY; + return rc; +} + +static void msm_ispif_select_clk_mux(struct ispif_device *ispif, + uint8_t intftype, uint8_t csid, uint8_t vfe_intf) +{ + uint32_t data = 0; + + switch (intftype) { + case PIX0: + data = msm_camera_io_r(ispif->clk_mux_base); + data &= ~(0xf << (vfe_intf * 8)); + data |= (csid << (vfe_intf * 8)); + msm_camera_io_w(data, ispif->clk_mux_base); + break; + + case RDI0: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (vfe_intf * 12)); + data |= (csid << (vfe_intf * 12)); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + + case PIX1: + data = msm_camera_io_r(ispif->clk_mux_base); + data &= ~(0xf0 << (vfe_intf * 8)); + data |= (csid << (4 + (vfe_intf * 8))); + msm_camera_io_w(data, ispif->clk_mux_base); + break; + + case RDI1: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (4 + (vfe_intf * 12))); + data |= (csid << (4 + (vfe_intf * 12))); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + + case RDI2: + data = msm_camera_io_r(ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + data &= ~(0xf << (8 + (vfe_intf * 12))); + data |= (csid << (8 + (vfe_intf * 12))); + msm_camera_io_w(data, ispif->clk_mux_base + + ISPIF_RDI_CLK_MUX_SEL_ADDR); + break; + } + CDBG("%s intftype %d data %x\n", __func__, intftype, data); + mb(); + return; +} + +static uint16_t msm_ispif_get_cids_mask_from_cfg( + struct msm_ispif_params_entry *entry) +{ + int i; + uint16_t cids_mask = 0; + + BUG_ON(!entry); + + for (i = 0; i < entry->num_cids; i++) + cids_mask |= (1 << entry->cids[i]); + + return cids_mask; +} + +static int msm_ispif_config(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int rc = 0, i = 0; + uint16_t cid_mask; + enum msm_ispif_intftype intftype; + enum msm_ispif_vfe_intf vfe_intf; + + BUG_ON(!ispif); + BUG_ON(!params); + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; + if (!msm_ispif_is_intf_valid(ispif->csid_version, + vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return -EINVAL; + } + msm_camera_io_w(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); + msm_camera_io_w(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); + msm_camera_io_w_mb(0x0, ispif->base + + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); + } + + for (i = 0; i < params->num; i++) { + intftype = params->entries[i].intftype; + + vfe_intf = params->entries[i].vfe_intf; + + CDBG("%s intftype %x, vfe_intf %d, csid %d\n", __func__, + intftype, vfe_intf, params->entries[i].csid); + + if ((intftype >= INTF_MAX) || + (vfe_intf >= ispif->vfe_info.num_vfe) || + (ispif->csid_version <= CSID_VERSION_V22 && + (vfe_intf > VFE0))) { + pr_err("%s: VFEID %d and CSID version %d mismatch\n", + __func__, vfe_intf, ispif->csid_version); + return -EINVAL; + } + + if (ispif->csid_version >= CSID_VERSION_V30) + msm_ispif_select_clk_mux(ispif, intftype, + params->entries[i].csid, vfe_intf); + + rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf); + if (rc) { + pr_err("%s:validate_intf_status failed, rc = %d\n", + __func__, rc); + return rc; + } + + msm_ispif_sel_csid_core(ispif, intftype, + params->entries[i].csid, vfe_intf); + cid_mask = msm_ispif_get_cids_mask_from_cfg( + ¶ms->entries[i]); + msm_ispif_enable_intf_cids(ispif, intftype, + cid_mask, vfe_intf, 1); + if (params->entries[i].crop_enable) + msm_ispif_enable_crop(ispif, intftype, vfe_intf, + params->entries[i].crop_start_pixel, + params->entries[i].crop_end_pixel); + } + + for (vfe_intf = 0; vfe_intf < 2; vfe_intf++) { + msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_0(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_0(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_1(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_1(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + + ISPIF_VFE_m_IRQ_MASK_2(vfe_intf)); + + msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base + + ISPIF_VFE_m_IRQ_CLEAR_2(vfe_intf)); + } + + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + return rc; +} + +static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits, + struct msm_ispif_param_data *params) +{ + uint8_t vc; + int i, k; + enum msm_ispif_intftype intf_type; + enum msm_ispif_cid cid; + enum msm_ispif_vfe_intf vfe_intf; + + BUG_ON(!ispif); + BUG_ON(!params); + + for (i = 0; i < params->num; i++) { + vfe_intf = params->entries[i].vfe_intf; + if (!msm_ispif_is_intf_valid(ispif->csid_version, vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + return; + } + if (params->entries[i].num_cids > MAX_CID_CH) { + pr_err("%s: out of range of cid_num %d\n", + __func__, params->entries[i].num_cids); + return; + } + } + + for (i = 0; i < params->num; i++) { + intf_type = params->entries[i].intftype; + vfe_intf = params->entries[i].vfe_intf; + for (k = 0; k < params->entries[i].num_cids; k++) { + cid = params->entries[i].cids[k]; + vc = cid / 4; + if (intf_type == RDI2) { + /* zero out two bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &= + ~(0x3 << (vc * 2 + 8)); + /* set cmd bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd1 |= + (cmd_bits << (vc * 2 + 8)); + } else { + /* zero 2 bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd &= + ~(0x3 << (vc * 2 + intf_type * 8)); + /* set cmd bits */ + ispif->applied_intf_cmd[vfe_intf].intf_cmd |= + (cmd_bits << (vc * 2 + intf_type * 8)); + } + } + + /* cmd for PIX0, PIX1, RDI0, RDI1 */ + if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF) + msm_camera_io_w_mb( + ispif->applied_intf_cmd[vfe_intf].intf_cmd, + ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe_intf)); + + /* cmd for RDI2 */ + if (ispif->applied_intf_cmd[vfe_intf].intf_cmd1 != 0xFFFFFFFF) + msm_camera_io_w_mb( + ispif->applied_intf_cmd[vfe_intf].intf_cmd1, + ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe_intf)); + } +} + +static int msm_ispif_stop_immediately(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int i, rc = 0; + uint16_t cid_mask = 0; + + BUG_ON(!ispif); + BUG_ON(!params); + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params); + + /* after stop the interface we need to unmask the CID enable bits */ + for (i = 0; i < params->num; i++) { + cid_mask = msm_ispif_get_cids_mask_from_cfg( + ¶ms->entries[i]); + msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, + cid_mask, params->entries[i].vfe_intf, 0); + } + + return rc; +} + +static int msm_ispif_start_frame_boundary(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int rc = 0; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params); + + return rc; +} + +static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif, + struct msm_ispif_param_data *params) +{ + int i, rc = 0; + uint16_t cid_mask = 0; + uint32_t intf_addr; + enum msm_ispif_vfe_intf vfe_intf; + uint32_t stop_flag = 0; + + BUG_ON(!ispif); + BUG_ON(!params); + + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + if (!msm_ispif_is_intf_valid(ispif->csid_version, + params->entries[i].vfe_intf)) { + pr_err("%s: invalid interface type\n", __func__); + rc = -EINVAL; + goto end; + } + } + + msm_ispif_intf_cmd(ispif, + ISPIF_INTF_CMD_DISABLE_FRAME_BOUNDARY, params); + + for (i = 0; i < params->num; i++) { + cid_mask = + msm_ispif_get_cids_mask_from_cfg(¶ms->entries[i]); + vfe_intf = params->entries[i].vfe_intf; + + switch (params->entries[i].intftype) { + case PIX0: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 0); + break; + case RDI0: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 0); + break; + case PIX1: + intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI1: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 1); + break; + case RDI2: + intf_addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe_intf, 2); + break; + default: + pr_err("%s: invalid intftype=%d\n", __func__, + params->entries[i].intftype); + rc = -EPERM; + goto end; + } + + rc = readl_poll_timeout(ispif->base + intf_addr, stop_flag, + (stop_flag & 0xF) == 0xF, + ISPIF_TIMEOUT_SLEEP_US, + ISPIF_TIMEOUT_ALL_US); + if (rc < 0) + goto end; + + /* disable CIDs in CID_MASK register */ + msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype, + cid_mask, vfe_intf, 0); + } + +end: + return rc; +} + +static void ispif_process_irq(struct ispif_device *ispif, + struct ispif_irq_status *out, enum msm_ispif_vfe_intf vfe_id) +{ + BUG_ON(!ispif); + BUG_ON(!out); + + if (out[vfe_id].ispifIrqStatus0 & + ISPIF_IRQ_STATUS_PIX_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[PIX0]++; + } + if (out[vfe_id].ispifIrqStatus0 & + ISPIF_IRQ_STATUS_RDI0_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI0]++; + } + if (out[vfe_id].ispifIrqStatus1 & + ISPIF_IRQ_STATUS_RDI1_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI1]++; + } + if (out[vfe_id].ispifIrqStatus2 & + ISPIF_IRQ_STATUS_RDI2_SOF_MASK) { + ispif->sof_count[vfe_id].sof_cnt[RDI2]++; + } +} + +static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out, + void *data) +{ + struct ispif_device *ispif = (struct ispif_device *)data; + + BUG_ON(!ispif); + BUG_ON(!out); + + out[VFE0].ispifIrqStatus0 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_0(VFE0)); + msm_camera_io_w(out[VFE0].ispifIrqStatus0, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE0)); + + out[VFE0].ispifIrqStatus1 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_1(VFE0)); + msm_camera_io_w(out[VFE0].ispifIrqStatus1, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE0)); + + out[VFE0].ispifIrqStatus2 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_2(VFE0)); + msm_camera_io_w_mb(out[VFE0].ispifIrqStatus2, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE0)); + + if (ispif->vfe_info.num_vfe > 1) { + out[VFE1].ispifIrqStatus0 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_0(VFE1)); + msm_camera_io_w(out[VFE1].ispifIrqStatus0, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(VFE1)); + + out[VFE1].ispifIrqStatus1 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_1(VFE1)); + msm_camera_io_w(out[VFE1].ispifIrqStatus1, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(VFE1)); + + out[VFE1].ispifIrqStatus2 = msm_camera_io_r(ispif->base + + ISPIF_VFE_m_IRQ_STATUS_2(VFE1)); + msm_camera_io_w_mb(out[VFE1].ispifIrqStatus2, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(VFE1)); + } + msm_camera_io_w_mb(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base + + ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) { + if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) + complete(&ispif->reset_complete[VFE0]); + + if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE0 pix0 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi0 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi1 overflow.\n", __func__); + + if (out[VFE0].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) + pr_err("%s: VFE0 rdi2 overflow.\n", __func__); + + ispif_process_irq(ispif, out, VFE0); + } + if (ispif->hw_num_isps > 1) { + if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ) + complete(&ispif->reset_complete[VFE1]); + + if (out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE1 pix0 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi0 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus1 & RAW_INTF_1_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi1 overflow.\n", __func__); + + if (out[VFE1].ispifIrqStatus2 & RAW_INTF_2_OVERFLOW_IRQ) + pr_err("%s: VFE1 rdi2 overflow.\n", __func__); + + ispif_process_irq(ispif, out, VFE1); + } +} + +static irqreturn_t msm_io_ispif_irq(int irq_num, void *data) +{ + struct ispif_irq_status irq[VFE_MAX]; + + msm_ispif_read_irq_status(irq, data); + return IRQ_HANDLED; +} + +static int msm_ispif_set_vfe_info(struct ispif_device *ispif, + struct msm_ispif_vfe_info *vfe_info) +{ + memcpy(&ispif->vfe_info, vfe_info, sizeof(struct msm_ispif_vfe_info)); + + return 0; +} + +static int msm_ispif_init(struct ispif_device *ispif, + uint32_t csid_version) +{ + int rc = 0; + + BUG_ON(!ispif); + + if (ispif->ispif_state == ISPIF_POWER_UP) { + pr_err("%s: ispif already initted state = %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + + /* can we set to zero? */ + ispif->applied_intf_cmd[VFE0].intf_cmd = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE0].intf_cmd1 = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE1].intf_cmd = 0xFFFFFFFF; + ispif->applied_intf_cmd[VFE1].intf_cmd1 = 0xFFFFFFFF; + memset(ispif->sof_count, 0, sizeof(ispif->sof_count)); + + ispif->csid_version = csid_version; + + if (ispif->csid_version >= CSID_VERSION_V30) { + if (!ispif->clk_mux_mem || !ispif->clk_mux_io) { + pr_err("%s csi clk mux mem %p io %p\n", __func__, + ispif->clk_mux_mem, ispif->clk_mux_io); + rc = -ENOMEM; + return rc; + } + ispif->clk_mux_base = ioremap(ispif->clk_mux_mem->start, + resource_size(ispif->clk_mux_mem)); + if (!ispif->clk_mux_base) { + pr_err("%s: clk_mux_mem ioremap failed\n", __func__); + rc = -ENOMEM; + return rc; + } + } + + ispif->base = ioremap(ispif->mem->start, + resource_size(ispif->mem)); + if (!ispif->base) { + rc = -ENOMEM; + pr_err("%s: nomem\n", __func__); + goto end; + } + rc = request_irq(ispif->irq->start, msm_io_ispif_irq, + IRQF_TRIGGER_RISING, "ispif", ispif); + if (rc) { + pr_err("%s: request_irq error = %d\n", __func__, rc); + goto error_irq; + } + + rc = msm_ispif_clk_ahb_enable(ispif, 1); + if (rc) { + pr_err("%s: ahb_clk enable failed", __func__); + goto error_ahb; + } + + msm_ispif_reset_hw(ispif); + + rc = msm_ispif_reset(ispif); + if (rc == 0) { + ispif->ispif_state = ISPIF_POWER_UP; + CDBG("%s: power up done\n", __func__); + goto end; + } + +error_ahb: + free_irq(ispif->irq->start, ispif); +error_irq: + iounmap(ispif->base); + +end: + return rc; +} + +static void msm_ispif_release(struct ispif_device *ispif) +{ + BUG_ON(!ispif); + + if (!ispif->base) { + pr_err("%s: ispif base is NULL\n", __func__); + return; + } + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + return; + } + + /* make sure no streaming going on */ + msm_ispif_reset(ispif); + + msm_ispif_clk_ahb_enable(ispif, 0); + + free_irq(ispif->irq->start, ispif); + + iounmap(ispif->base); + + iounmap(ispif->clk_mux_base); + + ispif->ispif_state = ISPIF_POWER_DOWN; +} + +static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) +{ + long rc = 0; + struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg; + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + + BUG_ON(!sd); + BUG_ON(!pcdata); + + mutex_lock(&ispif->mutex); + switch (pcdata->cfg_type) { + case ISPIF_ENABLE_REG_DUMP: + ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */ + break; + case ISPIF_INIT: + rc = msm_ispif_init(ispif, pcdata->csid_version); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_CFG: + rc = msm_ispif_config(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_START_FRAME_BOUNDARY: + rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_STOP_FRAME_BOUNDARY: + rc = msm_ispif_stop_frame_boundary(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_STOP_IMMEDIATELY: + rc = msm_ispif_stop_immediately(ispif, &pcdata->params); + msm_ispif_io_dump_reg(ispif); + break; + case ISPIF_RELEASE: + msm_ispif_release(ispif); + break; + case ISPIF_SET_VFE_INFO: + rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info); + break; + default: + pr_err("%s: invalid cfg_type\n", __func__); + rc = -EINVAL; + break; + } + mutex_unlock(&ispif->mutex); + return rc; +} +static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops; + +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ +#ifdef CONFIG_COMPAT + void __user *up; + if (is_compat_task()) { + up = (void __user *)compat_ptr((unsigned long)arg); + arg = up; + } +#endif + + switch (cmd) { + case VIDIOC_MSM_ISPIF_CFG: + return msm_ispif_cmd(sd, arg); + case MSM_SD_SHUTDOWN: { + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + if (ispif && ispif->base) + msm_ispif_release(ispif); + return 0; + } + default: + pr_err_ratelimited("%s: invalid cmd 0x%x received\n", + __func__, cmd); + return -ENOIOCTLCMD; + } +} + +static long msm_ispif_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + return msm_ispif_subdev_ioctl(sd, cmd, arg); +} + +static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_ispif_subdev_do_ioctl); +} + +static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ispif_device *ispif = v4l2_get_subdevdata(sd); + + mutex_lock(&ispif->mutex); + /* mem remap is done in init when the clock is on */ + ispif->open_cnt++; + mutex_unlock(&ispif->mutex); + return 0; +} + +static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct ispif_device *ispif = v4l2_get_subdevdata(sd); + + if (!ispif) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + mutex_lock(&ispif->mutex); + if (ispif->open_cnt == 0) { + pr_err("%s: Invalid close\n", __func__); + rc = -ENODEV; + goto end; + } + ispif->open_cnt--; + if (ispif->open_cnt == 0) + msm_ispif_release(ispif); +end: + mutex_unlock(&ispif->mutex); + return rc; +} + +static struct v4l2_subdev_core_ops msm_ispif_subdev_core_ops = { + .g_chip_ident = &msm_ispif_subdev_g_chip_ident, + .ioctl = &msm_ispif_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_ispif_subdev_ops = { + .core = &msm_ispif_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops = { + .open = ispif_open_node, + .close = ispif_close_node, +}; + +static int ispif_probe(struct platform_device *pdev) +{ + int rc; + struct ispif_device *ispif; + + ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL); + if (!ispif) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + rc = of_property_read_u32((&pdev->dev)->of_node, + "qcom,num-isps", &ispif->hw_num_isps); + if (rc) + /* backward compatibility */ + ispif->hw_num_isps = 1; + /* not an error condition */ + rc = 0; + } + + mutex_init(&ispif->mutex); + ispif->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ispif"); + if (!ispif->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto error; + } + ispif->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "ispif"); + if (!ispif->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto error; + } + ispif->io = request_mem_region(ispif->mem->start, + resource_size(ispif->mem), pdev->name); + if (!ispif->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto error; + } + ispif->clk_mux_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csi_clk_mux"); + if (ispif->clk_mux_mem) { + ispif->clk_mux_io = request_mem_region( + ispif->clk_mux_mem->start, + resource_size(ispif->clk_mux_mem), + ispif->clk_mux_mem->name); + if (!ispif->clk_mux_io) + pr_err("%s: no valid csi_mux region\n", __func__); + } + + v4l2_subdev_init(&ispif->msm_sd.sd, &msm_ispif_subdev_ops); + ispif->msm_sd.sd.internal_ops = &msm_ispif_internal_ops; + ispif->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + snprintf(ispif->msm_sd.sd.name, + ARRAY_SIZE(ispif->msm_sd.sd.name), MSM_ISPIF_DRV_NAME); + v4l2_set_subdevdata(&ispif->msm_sd.sd, ispif); + + platform_set_drvdata(pdev, &ispif->msm_sd.sd); + + media_entity_init(&ispif->msm_sd.sd.entity, 0, NULL, 0); + ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF; + ispif->msm_sd.sd.entity.name = pdev->name; + ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1; + rc = msm_sd_register(&ispif->msm_sd); + if (rc) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + goto error; + } + msm_ispif_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_ispif_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_ispif_v4l2_subdev_fops.unlocked_ioctl = msm_ispif_subdev_fops_ioctl; + msm_ispif_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_ispif_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; +#ifdef CONFIG_COMPAT + msm_ispif_v4l2_subdev_fops.compat_ioctl32 = msm_ispif_subdev_fops_ioctl; +#endif + + ispif->pdev = pdev; + ispif->ispif_state = ISPIF_POWER_DOWN; + ispif->open_cnt = 0; + return 0; + +error: + mutex_destroy(&ispif->mutex); + kfree(ispif); + return rc; +} + +static const struct of_device_id msm_ispif_dt_match[] = { + {.compatible = "qcom,ispif"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_ispif_dt_match); + +static struct platform_driver ispif_driver = { + .probe = ispif_probe, + .driver = { + .name = MSM_ISPIF_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_ispif_dt_match, + }, +}; + +static int __init msm_ispif_init_module(void) +{ + return platform_driver_register(&ispif_driver); +} + +static void __exit msm_ispif_exit_module(void) +{ + platform_driver_unregister(&ispif_driver); +} + +module_init(msm_ispif_init_module); +module_exit(msm_ispif_exit_module); +MODULE_DESCRIPTION("MSM ISP Interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif.h new file mode 100755 index 0000000000000000000000000000000000000000..180b0ce5a445752c9765a3f04360c9700c437139 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_ISPIF_H +#define MSM_ISPIF_H + +#include +#include +#include +#include "../include/media/msmb_ispif.h" +#include "msm_sd.h" + +#define ISPIF_CLK_INFO_MAX 16 +#define ISPIF_AHB_CLK_INFO 2 + +struct ispif_irq_status { + uint32_t ispifIrqStatus0; + uint32_t ispifIrqStatus1; + uint32_t ispifIrqStatus2; +}; + +enum msm_ispif_state_t { + ISPIF_POWER_UP, + ISPIF_POWER_DOWN, +}; +struct ispif_sof_count { + uint32_t sof_cnt[INTF_MAX]; +}; + +struct ispif_intf_cmd { + uint32_t intf_cmd; + uint32_t intf_cmd1; +}; + +struct ispif_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct resource *mem; + struct resource *clk_mux_mem; + struct resource *irq; + struct resource *io; + struct resource *clk_mux_io; + void __iomem *base; + void __iomem *clk_mux_base; + struct mutex mutex; + uint8_t start_ack_pending; + uint32_t csid_version; + int enb_dump_reg; + uint32_t open_cnt; + struct ispif_sof_count sof_count[VFE_MAX]; + struct ispif_intf_cmd applied_intf_cmd[VFE_MAX]; + enum msm_ispif_state_t ispif_state; + struct msm_ispif_vfe_info vfe_info; + struct clk *ahb_clk[ISPIF_CLK_INFO_MAX]; + struct completion reset_complete[VFE_MAX]; + uint32_t hw_num_isps; + uint32_t num_clk; + uint32_t clk_idx; +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif_hwreg_v1.h new file mode 100644 index 0000000000000000000000000000000000000000..91af7cb2c4fb4c7d82bae2058125592abbc80253 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif_hwreg_v1.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_ISPIF_HWREG_V1_H__ +#define __MSM_ISPIF_HWREG_V1_H__ + +/* common registers */ +#define ISPIF_RST_CMD_ADDR 0x0000 +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x0124 +#define PIX0_LINE_BUF_EN_BIT 0 + +#define ISPIF_VFE(m) (0x0) + +#define ISPIF_VFE_m_CTRL_0(m) (0x0008 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x0100 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x010C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x0118 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x0108 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x0114 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x0120 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x0104 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x0110 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x011C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INPUT_SEL(m) (0x000C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_0(m) (0x0004 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_1(m) (0x0030 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x0010 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + \ + ((n > 0) ? (0x20) : 0) \ + + 8*(n)) +#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x0290 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x001C + ISPIF_VFE(m) + \ + ((n > 0) ? (0x24) : 0) \ + + 0xc*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x0020 + ISPIF_VFE(m) + \ + ((n > 0) ? (0x24) : 0) \ + + 0xc*(n)) +#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x0024 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + \ + ((n > 0) ? (0x34) : 0) \ + + 8*(n)) + +/* Defines for compatibility with newer ISPIF versions */ +#define ISPIF_RST_CMD_1_ADDR (0x0000) +#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x0000 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x0000 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x0000 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x0000 + ISPIF_VFE(m)) + + + +/* CSID CLK MUX SEL REGISTERS */ +#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 + +/*ISPIF RESET BITS*/ +#define VFE_CLK_DOMAIN_RST BIT(31) +#define RDI_CLK_DOMAIN_RST BIT(30) +#define PIX_CLK_DOMAIN_RST BIT(29) +#define AHB_CLK_DOMAIN_RST BIT(28) +#define RDI_1_CLK_DOMAIN_RST BIT(27) +#define PIX_1_CLK_DOMAIN_RST BIT(26) +#define RDI_2_CLK_DOMAIN_RST BIT(25) +#define RDI_2_MISR_RST_STB BIT(20) +#define RDI_2_VFE_RST_STB BIT(19) +#define RDI_2_CSID_RST_STB BIT(18) +#define RDI_1_MISR_RST_STB BIT(14) +#define RDI_1_VFE_RST_STB BIT(13) +#define RDI_1_CSID_RST_STB BIT(12) +#define PIX_1_VFE_RST_STB BIT(10) +#define PIX_1_CSID_RST_STB BIT(9) +#define RDI_0_MISR_RST_STB BIT(8) +#define RDI_0_VFE_RST_STB BIT(7) +#define RDI_0_CSID_RST_STB BIT(6) +#define PIX_0_MISR_RST_STB BIT(5) +#define PIX_0_VFE_RST_STB BIT(4) +#define PIX_0_CSID_RST_STB BIT(3) +#define SW_REG_RST_STB BIT(2) +#define MISC_LOGIC_RST_STB BIT(1) +#define STROBED_RST_EN BIT(0) + +#define ISPIF_RST_CMD_MASK 0xFE1C77FF +#define ISPIF_RST_CMD_1_MASK 0xFFFFFFFF /* undefined */ + +/* irq_mask_0 */ +#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) +#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) +#define RESET_DONE_IRQ BIT(27) +/* irq_mask_1 */ +#define PIX_INTF_1_OVERFLOW_IRQ BIT(12) +#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) +/* irq_mask_2 */ +#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) + +#define ISPIF_IRQ_STATUS_MASK 0x0A493249 +#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 +#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 + +#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x000249 +#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x000249 + +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001 + +#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA +#endif /* __MSM_ISPIF_HWREG_V1_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif_hwreg_v2.h new file mode 100644 index 0000000000000000000000000000000000000000..3cc21a7dce6db7ef554835341d08223a579cb862 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/ispif/msm_ispif_hwreg_v2.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_ISPIF_HWREG_V2_H__ +#define __MSM_ISPIF_HWREG_V2_H__ + +/* common registers */ +#define ISPIF_RST_CMD_ADDR 0x008 +#define ISPIF_RST_CMD_1_ADDR 0x00C +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x01C +#define PIX0_LINE_BUF_EN_BIT 6 + +#define ISPIF_VFE(m) ((m) * 0x200) + +#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INPUT_SEL(m) (0x244 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x254 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x264 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_PIX_INTF_n_CROP(m, n) (0x278 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_3D_THRESHOLD(m) (0x288 + ISPIF_VFE(m)) +#define ISPIF_VFE_m_OUTPUT_SEL(m) (0x28C + ISPIF_VFE(m)) +#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x290 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x298 + ISPIF_VFE(m) + 8*(n)) +#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x29C + ISPIF_VFE(m) + 8*(n)) +#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x2C0 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x2D0 + ISPIF_VFE(m) + 4*(n)) +#define ISPIF_VFE_m_3D_DESKEW_SIZE(m) (0x2E4 + ISPIF_VFE(m)) + +/* CSID CLK MUX SEL REGISTERS */ +#define ISPIF_RDI_CLK_MUX_SEL_ADDR 0x8 + +/*ISPIF RESET BITS*/ +#define VFE_CLK_DOMAIN_RST BIT(31) +#define PIX_1_CLK_DOMAIN_RST BIT(30) +#define PIX_CLK_DOMAIN_RST BIT(29) +#define RDI_2_CLK_DOMAIN_RST BIT(28) +#define RDI_1_CLK_DOMAIN_RST BIT(27) +#define RDI_CLK_DOMAIN_RST BIT(26) +#define AHB_CLK_DOMAIN_RST BIT(25) +#define RDI_2_VFE_RST_STB BIT(12) +#define RDI_2_CSID_RST_STB BIT(11) +#define RDI_1_VFE_RST_STB BIT(10) +#define RDI_1_CSID_RST_STB BIT(9) +#define RDI_0_VFE_RST_STB BIT(8) +#define RDI_0_CSID_RST_STB BIT(7) +#define PIX_1_VFE_RST_STB BIT(6) +#define PIX_1_CSID_RST_STB BIT(5) +#define PIX_0_VFE_RST_STB BIT(4) +#define PIX_0_CSID_RST_STB BIT(3) +#define SW_REG_RST_STB BIT(2) +#define MISC_LOGIC_RST_STB BIT(1) +#define STROBED_RST_EN BIT(0) + +#define ISPIF_RST_CMD_MASK 0xFE0F1FFF +#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9 + +#define PIX_INTF_0_OVERFLOW_IRQ BIT(12) +#define RAW_INTF_0_OVERFLOW_IRQ BIT(25) +#define RAW_INTF_1_OVERFLOW_IRQ BIT(25) +#define RAW_INTF_2_OVERFLOW_IRQ BIT(12) +#define RESET_DONE_IRQ BIT(27) + +#define ISPIF_IRQ_STATUS_MASK 0x0A493249 +#define ISPIF_IRQ_STATUS_1_MASK 0x02493249 +#define ISPIF_IRQ_STATUS_2_MASK 0x00001249 + +#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249 +#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000 +#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249 + +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1 + +#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA + +#endif /* __MSM_ISPIF_HWREG_V2_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/Makefile b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d5902d87a6a73e2e1182b7d997151af67ca82887 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/Makefile @@ -0,0 +1,6 @@ +GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) + +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/jpeg_10 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io + +obj-$(CONFIG_MSMB_JPEG) += msm_jpeg_dev.o msm_jpeg_sync.o msm_jpeg_core.o msm_jpeg_hw.o msm_jpeg_platform.o diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_common.h b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_common.h new file mode 100644 index 0000000000000000000000000000000000000000..634becafc5756796352269b82fe74d97cc3d8e4e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_common.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_JPEG_COMMON_H +#define MSM_JPEG_COMMON_H + +#ifdef MSM_JPEG_DEBUG +#define JPEG_DBG(fmt, args...) pr_info(fmt, ##args) +#else +#define JPEG_DBG(fmt, args...) do { } while (0) +#endif + +#define JPEG_PR_ERR pr_err +#define JPEG_DBG_HIGH pr_debug + +enum JPEG_MODE { + JPEG_MODE_DISABLE, + JPEG_MODE_OFFLINE, + JPEG_MODE_REALTIME, + JPEG_MODE_REALTIME_ROTATION +}; + +enum JPEG_ROTATION { + JPEG_ROTATION_0, + JPEG_ROTATION_90, + JPEG_ROTATION_180, + JPEG_ROTATION_270 +}; + +#endif /* MSM_JPEG_COMMON_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_core.c b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_core.c new file mode 100644 index 0000000000000000000000000000000000000000..52011346fb80c656f0749b1226fc89638326c28e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_core.c @@ -0,0 +1,284 @@ +/* Copyright (c) 2012-2013,The Linux Foundation. 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 and + * only 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 +#include +#include "msm_jpeg_hw.h" +#include "msm_jpeg_core.h" +#include "msm_jpeg_platform.h" +#include "msm_jpeg_common.h" + +int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, + void *base, int size) { + unsigned long flags; + int rc = 0; + int tm = 500; /*500ms*/ + JPEG_DBG("%s:%d] reset", __func__, __LINE__); + memset(&pgmn_dev->fe_pingpong_buf, 0, + sizeof(pgmn_dev->fe_pingpong_buf)); + pgmn_dev->fe_pingpong_buf.is_fe = 1; + memset(&pgmn_dev->we_pingpong_buf, 0, + sizeof(pgmn_dev->we_pingpong_buf)); + spin_lock_irqsave(&pgmn_dev->reset_lock, flags); + pgmn_dev->reset_done_ack = 0; + msm_jpeg_hw_reset(base, size); + spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); + rc = wait_event_interruptible_timeout( + pgmn_dev->reset_wait, + pgmn_dev->reset_done_ack, + msecs_to_jiffies(tm)); + + if (!pgmn_dev->reset_done_ack) { + JPEG_DBG("%s: reset ACK failed %d", __func__, rc); + return -EBUSY; + } + + JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc); + spin_lock_irqsave(&pgmn_dev->reset_lock, flags); + pgmn_dev->reset_done_ack = 0; + pgmn_dev->state = MSM_JPEG_RESET; + spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); + + return 0; +} + +void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev, + int domain_num) { + int i = 0; + for (i = 0; i < 2; i++) { + if (pgmn_dev->we_pingpong_buf.buf_status[i] && + pgmn_dev->release_buf) + msm_jpeg_platform_p2v(pgmn_dev, + pgmn_dev->we_pingpong_buf.buf[i].file, + &pgmn_dev->we_pingpong_buf.buf[i].handle, + domain_num); + pgmn_dev->we_pingpong_buf.buf_status[i] = 0; + } +} + +void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev) +{ + init_waitqueue_head(&pgmn_dev->reset_wait); + spin_lock_init(&pgmn_dev->reset_lock); +} + +int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev) +{ + msm_jpeg_hw_fe_start(pgmn_dev->base); + return 0; +} + +/* fetch engine */ +int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf) +{ + if (0 == buf->cbcr_len) + buf->cbcr_buffer_addr = 0x0; + JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__, + (int) buf->y_buffer_addr, buf->y_len, + (int) buf->cbcr_buffer_addr, buf->cbcr_len); + return msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf, buf, + pgmn_dev->base); +} + +void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf); +} + +/* write engine */ +int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf) { + JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__, + (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr, + buf->y_len); + pgmn_dev->we_pingpong_buf.buf[0] = *buf; + pgmn_dev->we_pingpong_buf.buf_status[0] = 1; + msm_jpeg_hw_we_buffer_update( + &pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base); + + return 0; +} + +int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_hw_buf *buf) +{ + int i = 0; + for (i = 0; i < 2; i++) { + if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr + == buf->y_buffer_addr) + pgmn_dev->we_pingpong_buf.buf_status[i] = 0; + } + return 0; +} + +void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + + return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf); +} + +void *msm_jpeg_core_framedone_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + struct msm_jpeg_hw_buf *buf_p; + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + + buf_p = msm_jpeg_hw_pingpong_active_buffer( + &pgmn_dev->we_pingpong_buf); + if (buf_p && !pgmn_dev->decode_flag) { + buf_p->framedone_len = + msm_jpeg_hw_encode_output_size(pgmn_dev->base); + JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__, + buf_p->framedone_len); + } + + return buf_p; +} + +void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + /* @todo return the status back to msm_jpeg_core_reset */ + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return NULL; +} + +void *msm_jpeg_core_err_irq(int jpeg_irq_status, + struct msm_jpeg_device *pgmn_dev) +{ + JPEG_PR_ERR("%s: Error %x\n", __func__, jpeg_irq_status); + return NULL; +} + +static int (*msm_jpeg_irq_handler) (int, void *, void *); + +void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev, + int jpeg_irq_status) +{ + void *data = NULL; + data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, + pgmn_dev, data); + data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE, + pgmn_dev, data); +} + +irqreturn_t msm_jpeg_core_irq(int irq_num, void *context) +{ + void *data = NULL; + unsigned long flags; + int jpeg_irq_status; + struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context; + + JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num); + + jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base); + + JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__, + jpeg_irq_status); + + /*For reset and framedone IRQs, clear all bits*/ + if (pgmn_dev->state == MSM_JPEG_IDLE) { + JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", + __func__, __LINE__, pgmn_dev->state); + JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, + __LINE__); + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + return IRQ_HANDLED; + } else if (jpeg_irq_status & 0x10000000) { + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + } else if (jpeg_irq_status & 0x1) { + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + if (pgmn_dev->decode_flag) + msm_jpeg_decode_status(pgmn_dev->base); + } else { + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + jpeg_irq_status, pgmn_dev->base); + } + + if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) { + /* send fe ping pong irq */ + JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__); + data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE, + context, data); + data = msm_jpeg_core_framedone_irq(jpeg_irq_status, + pgmn_dev); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler( + MSM_JPEG_HW_MASK_COMP_FRAMEDONE, + context, data); + pgmn_dev->state = MSM_JPEG_INIT; + } + if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) { + data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status, + pgmn_dev); + spin_lock_irqsave(&pgmn_dev->reset_lock, flags); + pgmn_dev->reset_done_ack = 1; + spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags); + wake_up(&pgmn_dev->reset_wait); + if (msm_jpeg_irq_handler) + msm_jpeg_irq_handler( + MSM_JPEG_HW_MASK_COMP_RESET_ACK, + context, data); + } + + /* Unexpected/unintended HW interrupt */ + if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) { + if (pgmn_dev->state != MSM_JPEG_EXECUTING) { + /*Clear all the bits and ignore the IRQ*/ + JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d", + __func__, __LINE__, pgmn_dev->state); + JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__, + __LINE__); + msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK, + JPEG_IRQ_CLEAR_ALL, pgmn_dev->base); + return IRQ_HANDLED; + } else { + if (pgmn_dev->decode_flag) + msm_jpeg_decode_status(pgmn_dev->base); + msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status); + data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev); + if (msm_jpeg_irq_handler) { + msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR, + context, data); + } + } + } + + return IRQ_HANDLED; +} + +void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)) +{ + msm_jpeg_irq_handler = irq_handler; +} + +void msm_jpeg_core_irq_remove(void) +{ + msm_jpeg_irq_handler = NULL; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_core.h b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_core.h new file mode 100644 index 0000000000000000000000000000000000000000..212eaff91d884236373a132315dab5d8611333d2 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_core.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2012, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_JPEG_CORE_H +#define MSM_JPEG_CORE_H + +#include +#include "msm_jpeg_hw.h" +#include "msm_jpeg_sync.h" + +#define msm_jpeg_core_buf msm_jpeg_hw_buf + +irqreturn_t msm_jpeg_core_irq(int irq_num, void *context); + +void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *)); +void msm_jpeg_core_irq_remove(void); + +int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf); +int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf); +int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_hw_buf *buf); + +int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode, + void *base, int size); +int msm_jpeg_core_fe_start(struct msm_jpeg_device *); + +void msm_jpeg_core_release(struct msm_jpeg_device *, int); +void msm_jpeg_core_init(struct msm_jpeg_device *); +#endif /* MSM_JPEG_CORE_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..34273d90b8c42720e9a5c21013f4d63994439f94 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_dev.c @@ -0,0 +1,315 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_jpeg_sync.h" +#include "msm_jpeg_common.h" + +#define MSM_JPEG_NAME "jpeg" +#define DEV_NAME_LEN 10 + +static int msm_jpeg_open(struct inode *inode, struct file *filp) +{ + int rc = 0; + + struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev, + struct msm_jpeg_device, cdev); + filp->private_data = pgmn_dev; + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + + rc = __msm_jpeg_open(pgmn_dev); + + JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, + filp->f_path.dentry->d_name.name, pgmn_dev->open_count); + + return rc; +} + +static int msm_jpeg_release(struct inode *inode, struct file *filp) +{ + int rc; + + struct msm_jpeg_device *pgmn_dev = filp->private_data; + + JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__); + + rc = __msm_jpeg_release(pgmn_dev); + + JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__, + filp->f_path.dentry->d_name.name, pgmn_dev->open_count); + return rc; +} +#ifdef CONFIG_COMPAT +static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = filp->private_data; + + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__, + __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg); + + rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return rc; +} +#endif +static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = filp->private_data; + + JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__, + __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg); + + rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return rc; +} + +static const struct file_operations msm_jpeg_fops = { + .owner = THIS_MODULE, + .open = msm_jpeg_open, + .release = msm_jpeg_release, + .unlocked_ioctl = msm_jpeg_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = msm_jpeg_compat_ioctl, +#endif +}; + + +int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *)jpeg_sd->host_priv; + + JPEG_DBG("%s:%d: jpeg_sd=0x%x pgmn_dev=0x%x\n", + __func__, __LINE__, (uint32_t)jpeg_sd, (uint32_t)pgmn_dev); + rc = __msm_jpeg_open(pgmn_dev); + JPEG_DBG("%s:%d: rc=%d\n", + __func__, __LINE__, rc); + return rc; +} + +static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + long rc; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *)sd->host_priv; + + JPEG_DBG("%s: cmd=%d\n", __func__, cmd); + + JPEG_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev); + + JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__); + + rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg); + pr_debug("%s: X\n", __func__); + return rc; +} + +void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd) +{ + int rc; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *)jpeg_sd->host_priv; + JPEG_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev); + rc = __msm_jpeg_release(pgmn_dev); + JPEG_DBG("%s:rc=%d", __func__, rc); +} + +static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = { + .ioctl = msm_jpeg_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = { + .core = &msm_jpeg_subdev_core_ops, +}; + +static int msm_jpeg_init_dev(struct platform_device *pdev) +{ + int rc = -1; + struct device *dev; + struct msm_jpeg_device *msm_jpeg_device_p; + char devname[DEV_NAME_LEN]; + + msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); + if (!msm_jpeg_device_p) { + JPEG_PR_ERR("%s: no mem\n", __func__); + return -EFAULT; + } + + msm_jpeg_device_p->pdev = pdev; + + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, "cell-index", + &pdev->id); + + snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id); + + rc = __msm_jpeg_init(msm_jpeg_device_p); + if (rc < -1) { + JPEG_PR_ERR("%s: initialization failed\n", __func__); + goto fail; + } + + v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops); + v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p); + JPEG_DBG("%s: msm_jpeg_device_p 0x%x", __func__, + (uint32_t)msm_jpeg_device_p); + + rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1, + devname); + if (rc < 0) { + JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__); + goto fail_1; + } + + if (!msm_jpeg_device_p->msm_jpeg_class) { + msm_jpeg_device_p->msm_jpeg_class = + class_create(THIS_MODULE, devname); + if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) { + rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class); + JPEG_PR_ERR("%s: create device class failed\n", + __func__); + goto fail_2; + } + } + + dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL, + MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno), + MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL, + "%s%d", MSM_JPEG_NAME, pdev->id); + if (IS_ERR(dev)) { + JPEG_PR_ERR("%s: error creating device\n", __func__); + rc = -ENODEV; + goto fail_3; + } + + cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops); + msm_jpeg_device_p->cdev.owner = THIS_MODULE; + msm_jpeg_device_p->cdev.ops = + (const struct file_operations *) &msm_jpeg_fops; + rc = cdev_add(&msm_jpeg_device_p->cdev, + msm_jpeg_device_p->msm_jpeg_devno, 1); + if (rc < 0) { + JPEG_PR_ERR("%s: error adding cdev\n", __func__); + rc = -ENODEV; + goto fail_4; + } + + platform_set_drvdata(pdev, &msm_jpeg_device_p); + + JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id); + + return rc; + +fail_4: + device_destroy(msm_jpeg_device_p->msm_jpeg_class, + msm_jpeg_device_p->msm_jpeg_devno); + +fail_3: + class_destroy(msm_jpeg_device_p->msm_jpeg_class); + +fail_2: + unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); + +fail_1: + __msm_jpeg_exit(msm_jpeg_device_p); + return rc; + +fail: + kfree(msm_jpeg_device_p); + return rc; + +} + +static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p) +{ + cdev_del(&msm_jpeg_device_p->cdev); + device_destroy(msm_jpeg_device_p->msm_jpeg_class, + msm_jpeg_device_p->msm_jpeg_devno); + class_destroy(msm_jpeg_device_p->msm_jpeg_class); + unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1); + + __msm_jpeg_exit(msm_jpeg_device_p); +} + +static int __msm_jpeg_probe(struct platform_device *pdev) +{ + return msm_jpeg_init_dev(pdev); +} + +static int __msm_jpeg_remove(struct platform_device *pdev) +{ + struct msm_jpeg_device *msm_jpegd_device_p; + + msm_jpegd_device_p = platform_get_drvdata(pdev); + if (msm_jpegd_device_p) + msm_jpeg_exit(msm_jpegd_device_p); + + return 0; +} + +static const struct of_device_id msm_jpeg_dt_match[] = { + {.compatible = "qcom,jpeg"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match); + +static struct platform_driver msm_jpeg_driver = { + .probe = __msm_jpeg_probe, + .remove = __msm_jpeg_remove, + .driver = { + .name = "msm_jpeg", + .owner = THIS_MODULE, + .of_match_table = msm_jpeg_dt_match, + }, +}; + +static int __init msm_jpeg_driver_init(void) +{ + int rc; + rc = platform_driver_register(&msm_jpeg_driver); + return rc; +} + +static void __exit msm_jpeg_driver_exit(void) +{ + platform_driver_unregister(&msm_jpeg_driver); +} + +MODULE_DESCRIPTION("msm jpeg jpeg driver"); + +module_init(msm_jpeg_driver_init); +module_exit(msm_jpeg_driver_exit); diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw.c new file mode 100644 index 0000000000000000000000000000000000000000..19696953eb788f36d032e9c9f303d153bb7e33c0 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw.c @@ -0,0 +1,416 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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 +#include +#include "msm_jpeg_hw.h" +#include "msm_jpeg_common.h" + +#include + +int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, + struct msm_jpeg_hw_buf *buf, void *base) +{ + int buf_free_index = -1; + + if (!pingpong_hw->buf_status[0]) { + buf_free_index = 0; + } else if (!pingpong_hw->buf_status[1]) { + buf_free_index = 1; + } else { + JPEG_PR_ERR("%s:%d: pingpong buffer busy\n", + __func__, __LINE__); + return -EBUSY; + } + + pingpong_hw->buf[buf_free_index] = *buf; + pingpong_hw->buf_status[buf_free_index] = 1; + + if (pingpong_hw->is_fe) { + /* it is fe */ + msm_jpeg_hw_fe_buffer_update( + &pingpong_hw->buf[buf_free_index], buf_free_index, + base); + } else { + /* it is we */ + msm_jpeg_hw_we_buffer_update( + &pingpong_hw->buf[buf_free_index], buf_free_index, + base); + } + return 0; +} + +void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw) +{ + struct msm_jpeg_hw_buf *buf_p = NULL; + + if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) { + buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; + pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0; + } + + pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index; + + return (void *) buf_p; +} + +void *msm_jpeg_hw_pingpong_active_buffer( + struct msm_jpeg_hw_pingpong *pingpong_hw) +{ + struct msm_jpeg_hw_buf *buf_p = NULL; + + if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) + buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index]; + + return (void *) buf_p; +} + +struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR, + JPEG_IRQ_STATUS_BMSK, {0} }, +}; + +int msm_jpeg_hw_irq_get_status(void *base) +{ + uint32_t n_irq_status = 0; + n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base); + return n_irq_status; +} + +struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_READ, 1, + JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR, + JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } , +}; + +long msm_jpeg_hw_encode_output_size(void *base) +{ + uint32_t encode_output_size = 0; + + encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0], + base); + + return encode_output_size; +} + +struct msm_jpeg_hw_cmd hw_cmd_irq_clear[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR, + JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} }, +}; + +void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base) +{ + JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data); + hw_cmd_irq_clear[0].mask = mask; + hw_cmd_irq_clear[0].data = data; + msm_jpeg_hw_write(&hw_cmd_irq_clear[0], base); +} + +struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, + JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR, + JPEG_PLN0_RD_OFFSET_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR, + JPEG_PLN0_RD_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR, + JPEG_PLN1_RD_OFFSET_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR, + JPEG_PLN1_RD_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_OFFSET_ADDR, + JPEG_PLN1_RD_OFFSET_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_PNTR_ADDR, + JPEG_PLN2_RD_PNTR_BMSK, {0} }, +}; + +void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *base) +{ + struct msm_jpeg_hw_cmd *hw_cmd_p; + + if (pingpong_index == 0) { + hw_cmd_p = &hw_cmd_fe_ping_update[0]; + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + hw_cmd_p->data = p_input->y_buffer_addr; + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + hw_cmd_p->data = p_input->cbcr_buffer_addr; + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + hw_cmd_p->data = p_input->pln2_addr; + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + } + return; +} + +struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR, + JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} }, +}; + +void msm_jpeg_hw_fe_start(void *base) +{ + msm_jpeg_hw_write(&hw_cmd_fe_start[0], base); + + return; +} + +struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR, + JPEG_PLN0_WR_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR, + JPEG_PLN0_WR_PNTR_BMSK, {0} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR, + JPEG_PLN0_WR_PNTR_BMSK, {0} }, +}; + +void msm_jpeg_decode_status(void *base) +{ + uint32_t data; + data = readl_relaxed(base + JPEG_DECODE_MCUS_DECODED_STATUS); + JPEG_DBG_HIGH("Decode MCUs decode status %u", data); + data = readl_relaxed(base + JPEG_DECODE_BITS_CONSUMED_STATUS); + JPEG_DBG_HIGH("Decode bits consumed status %u", data); + data = readl_relaxed(base + JPEG_DECODE_PRED_Y_STATE); + JPEG_DBG_HIGH("Decode prediction Y state %u", data); + data = readl_relaxed(base + JPEG_DECODE_PRED_C_STATE); + JPEG_DBG_HIGH("Decode prediction C state %u", data); + data = readl_relaxed(base + JPEG_DECODE_RSM_STATE); + JPEG_DBG_HIGH("Decode prediction RSM state %u", data); +} + + +void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *base) +{ + struct msm_jpeg_hw_cmd *hw_cmd_p; + + if (pingpong_index == 0) { + hw_cmd_p = &hw_cmd_we_ping_update[0]; + hw_cmd_p->data = p_input->y_buffer_addr; + JPEG_DBG_HIGH("%s Output pln0 buffer address is %x\n", __func__, + p_input->y_buffer_addr); + msm_jpeg_hw_write(hw_cmd_p++, base); + hw_cmd_p->data = p_input->cbcr_buffer_addr; + JPEG_DBG_HIGH("%s Output pln1 buffer address is %x\n", __func__, + p_input->cbcr_buffer_addr); + msm_jpeg_hw_write(hw_cmd_p++, base); + hw_cmd_p->data = p_input->pln2_addr; + JPEG_DBG_HIGH("%s Output pln2 buffer address is %x\n", __func__, + p_input->pln2_addr); + msm_jpeg_hw_write(hw_cmd_p++, base); + } + return; +} + +struct msm_jpeg_hw_cmd hw_cmd_reset[] = { + /* type, repeat n times, offset, mask, data or pdata */ + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR, + JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} }, + {MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR, + JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} }, +}; + +void msm_jpeg_hw_reset(void *base, int size) +{ + struct msm_jpeg_hw_cmd *hw_cmd_p; + + hw_cmd_p = &hw_cmd_reset[0]; + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p++, base); + wmb(); + msm_jpeg_hw_write(hw_cmd_p, base); + wmb(); + + return; +} + +uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p, + void *jpeg_region_base) +{ + uint32_t *paddr; + uint32_t data; + + paddr = jpeg_region_base + hw_cmd_p->offset; + + data = readl_relaxed(paddr); + data &= hw_cmd_p->mask; + + return data; +} + +void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p, + void *jpeg_region_base) +{ + uint32_t *paddr; + uint32_t old_data, new_data; + + paddr = jpeg_region_base + hw_cmd_p->offset; + + if (hw_cmd_p->mask == 0xffffffff) { + old_data = 0; + } else { + old_data = readl_relaxed(paddr); + old_data &= ~hw_cmd_p->mask; + } + + new_data = hw_cmd_p->data & hw_cmd_p->mask; + new_data |= old_data; + writel_relaxed(new_data, paddr); +} + +int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us, + void *base) +{ + int tm = hw_cmd_p->n; + uint32_t data; + uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask; + + data = msm_jpeg_hw_read(hw_cmd_p, base); + if (data != wait_data) { + while (tm) { + udelay(m_us); + data = msm_jpeg_hw_read(hw_cmd_p, base); + if (data == wait_data) + break; + tm--; + } + } + hw_cmd_p->data = data; + return tm; +} + +void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us) +{ + int tm = hw_cmd_p->n; + while (tm) { + udelay(m_us); + tm--; + } +} + +int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds, + uint32_t max_size, void *base) +{ + int is_copy_to_user = 0; + uint32_t data; + + while (m_cmds--) { + if (hw_cmd_p->offset > max_size) { + JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__, + __LINE__, hw_cmd_p->offset, max_size); + return -EFAULT; + } + if (hw_cmd_p->offset & 0x3) { + JPEG_PR_ERR("%s:%d] %d Invalid alignment\n", __func__, + __LINE__, hw_cmd_p->offset); + return -EFAULT; + } + + switch (hw_cmd_p->type) { + case MSM_JPEG_HW_CMD_TYPE_READ: + hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base); + is_copy_to_user = 1; + break; + + case MSM_JPEG_HW_CMD_TYPE_WRITE: + msm_jpeg_hw_write(hw_cmd_p, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_WRITE_OR: + data = msm_jpeg_hw_read(hw_cmd_p, base); + hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) | + data; + msm_jpeg_hw_write(hw_cmd_p, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_UWAIT: + msm_jpeg_hw_wait(hw_cmd_p, 1, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_MWAIT: + msm_jpeg_hw_wait(hw_cmd_p, 1000, base); + break; + + case MSM_JPEG_HW_CMD_TYPE_UDELAY: + msm_jpeg_hw_delay(hw_cmd_p, 1); + break; + + case MSM_JPEG_HW_CMD_TYPE_MDELAY: + msm_jpeg_hw_delay(hw_cmd_p, 1000); + break; + + default: + JPEG_PR_ERR("wrong hw command type\n"); + break; + } + + hw_cmd_p++; + } + return is_copy_to_user; +} + +void msm_jpeg_io_dump(void *base, int size) +{ + char line_str[128], *p_str; + void __iomem *addr = (void __iomem *)base; + int i; + u32 *p = (u32 *) addr; + u32 data; + JPEG_DBG_HIGH("%s:%d] %p %d", __func__, __LINE__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08lx: ", (unsigned long)p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + JPEG_DBG_HIGH("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + JPEG_DBG_HIGH("%s\n", line_str); +} + diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..c3c5bd77231c75bcb8981b7113eea0137b185b7f --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_JPEG_HW_H +#define MSM_JPEG_HW_H + +#include +#include "msm_jpeg_hw_reg.h" +#include +#include + +struct msm_jpeg_hw_buf { + struct msm_jpeg_buf vbuf; + struct file *file; + uint32_t framedone_len; + uint32_t y_buffer_addr; + uint32_t y_len; + uint32_t cbcr_buffer_addr; + uint32_t cbcr_len; + uint32_t num_of_mcu_rows; + struct ion_handle *handle; + uint32_t pln2_addr; + uint32_t pln2_len; +}; + +struct msm_jpeg_hw_pingpong { + uint8_t is_fe; /* 1: fe; 0: we */ + struct msm_jpeg_hw_buf buf[2]; + int buf_status[2]; + int buf_active_index; +}; + +int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw, + struct msm_jpeg_hw_buf *buf, void *); +void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw); +void *msm_jpeg_hw_pingpong_active_buffer(struct msm_jpeg_hw_pingpong + *pingpong_hw); + +void msm_jpeg_hw_irq_clear(uint32_t, uint32_t, void *); +int msm_jpeg_hw_irq_get_status(void *); +long msm_jpeg_hw_encode_output_size(void *); +#define MSM_JPEG_HW_MASK_COMP_FRAMEDONE \ + MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK +#define MSM_JPEG_HW_MASK_COMP_FE \ + MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK +#define MSM_JPEG_HW_MASK_COMP_WE \ + (MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \ + MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK) +#define MSM_JPEG_HW_MASK_COMP_RESET_ACK \ + MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK +#define MSM_JPEG_HW_MASK_COMP_ERR \ + (MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \ + MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \ + MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK) + +#define msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FRAMEDONE) +#define msm_jpeg_hw_irq_is_fe_pingpong(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_FE) +#define msm_jpeg_hw_irq_is_we_pingpong(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_WE) +#define msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_RESET_ACK) +#define msm_jpeg_hw_irq_is_err(jpeg_irq_status) \ + (jpeg_irq_status & MSM_JPEG_HW_MASK_COMP_ERR) + +void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *); +void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input, + uint8_t pingpong_index, void *); + +void msm_jpeg_hw_we_buffer_cfg(uint8_t is_realtime); + +void msm_jpeg_hw_fe_start(void *); +void msm_jpeg_hw_clk_cfg(void); + +void msm_jpeg_hw_reset(void *base, int size); +void msm_jpeg_hw_irq_cfg(void); + +uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *, void *); +void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *); +int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *); +void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int); +int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t , + uint32_t , void *); +void msm_jpeg_hw_region_dump(int size); +void msm_jpeg_io_dump(void *base, int size); +void msm_jpeg_decode_status(void *base); + +#endif /* MSM_JPEG_HW_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..4fbab4b3ea71202bbeef07a1d47da4d2e4fface5 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_hw_reg.h @@ -0,0 +1,138 @@ +/* Copyright (c) 2012-2013 The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_JPEG_HW_REG_H +#define MSM_JPEG_HW_REG_H + +#define JPEG_REG_BASE 0 + +#define MSM_JPEG_HW_IRQ_MASK_ADDR 0x00000018 +#define MSM_JPEG_HW_IRQ_MASK_RMSK 0xFFFFFFFF +#define MSM_JPEG_HW_IRQ_ENABLE 0xFFFFFFFF + +#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 +#define MSM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 + +#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000010 +#define MSM_JPEG_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001 + +#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004 +#define MSM_JPEG_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002 + +#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008 +#define MSM_JPEG_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003 + +#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010 +#define MSM_JPEG_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004 + +#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020 +#define MSM_JPEG_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005 + +#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000 +#define MSM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a + +#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800 +#define MSM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b + +#define MSM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25) +#define MSM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26) +#define MSM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29) + +#define JPEG_OFFLINE_CMD_START 0x00000001 + +#define JPEG_RESET_DEFAULT 0x00032013 + +#define JPEG_IRQ_DISABLE_ALL 0x00000000 +#define JPEG_IRQ_CLEAR_ALL 0xFFFFFFFF + +#define JPEG_PLN0_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000038) +#define JPEG_PLN0_RD_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN0_RD_OFFSET_ADDR 0x0000003C +#define JPEG_PLN0_RD_OFFSET_BMSK 0x1FFFFFFF + +#define JPEG_PLN1_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000044) +#define JPEG_PLN1_RD_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN1_RD_OFFSET_ADDR 0x00000048 +#define JPEG_PLN1_RD_OFFSET_BMSK 0x1FFFFFFF + +#define JPEG_PLN2_RD_PNTR_ADDR (JPEG_REG_BASE + 0x00000050) +#define JPEG_PLN2_RD_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN2_RD_OFFSET_ADDR 0x00000054 +#define JPEG_PLN2_RD_OFFSET_BMSK 0x1FFFFFFF + +#define JPEG_CMD_ADDR (JPEG_REG_BASE + 0x00000010) +#define JPEG_CMD_BMSK 0x00000FFF +#define JPEG_CMD_CLEAR_WRITE_PLN_QUEUES 0x700 + +#define JPEG_PLN0_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000cc) +#define JPEG_PLN0_WR_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN1_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D0) +#define JPEG_PLN1_WR_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_PLN2_WR_PNTR_ADDR (JPEG_REG_BASE + 0x000000D4) +#define JPEG_PLN2_WR_PNTR_BMSK 0xFFFFFFFF + +#define JPEG_IRQ_MASK_ADDR (JPEG_REG_BASE + 0x00000018) +#define JPEG_IRQ_MASK_BMSK 0xFFFFFFFF +#define JPEG_IRQ_ALLSOURCES_ENABLE 0xFFFFFFFF + +#define JPEG_IRQ_CLEAR_ADDR (JPEG_REG_BASE + 0x0000001c) +#define JPEG_IRQ_CLEAR_BMSK 0xFFFFFFFF + +#define JPEG_RESET_CMD_ADDR (JPEG_REG_BASE + 0x00000008) +#define JPEG_RESET_CMD_RMSK 0xFFFFFFFF + +#define JPEG_IRQ_STATUS_ADDR (JPEG_REG_BASE + 0x00000020) +#define JPEG_IRQ_STATUS_BMSK 0xFFFFFFFF + +#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR (JPEG_REG_BASE + 0x00000180) +#define JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK 0x1FFFFFFF + +#define JPEG_DECODE_MCUS_DECODED_STATUS (JPEG_REG_BASE + 0x00000258) +#define JPEG_DECODE_BITS_CONSUMED_STATUS (JPEG_REG_BASE + 0x0000025C) +#define JPEG_DECODE_PRED_Y_STATE (JPEG_REG_BASE + 0x00000260) +#define JPEG_DECODE_PRED_C_STATE (JPEG_REG_BASE + 0x00000264) +#define JPEG_DECODE_RSM_STATE (JPEG_REG_BASE + 0x00000268) + +#define JPEG_HW_VERSION (JPEG_REG_BASE + 0x00000000) + +#define VBIF_BASE_ADDRESS 0xFDA60000 +#define VBIF_REGION_SIZE 0xC30 +#define JPEG_VBIF_CLKON 0x4 +#define JPEG_VBIF_IN_RD_LIM_CONF0 0xB0 +#define JPEG_VBIF_IN_RD_LIM_CONF1 0xB4 +#define JPEG_VBIF_IN_RD_LIM_CONF2 0xB8 +#define JPEG_VBIF_IN_WR_LIM_CONF0 0xC0 +#define JPEG_VBIF_IN_WR_LIM_CONF1 0xC4 +#define JPEG_VBIF_IN_WR_LIM_CONF2 0xC8 +#define JPEG_VBIF_OUT_RD_LIM_CONF0 0xD0 +#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4 +#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8 +#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC +#define JPEG_VBIF_ARB_CTL 0xF0 +#define JPEG_VBIF_OUT_AXI_AOOO_EN 0x178 +#define JPEG_VBIF_OUT_AXI_AOOO 0x17c +#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB 0x124 +#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160 +#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164 + +#endif /* MSM_JPEG_HW_REG_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_platform.c new file mode 100644 index 0000000000000000000000000000000000000000..1243d8b42fefc1acaf7e1fb9907c6db02a6469ec --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_platform.c @@ -0,0 +1,460 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_jpeg_platform.h" +#include "msm_jpeg_sync.h" +#include "msm_jpeg_common.h" +#include "msm_jpeg_hw.h" +#include "msm_camera_io_util.h" + +#define JPEG_CLK_INFO_MAX 16 + +static struct msm_cam_clk_info jpeg_8x_clk_info[JPEG_CLK_INFO_MAX]; + +static int msm_jpeg_get_clk_info(struct msm_jpeg_device *jpeg_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[JPEG_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + JPEG_DBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > JPEG_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + JPEG_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(jpeg_8x_clk_info[i].clk_name)); + JPEG_DBG("clock-names[%d] = %s\n", + i, jpeg_8x_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + jpeg_8x_clk_info[i].clk_rate = + (rates[i] == 0) ? -1 : rates[i]; + JPEG_DBG("clk_rate[%d] = %ld\n", + i, jpeg_8x_clk_info[i].clk_rate); + } + jpeg_dev->num_clk = count; + return 0; +} + + +int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, + long clk_rate) +{ + int rc = 0; + struct clk *jpeg_clk; + + jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk"); + if (IS_ERR(jpeg_clk)) { + JPEG_PR_ERR("%s get failed\n", "core_clk"); + rc = PTR_ERR(jpeg_clk); + return rc; + } + + rc = clk_set_rate(jpeg_clk, clk_rate); + + return rc; +} + +void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file, + struct ion_handle **ionhandle, int domain_num) +{ + ion_unmap_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0); + ion_free(pgmn_dev->jpeg_client, *ionhandle); + *ionhandle = NULL; +} + +uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, + uint32_t len, struct file **file_p, struct ion_handle **ionhandle, + int domain_num) { + dma_addr_t paddr; + unsigned long size; + int rc; + *ionhandle = ion_import_dma_buf(pgmn_dev->jpeg_client, fd); + if (IS_ERR_OR_NULL(*ionhandle)) + return 0; + + rc = ion_map_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0, + SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0); + JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__, + (uint32_t)paddr, size); + + if (rc < 0) { + JPEG_PR_ERR("%s: ion_map_iommu fd %d error %d\n", __func__, fd, + rc); + goto error1; + } + + /* validate user input */ + if (len > size) { + JPEG_PR_ERR("%s: invalid offset + len\n", __func__); + goto error1; + } + + return paddr; +error1: + ion_free(pgmn_dev->jpeg_client, *ionhandle); + return 0; +} + +static void set_vbif_params(struct msm_jpeg_device *pgmn_dev, + void *jpeg_vbif_base) +{ + writel_relaxed(0x1, + jpeg_vbif_base + JPEG_VBIF_CLKON); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF0); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF1); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_RD_LIM_CONF2); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF0); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF1); + writel_relaxed(0x10101010, + jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2); + writel_relaxed(0x00001010, + jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0); + writel_relaxed(0x00000110, + jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0); + writel_relaxed(0x00000707, + jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST); + writel_relaxed(0x7, + jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST); + writel_relaxed(0x00000030, + jpeg_vbif_base + JPEG_VBIF_ARB_CTL); + writel_relaxed(0x00000FFF, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN); + writel_relaxed(0x0FFF0FFF, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO); + /*FE and WE QOS configuration need to be set when + QOS RR arbitration is enabled*/ + if (pgmn_dev->hw_version != JPEG_8974_V1) + writel_relaxed(0x00000003, + jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); + else + writel_relaxed(0x00000001, + jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB); + + writel_relaxed(0x22222222, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0); + writel_relaxed(0x2222, + jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1); +} + +static struct msm_bus_vectors msm_jpeg_init_vectors[] = { + { + .src = MSM_BUS_MASTER_JPEG, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = 0, + .ib = 0, + }, +}; + +static struct msm_bus_vectors msm_jpeg_vectors[] = { + { + .src = MSM_BUS_MASTER_JPEG, + .dst = MSM_BUS_SLAVE_EBI_CH0, + .ab = JPEG_CLK_RATE * 2.5, + .ib = JPEG_CLK_RATE * 2.5, + }, +}; + +static struct msm_bus_paths msm_jpeg_bus_client_config[] = { + { + ARRAY_SIZE(msm_jpeg_init_vectors), + msm_jpeg_init_vectors, + }, + { + ARRAY_SIZE(msm_jpeg_vectors), + msm_jpeg_vectors, + }, +}; + +static struct msm_bus_scale_pdata msm_jpeg_bus_client_pdata = { + msm_jpeg_bus_client_config, + ARRAY_SIZE(msm_jpeg_bus_client_config), + .name = "msm_jpeg", +}; + +#ifdef CONFIG_MSM_IOMMU +static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + int i; + + for (i = 0; i < pgmn_dev->iommu_cnt; i++) { + int rc = iommu_attach_device(pgmn_dev->domain, + pgmn_dev->iommu_ctx_arr[i]); + if (rc < 0) { + JPEG_PR_ERR("%s: Device attach failed\n", __func__); + return -ENODEV; + } + JPEG_DBG("%s:%d] dom 0x%lx ctx 0x%lx", __func__, __LINE__, + (unsigned long)pgmn_dev->domain, + (unsigned long)pgmn_dev->iommu_ctx_arr[i]); + } + return 0; +} +static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + int i; + + for (i = 0; i < pgmn_dev->iommu_cnt; i++) { + JPEG_DBG("%s:%d] dom 0x%lx ctx 0x%lx", __func__, __LINE__, + (unsigned long)pgmn_dev->domain, + (unsigned long)pgmn_dev->iommu_ctx_arr[i]); + iommu_detach_device(pgmn_dev->domain, + pgmn_dev->iommu_ctx_arr[i]); + } + return 0; +} +#else +static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + return 0; +} +static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev) +{ + return 0; +} +#endif + + + +int msm_jpeg_platform_init(struct platform_device *pdev, + struct resource **mem, + void **base, + int *irq, + irqreturn_t (*handler) (int, void *), + void *context) +{ + int rc = -1; + int jpeg_irq; + struct resource *jpeg_mem, *vbif_mem, *jpeg_io, *jpeg_irq_res; + void *jpeg_base; + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *) context; + + pgmn_dev->state = MSM_JPEG_IDLE; + + jpeg_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!jpeg_mem) { + JPEG_PR_ERR("%s: jpeg no mem resource?\n", __func__); + return -ENODEV; + } + + vbif_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!vbif_mem) { + JPEG_PR_ERR("%s: vbif no mem resource?\n", __func__); + return -ENODEV; + } + + jpeg_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!jpeg_irq_res) { + JPEG_PR_ERR("no irq resource?\n"); + return -ENODEV; + } + jpeg_irq = jpeg_irq_res->start; + JPEG_DBG("%s base address: 0x%x, jpeg irq number: %d\n", __func__, + jpeg_mem->start, jpeg_irq); + + pgmn_dev->jpeg_bus_client = + msm_bus_scale_register_client(&msm_jpeg_bus_client_pdata); + if (!pgmn_dev->jpeg_bus_client) { + JPEG_PR_ERR("%s: Registration Failed!\n", __func__); + pgmn_dev->jpeg_bus_client = 0; + return -EINVAL; + } + msm_bus_scale_client_update_request( + pgmn_dev->jpeg_bus_client, 1); + + jpeg_io = request_mem_region(jpeg_mem->start, + resource_size(jpeg_mem), pdev->name); + if (!jpeg_io) { + JPEG_PR_ERR("%s: region already claimed\n", __func__); + return -EBUSY; + } + + jpeg_base = ioremap(jpeg_mem->start, resource_size(jpeg_mem)); + if (!jpeg_base) { + rc = -ENOMEM; + JPEG_PR_ERR("%s: ioremap failed\n", __func__); + goto fail_remap; + } + + pgmn_dev->jpeg_fs = regulator_get(&pgmn_dev->pdev->dev, "vdd"); + rc = regulator_enable(pgmn_dev->jpeg_fs); + if (rc) { + JPEG_PR_ERR("%s:%d]jpeg regulator get failed\n", + __func__, __LINE__); + goto fail_fs; + } + + if (msm_jpeg_get_clk_info(pgmn_dev, pgmn_dev->pdev) < 0) { + JPEG_PR_ERR("%s:%d]jpeg clock get failed\n", + __func__, __LINE__); + goto fail_fs; + } + + rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, + pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 1); + if (rc < 0) { + JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); + goto fail_clk; + } + + pgmn_dev->hw_version = readl_relaxed(jpeg_base + + JPEG_HW_VERSION); + JPEG_DBG_HIGH("%s:%d] jpeg HW version 0x%x", __func__, __LINE__, + pgmn_dev->hw_version); + + pgmn_dev->jpeg_vbif = ioremap(vbif_mem->start, resource_size(vbif_mem)); + if (!pgmn_dev->jpeg_vbif) { + rc = -ENOMEM; + JPEG_PR_ERR("%s: ioremap failed\n", __func__); + goto fail_vbif; + } + + JPEG_DBG("%s:%d] jpeg_vbif 0x%x", __func__, __LINE__, + (uint32_t)pgmn_dev->jpeg_vbif); + + rc = msm_jpeg_attach_iommu(pgmn_dev); + if (rc < 0) + goto fail_iommu; + + set_vbif_params(pgmn_dev, pgmn_dev->jpeg_vbif); + + rc = request_irq(jpeg_irq, handler, IRQF_TRIGGER_RISING, "jpeg", + context); + if (rc) { + JPEG_PR_ERR("%s: request_irq failed, %d\n", __func__, + jpeg_irq); + goto fail_request_irq; + } + + *mem = jpeg_mem; + *base = jpeg_base; + *irq = jpeg_irq; + + pgmn_dev->jpeg_client = msm_ion_client_create("camera/jpeg"); + JPEG_DBG("%s:%d] success\n", __func__, __LINE__); + + pgmn_dev->state = MSM_JPEG_INIT; + return rc; + +fail_request_irq: + msm_jpeg_detach_iommu(pgmn_dev); + +fail_iommu: + iounmap(pgmn_dev->jpeg_vbif); + + +fail_vbif: + msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, + pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 0); + +fail_clk: + rc = regulator_disable(pgmn_dev->jpeg_fs); + if (!rc) + regulator_put(pgmn_dev->jpeg_fs); + else + JPEG_PR_ERR("%s:%d] regulator disable failed %d", + __func__, __LINE__, rc); + pgmn_dev->jpeg_fs = NULL; + +fail_fs: + iounmap(jpeg_base); + +fail_remap: + release_mem_region(jpeg_mem->start, resource_size(jpeg_mem)); + JPEG_DBG("%s:%d] fail\n", __func__, __LINE__); + return rc; +} + +int msm_jpeg_platform_release(struct resource *mem, void *base, int irq, + void *context) +{ + int result = 0; + + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *) context; + + free_irq(irq, context); + + msm_jpeg_detach_iommu(pgmn_dev); + + if (pgmn_dev->jpeg_bus_client) { + msm_bus_scale_client_update_request( + pgmn_dev->jpeg_bus_client, 0); + msm_bus_scale_unregister_client(pgmn_dev->jpeg_bus_client); + } + + msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_8x_clk_info, + pgmn_dev->jpeg_clk, pgmn_dev->num_clk, 0); + JPEG_DBG("%s:%d] clock disbale done", __func__, __LINE__); + + if (pgmn_dev->jpeg_fs) { + result = regulator_disable(pgmn_dev->jpeg_fs); + if (!result) + regulator_put(pgmn_dev->jpeg_fs); + else + JPEG_PR_ERR("%s:%d] regulator disable failed %d", + __func__, __LINE__, result); + pgmn_dev->jpeg_fs = NULL; + } + iounmap(pgmn_dev->jpeg_vbif); + iounmap(base); + release_mem_region(mem->start, resource_size(mem)); + ion_client_destroy(pgmn_dev->jpeg_client); + pgmn_dev->state = MSM_JPEG_IDLE; + JPEG_DBG("%s:%d] success\n", __func__, __LINE__); + return result; +} + diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_platform.h new file mode 100644 index 0000000000000000000000000000000000000000..b59c41f8780c9a21853dde4e85c7195c402d76d4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_platform.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_JPEG_PLATFORM_H +#define MSM_JPEG_PLATFORM_H + +#include +#include +#include +#include +#include "msm_jpeg_sync.h" +#define JPEG_CLK_RATE 266670000 + +int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev, + long clk_rate); +void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file, + struct ion_handle **ionhandle, int domain_num); +uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd, + uint32_t len, struct file **file, struct ion_handle **ionhandle, + int domain_num); + +int msm_jpeg_platform_clk_enable(void); +int msm_jpeg_platform_clk_disable(void); + +int msm_jpeg_platform_init(struct platform_device *pdev, + struct resource **mem, + void **base, + int *irq, + irqreturn_t (*handler) (int, void *), + void *context); +int msm_jpeg_platform_release(struct resource *mem, void *base, int irq, + void *context); + +#endif /* MSM_JPEG_PLATFORM_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_sync.c new file mode 100644 index 0000000000000000000000000000000000000000..3939cde84432a7ab0ceec78f737a4e628a5865c3 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_sync.c @@ -0,0 +1,1292 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include "msm_jpeg_sync.h" +#include "msm_jpeg_core.h" +#include "msm_jpeg_platform.h" +#include "msm_jpeg_common.h" + +#define JPEG_REG_SIZE 0x308 +#define JPEG_DEV_CNT 3 +#define JPEG_DEC_ID 2 +#define UINT32_MAX (0xFFFFFFFFU) + +#ifdef CONFIG_COMPAT +#define MSM_JPEG_IOCTL_RESET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd32) + +#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_INPUT_GET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_OUTPUT_GET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf32) + +#define MSM_JPEG_IOCTL_EVT_GET32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd32) + +#define MSM_JPEG_IOCTL_TEST_DUMP_REGION32 \ + _IOW(MSM_JPEG_IOCTL_MAGIC, 15, compat_ulong_t) + +struct msm_jpeg_ctrl_cmd32 { + uint32_t type; + uint32_t len; + compat_uptr_t value; +}; +struct msm_jpeg_buf32 { + uint32_t type; + int fd; + + compat_uptr_t vaddr; + + uint32_t y_off; + uint32_t y_len; + uint32_t framedone_len; + + uint32_t cbcr_off; + uint32_t cbcr_len; + + uint32_t num_of_mcu_rows; + uint32_t offset; + uint32_t pln2_off; + uint32_t pln2_len; +}; + +#endif + + +inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p) +{ + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name); + q_p->name = name; + spin_lock_init(&q_p->lck); + INIT_LIST_HEAD(&q_p->q); + init_waitqueue_head(&q_p->wait); + q_p->unblck = 0; +} + +inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p) +{ + unsigned long flags; + struct msm_jpeg_q_entry *q_entry_p = NULL; + void *data = NULL; + + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + spin_lock_irqsave(&q_p->lck, flags); + if (!list_empty(&q_p->q)) { + q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry, + list); + list_del_init(&q_entry_p->list); + } + spin_unlock_irqrestore(&q_p->lck, flags); + + if (q_entry_p) { + data = q_entry_p->data; + kfree(q_entry_p); + } else { + JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__, + q_p->name); + } + + return data; +} + +inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data) +{ + unsigned long flags; + + struct msm_jpeg_q_entry *q_entry_p; + + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + + q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC); + if (!q_entry_p) { + JPEG_PR_ERR("%s: no mem\n", __func__); + return -EFAULT; + } + q_entry_p->data = data; + + spin_lock_irqsave(&q_p->lck, flags); + list_add_tail(&q_entry_p->list, &q_p->q); + spin_unlock_irqrestore(&q_p->lck, flags); + + return 0; +} + +inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p, + struct msm_jpeg_core_buf *buf) +{ + struct msm_jpeg_core_buf *buf_p; + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); + if (!buf_p) { + JPEG_PR_ERR("%s: no mem\n", __func__); + return -EFAULT; + } + + memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf)); + + msm_jpeg_q_in(q_p, buf_p); + return 0; +} + +inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p) +{ + long tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */ + int rc; + + JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name); + rc = wait_event_interruptible_timeout(q_p->wait, + (!list_empty_careful(&q_p->q) || q_p->unblck), + msecs_to_jiffies(tm)); + JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name); + if (list_empty_careful(&q_p->q)) { + if (rc == 0) { + rc = -ETIMEDOUT; + JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__, + q_p->name); + } else if (q_p->unblck) { + JPEG_DBG("%s:%d] %s unblock is true\n", __func__, + __LINE__, q_p->name); + q_p->unblck = 0; + rc = -ECANCELED; + } else if (rc < 0) { + JPEG_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__, + q_p->name, rc); + } + } + return rc; +} + +inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p) +{ + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + wake_up(&q_p->wait); + return 0; +} + +inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p) +{ + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + q_p->unblck = 1; + wake_up(&q_p->wait); + return 0; +} + +inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_q *q_p, int domain_num) +{ + struct msm_jpeg_core_buf *buf_p; + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + do { + buf_p = msm_jpeg_q_out(q_p); + if (buf_p) { + msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, + &buf_p->handle, domain_num); + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + kfree(buf_p); + } + } while (buf_p); + q_p->unblck = 0; +} + +inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p) +{ + void *data; + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + do { + data = msm_jpeg_q_out(q_p); + if (data) { + JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name); + kfree(data); + } + } while (data); + q_p->unblck = 0; +} + +/*************** event queue ****************/ + +int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf_in) +{ + int rc = 0; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + if (buf_in) { + buf_in->vbuf.framedone_len = buf_in->framedone_len; + buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE; + JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n", + __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len, + buf_in->vbuf.framedone_len); + rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in); + } else { + JPEG_PR_ERR("%s:%d] no output return buffer\n", + __func__, __LINE__); + rc = -1; + } + + if (buf_in) + rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); + + return rc; +} + +int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev, + void __user *to) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_ctrl_cmd ctrl_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + msm_jpeg_q_wait(&pgmn_dev->evt_q); + buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q); + + if (!buf_p) { + JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__); + return -EAGAIN; + } + + memset(&ctrl_cmd, 0, sizeof(ctrl_cmd)); + ctrl_cmd.type = buf_p->vbuf.type; + kfree(buf_p); + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) ctrl_cmd.value, ctrl_cmd.len); + + if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) { + JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_unblock(&pgmn_dev->evt_q); + return 0; +} + +void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d]\n", __func__, __LINE__); +} + +void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev, + int event) +{ + int rc = 0; + struct msm_jpeg_core_buf buf; + + JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event); + + buf.vbuf.type = MSM_JPEG_EVT_ERR; + rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf); + if (!rc) + rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q); + + if (!rc) + JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__); + + return; +} + +/*************** output queue ****************/ + +int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf_in) +{ + int rc = 0; + struct msm_jpeg_core_buf *buf_out; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (buf_in) { + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len); + rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in); + } else { + JPEG_DBG("%s:%d] no output return buffer\n", __func__, + __LINE__); + rc = -1; + return rc; + } + + buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q); + + if (buf_out) { + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_out->y_buffer_addr, buf_out->y_len); + rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out); + kfree(buf_out); + } else { + msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in); + JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__); + rc = -2; + } + + if (buf_in) + rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q); + + return rc; +} + +int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev, void __user *to) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_buf buf_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + msm_jpeg_q_wait(&pgmn_dev->output_rtn_q); + buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q); + + if (!buf_p) { + JPEG_DBG("%s:%d] no output buffer return\n", + __func__, __LINE__); + return -EAGAIN; + } + + buf_cmd = buf_p->vbuf; + msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle, + pgmn_dev->domain_num); + kfree(buf_p); + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { + JPEG_PR_ERR("%s:%d]", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q); + return 0; +} + +int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev, + void __user *arg) +{ + struct msm_jpeg_buf buf_cmd; + struct msm_jpeg_core_buf *buf_p; + memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); + if (!buf_p) { + JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + return -EFAULT; + } + + JPEG_DBG("%s:%d] vaddr = 0x%08x y_len = %d\n, fd = %d", + __func__, __LINE__, (int) buf_cmd.vaddr, buf_cmd.y_len, + buf_cmd.fd); + + buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, + buf_cmd.y_len + buf_cmd.cbcr_len + buf_cmd.pln2_len, + &buf_p->file, &buf_p->handle, pgmn_dev->domain_num); + if (!buf_p->y_buffer_addr) { + JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); + kfree(buf_p); + return -EFAULT; + } + + if (buf_cmd.cbcr_len) + buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + + buf_cmd.y_len; + else + buf_p->cbcr_buffer_addr = 0x0; + + if (buf_cmd.pln2_len) + buf_p->pln2_addr = buf_p->cbcr_buffer_addr + + buf_cmd.cbcr_len; + else + buf_p->pln2_addr = 0x0; + + JPEG_DBG("%s:%d]After v2p pln0_addr %x pln0_len %d", + __func__, __LINE__, buf_p->y_buffer_addr, + buf_cmd.y_len); + + JPEG_DBG("pl1_len %d, pln1_addr %x, pln2_adrr %x,pln2_len %d", + buf_cmd.cbcr_len, buf_p->cbcr_buffer_addr, + buf_p->pln2_addr, buf_cmd.pln2_len); + + buf_p->y_len = buf_cmd.y_len; + buf_p->cbcr_len = buf_cmd.cbcr_len; + buf_p->pln2_len = buf_cmd.pln2_len; + buf_p->vbuf = buf_cmd; + + msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p); + return 0; +} + +/*************** input queue ****************/ + +int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev, + struct msm_jpeg_core_buf *buf_in) +{ + struct msm_jpeg_core_buf *buf_out; + int rc = 0; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + if (buf_in) { + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_in->y_buffer_addr, buf_in->y_len); + rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in); + } else { + JPEG_DBG("%s:%d] no input return buffer\n", __func__, + __LINE__); + rc = -EFAULT; + } + + buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); + + if (buf_out) { + rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); + kfree(buf_out); + msm_jpeg_core_fe_start(pgmn_dev); + } else { + JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__); + rc = -EFAULT; + } + + if (buf_in) + rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q); + + return rc; +} + +int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev, void __user *to) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_buf buf_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_wait(&pgmn_dev->input_rtn_q); + buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q); + + if (!buf_p) { + JPEG_DBG("%s:%d] no input buffer return\n", + __func__, __LINE__); + return -EAGAIN; + } + + buf_cmd = buf_p->vbuf; + msm_jpeg_platform_p2v(pgmn_dev, buf_p->file, &buf_p->handle, + pgmn_dev->domain_num); + kfree(buf_p); + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) { + JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q); + return 0; +} + +int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev, + void __user *arg) +{ + struct msm_jpeg_core_buf *buf_p; + struct msm_jpeg_buf buf_cmd; + memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf)); + + if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC); + if (!buf_p) { + JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__); + return -EFAULT; + } + + JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, + (int) buf_cmd.vaddr, buf_cmd.y_len); + + buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd, + buf_cmd.y_len + buf_cmd.cbcr_len + + buf_cmd.pln2_len + buf_cmd.offset, + &buf_p->file, &buf_p->handle, pgmn_dev->domain_num) + + buf_cmd.offset + buf_cmd.y_off; + buf_p->y_len = buf_cmd.y_len; + buf_p->cbcr_len = buf_cmd.cbcr_len; + buf_p->pln2_len = buf_cmd.pln2_len; + buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows; + + if (buf_cmd.cbcr_len) + buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + + buf_cmd.y_len + buf_cmd.cbcr_off; + else + buf_p->cbcr_buffer_addr = 0x0; + + if (buf_cmd.pln2_len) + buf_p->pln2_addr = buf_p->cbcr_buffer_addr + + buf_cmd.cbcr_len + buf_cmd.pln2_off; + else + buf_p->pln2_addr = 0x0; + + JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%d", + __func__, buf_p->y_buffer_addr, buf_p->y_len, + buf_p->cbcr_buffer_addr, buf_p->cbcr_len); + JPEG_DBG("pln2_addr = %x, pln2_len = %d, fd =%d\n", + buf_p->pln2_addr, buf_p->pln2_len, buf_cmd.fd); + + if (!buf_p->y_buffer_addr) { + JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__); + kfree(buf_p); + return -EFAULT; + } + buf_p->vbuf = buf_cmd; + + msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p); + + return 0; +} + +int msm_jpeg_irq(int event, void *context, void *data) +{ + struct msm_jpeg_device *pgmn_dev = + (struct msm_jpeg_device *) context; + + switch (event) { + case MSM_JPEG_EVT_SESSION_DONE: + msm_jpeg_framedone_irq(pgmn_dev, data); + msm_jpeg_we_pingpong_irq(pgmn_dev, data); + break; + + case MSM_JPEG_HW_MASK_COMP_FE: + msm_jpeg_fe_pingpong_irq(pgmn_dev, data); + break; + + case MSM_JPEG_HW_MASK_COMP_WE: + msm_jpeg_we_pingpong_irq(pgmn_dev, data); + break; + + case MSM_JPEG_HW_MASK_COMP_RESET_ACK: + msm_jpeg_reset_ack_irq(pgmn_dev); + break; + + case MSM_JPEG_HW_MASK_COMP_ERR: + default: + msm_jpeg_err_irq(pgmn_dev, event); + break; + } + + return 0; +} + +int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev) +{ + int rc; + + mutex_lock(&pgmn_dev->lock); + if (pgmn_dev->open_count) { + /* only open once */ + JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__); + mutex_unlock(&pgmn_dev->lock); + return -EBUSY; + } + pgmn_dev->open_count++; + mutex_unlock(&pgmn_dev->lock); + + msm_jpeg_core_irq_install(msm_jpeg_irq); + rc = msm_jpeg_platform_init(pgmn_dev->pdev, + &pgmn_dev->mem, &pgmn_dev->base, + &pgmn_dev->irq, msm_jpeg_core_irq, pgmn_dev); + if (rc) { + JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__, + __LINE__, rc); + return rc; + } + + JPEG_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n", + __func__, __LINE__, + pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq); + pgmn_dev->res_size = resource_size(pgmn_dev->mem); + + msm_jpeg_q_cleanup(&pgmn_dev->evt_q); + msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); + msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q, + pgmn_dev->domain_num); + msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); + msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q); + msm_jpeg_core_init(pgmn_dev); + + JPEG_DBG("%s:%d] success\n", __func__, __LINE__); + return rc; +} + +int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + mutex_lock(&pgmn_dev->lock); + if (!pgmn_dev->open_count) { + JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__); + mutex_unlock(&pgmn_dev->lock); + return -EINVAL; + } + pgmn_dev->open_count--; + mutex_unlock(&pgmn_dev->lock); + + msm_jpeg_core_release(pgmn_dev, pgmn_dev->domain_num); + msm_jpeg_q_cleanup(&pgmn_dev->evt_q); + msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q); + msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q, + pgmn_dev->domain_num); + msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q); + msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q, + pgmn_dev->domain_num); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + if (pgmn_dev->open_count) + JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__); + + msm_jpeg_platform_release(pgmn_dev->mem, pgmn_dev->base, + pgmn_dev->irq, pgmn_dev); + + JPEG_DBG("%s:%d]\n", __func__, __LINE__); + return 0; +} + +int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + struct msm_jpeg_hw_cmd hw_cmd; + int is_copy_to_user; + + if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_jpeg_hw_cmd))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1, + pgmn_dev->res_size, pgmn_dev->base); + JPEG_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x,pdata %x\n", + __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset, + hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata); + + if (is_copy_to_user >= 0) { + if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + } else { + return is_copy_to_user; + } + + return 0; +} + +int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + int is_copy_to_user; + uint32_t len; + uint32_t m; + struct msm_jpeg_hw_cmds *hw_cmds_p; + struct msm_jpeg_hw_cmd *hw_cmd_p; + + if (copy_from_user(&m, arg, sizeof(m))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) / + sizeof(struct msm_jpeg_hw_cmd)))) { + JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__); + return -EFAULT; + } + + len = sizeof(struct msm_jpeg_hw_cmds) + + sizeof(struct msm_jpeg_hw_cmd) * (m - 1); + hw_cmds_p = kmalloc(len, GFP_KERNEL); + if (!hw_cmds_p) { + JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len); + return -EFAULT; + } + + if (copy_from_user(hw_cmds_p, arg, len)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + kfree(hw_cmds_p); + return -EFAULT; + } + + hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd); + + is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m, + pgmn_dev->res_size, pgmn_dev->base); + + if (is_copy_to_user >= 0) { + if (copy_to_user(arg, hw_cmds_p, len)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + kfree(hw_cmds_p); + return -EFAULT; + } + } else { + kfree(hw_cmds_p); + return is_copy_to_user; + } + kfree(hw_cmds_p); + return 0; +} + +int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void * __user arg) +{ + struct msm_jpeg_core_buf *buf_out; + struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL}; + int i, rc; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + pgmn_dev->release_buf = 1; + for (i = 0; i < 2; i++) { + buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q); + + if (buf_out) { + msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out); + kfree(buf_out); + } else { + JPEG_DBG("%s:%d] no input buffer\n", __func__, + __LINE__); + break; + } + } + + for (i = 0; i < 2; i++) { + buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q); + + if (buf_out_free[i]) { + msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]); + pgmn_dev->release_buf = 0; + } else { + JPEG_DBG("%s:%d] no output buffer\n", + __func__, __LINE__); + break; + } + } + + for (i = 0; i < 2; i++) + kfree(buf_out_free[i]); + + pgmn_dev->state = MSM_JPEG_EXECUTING; + JPEG_DBG_HIGH("%s:%d] START\n", __func__, __LINE__); + wmb(); + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg); + wmb(); + + JPEG_DBG("%s:%d]", __func__, __LINE__); + return rc; +} + +int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + int rc; + struct msm_jpeg_ctrl_cmd ctrl_cmd; + + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + + if (pgmn_dev->state == MSM_JPEG_INIT) { + if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + pgmn_dev->op_mode = ctrl_cmd.type; + + rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode, pgmn_dev->base, + resource_size(pgmn_dev->mem)); + } else { + JPEG_PR_ERR("%s:%d] JPEG not been initialized Wrong state\n", + __func__, __LINE__); + rc = -1; + } + return rc; +} + +int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev, + unsigned long arg) +{ + JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__); + msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE); + return 0; +} + +int msm_jpeg_ioctl_set_clk_rate(struct msm_jpeg_device *pgmn_dev, + void * __user arg) +{ + long clk_rate; + int rc; + + if ((pgmn_dev->state != MSM_JPEG_INIT) && + (pgmn_dev->state != MSM_JPEG_RESET)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + if (get_user(clk_rate, (unsigned int __user *)arg)) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + JPEG_DBG("%s:%d] Requested clk rate %ld\n", __func__, __LINE__, + clk_rate); + if (clk_rate < 0) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + rc = msm_jpeg_platform_set_clk_rate(pgmn_dev, clk_rate); + if (rc < 0) { + JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc); + return -EFAULT; + } + + return 0; +} +#ifdef CONFIG_COMPAT +int msm_jpeg_get_compat_ctrl_cmd(struct msm_jpeg_ctrl_cmd *ctrl_cmd, + void __user *arg) +{ + struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; + unsigned long temp; + if (copy_from_user(&ctrl_cmd32, arg, + sizeof(struct msm_jpeg_ctrl_cmd32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + ctrl_cmd->type = ctrl_cmd32.type; + ctrl_cmd->len = ctrl_cmd32.len; + temp = (unsigned long) ctrl_cmd32.value; + ctrl_cmd->value = (void *) temp; + + return 0; +} +int msm_jpeg_put_compat_ctrl_cmd(struct msm_jpeg_ctrl_cmd *ctrl_cmd, + void __user *arg) +{ + struct msm_jpeg_ctrl_cmd32 ctrl_cmd32; + unsigned long temp; + + ctrl_cmd32.type = ctrl_cmd->type; + ctrl_cmd32.len = ctrl_cmd->len; + temp = (unsigned long) ctrl_cmd->value; + ctrl_cmd32.value = (compat_uptr_t) temp; + + if (copy_from_user(arg, &ctrl_cmd32, + sizeof(struct msm_jpeg_ctrl_cmd32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + + return 0; +} + +int msm_jpeg_get_jpeg_buf(struct msm_jpeg_buf *jpeg_buf, + void __user *arg) +{ + struct msm_jpeg_buf32 jpeg_buf32; + unsigned long temp; + if (copy_from_user(&jpeg_buf32, arg, sizeof(struct msm_jpeg_buf32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + jpeg_buf->type = jpeg_buf32.type; + jpeg_buf->fd = jpeg_buf32.fd; + temp = (unsigned long) jpeg_buf32.vaddr; + jpeg_buf->vaddr = (void *) temp; + jpeg_buf->y_off = jpeg_buf32.y_off; + jpeg_buf->y_len = jpeg_buf32.y_len; + jpeg_buf->framedone_len = jpeg_buf32.framedone_len; + jpeg_buf->cbcr_off = jpeg_buf32.cbcr_off; + jpeg_buf->cbcr_len = jpeg_buf32.cbcr_len; + jpeg_buf->num_of_mcu_rows = jpeg_buf32.num_of_mcu_rows; + jpeg_buf->offset = jpeg_buf32.offset; + jpeg_buf->pln2_off = jpeg_buf32.pln2_off; + jpeg_buf->pln2_len = jpeg_buf32.pln2_len; + + return 0; +} +int msm_jpeg_put_jpeg_buf(struct msm_jpeg_buf *jpeg_buf, + void __user *arg) +{ + struct msm_jpeg_buf32 jpeg_buf32; + unsigned long temp; + + jpeg_buf32.type = jpeg_buf->type; + jpeg_buf32.fd = jpeg_buf->fd; + temp = (unsigned long) jpeg_buf->vaddr; + jpeg_buf32.vaddr = (compat_uptr_t) temp; + jpeg_buf32.y_off = jpeg_buf->y_off; + jpeg_buf32.y_len = jpeg_buf->y_len; + jpeg_buf32.framedone_len = jpeg_buf->framedone_len; + jpeg_buf32.cbcr_off = jpeg_buf->cbcr_off; + jpeg_buf32.cbcr_len = jpeg_buf->cbcr_len; + jpeg_buf32.num_of_mcu_rows = jpeg_buf->num_of_mcu_rows; + jpeg_buf32.offset = jpeg_buf->offset; + jpeg_buf32.pln2_off = jpeg_buf->pln2_off; + jpeg_buf32.pln2_len = jpeg_buf->pln2_len; + + if (copy_to_user(arg, &jpeg_buf32, sizeof(struct msm_jpeg_buf32))) { + JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__); + return -EFAULT; + } + return 0; +} + +long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + struct msm_jpeg_ctrl_cmd ctrl_cmd; + struct msm_jpeg_buf jpeg_buf; + switch (cmd) { + case MSM_JPEG_IOCTL_GET_HW_VERSION: + JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_RESET: + rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_RESET32: + rc = msm_jpeg_get_compat_ctrl_cmd(&ctrl_cmd, + (void __user *) arg); + if (rc < 0) + break; + rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) &ctrl_cmd); + break; + + case MSM_JPEG_IOCTL_STOP: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + pgmn_dev->state = MSM_JPEG_STOPPED; + break; + + case MSM_JPEG_IOCTL_START: + rc = msm_jpeg_start(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: + rc = msm_jpeg_input_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32: + rc = msm_jpeg_get_jpeg_buf(&jpeg_buf, (void __user *) arg); + if (rc < 0) + break; + rc = msm_jpeg_input_buf_enqueue(pgmn_dev, + (void __user *) &jpeg_buf); + break; + + case MSM_JPEG_IOCTL_INPUT_GET: + rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_GET32: + rc = msm_jpeg_input_get(pgmn_dev, (void __user *) &jpeg_buf); + if (rc < 0) + break; + rc = msm_jpeg_put_jpeg_buf(&jpeg_buf, (void __user *) arg); + + break; + + case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: + rc = msm_jpeg_input_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: + rc = msm_jpeg_output_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32: + rc = msm_jpeg_get_jpeg_buf(&jpeg_buf, (void __user *) arg); + if (rc < 0) + break; + rc = msm_jpeg_output_buf_enqueue(pgmn_dev, + (void __user *) &jpeg_buf); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET: + rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET32: + rc = msm_jpeg_output_get(pgmn_dev, (void __user *) &jpeg_buf); + if (rc < 0) + break; + rc = msm_jpeg_put_jpeg_buf(&jpeg_buf, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: + rc = msm_jpeg_output_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_EVT_GET: + rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_EVT_GET32: + rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) &ctrl_cmd); + if (rc < 0) + break; + msm_jpeg_put_compat_ctrl_cmd(&ctrl_cmd, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: + rc = msm_jpeg_evt_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_HW_CMD: + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_HW_CMDS: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_TEST_DUMP_REGION: + rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); + break; + + case MSM_JPEG_IOCTL_TEST_DUMP_REGION32: + rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); + break; + + case MSM_JPEG_IOCTL_SET_CLK_RATE: + rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, + (void __user *) arg); + break; + + default: + JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n", + __func__, __LINE__, _IOC_NR(cmd)); + rc = -EINVAL; + break; + } + return rc; +} +#else +long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg) +{ + return 0; +} +#endif + +long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + switch (cmd) { + case MSM_JPEG_IOCTL_GET_HW_VERSION: + JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__); + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_RESET: + rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_STOP: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + pgmn_dev->state = MSM_JPEG_STOPPED; + break; + + case MSM_JPEG_IOCTL_START: + rc = msm_jpeg_start(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE: + rc = msm_jpeg_input_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_GET: + rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK: + rc = msm_jpeg_input_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE: + rc = msm_jpeg_output_buf_enqueue(pgmn_dev, + (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET: + rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK: + rc = msm_jpeg_output_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_EVT_GET: + rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK: + rc = msm_jpeg_evt_get_unblock(pgmn_dev); + break; + + case MSM_JPEG_IOCTL_HW_CMD: + rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_HW_CMDS: + rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg); + break; + + case MSM_JPEG_IOCTL_TEST_DUMP_REGION: + rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg); + break; + + case MSM_JPEG_IOCTL_SET_CLK_RATE: + rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, (void __user *) arg); + break; + default: + pr_err_ratelimited("%s:%d] cmd = %d not supported\n", + __func__, __LINE__, _IOC_NR(cmd)); + rc = -EINVAL; + break; + } + return rc; +} +#ifdef CONFIG_MSM_IOMMU +static int camera_register_domain(void) +{ + struct msm_iova_partition camera_fw_partition = { + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + + struct msm_iova_layout camera_fw_layout = { + .partitions = &camera_fw_partition, + .npartitions = 1, + .client_name = "camera_jpeg", + .domain_flags = 0, + }; + return msm_register_domain(&camera_fw_layout); +} +#endif + +int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev) +{ + int rc = 0; + int idx = 0; +#ifdef CONFIG_MSM_IOMMU + int i = 0, j = 0; + char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1", + "jpeg_dec"}; +#endif + + mutex_init(&pgmn_dev->lock); + + pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__, + pgmn_dev->pdev->id); + idx = pgmn_dev->pdev->id; + pgmn_dev->idx = idx; + pgmn_dev->iommu_cnt = 1; + pgmn_dev->decode_flag = (idx == JPEG_DEC_ID); + + msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q); + msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q); + msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q); + msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q); + msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q); + +#ifdef CONFIG_MSM_IOMMU + j = (pgmn_dev->iommu_cnt <= 1) ? idx : 0; + /*get device context for IOMMU*/ + for (i = 0; i < pgmn_dev->iommu_cnt; i++) { + pgmn_dev->iommu_ctx_arr[i] = msm_iommu_get_ctx(iommu_name[j]); + JPEG_DBG("%s:%d] name %s", __func__, __LINE__, iommu_name[j]); + JPEG_DBG("%s:%d] ctx 0x%x", __func__, __LINE__, + (uint32_t)pgmn_dev->iommu_ctx_arr[i]); + if (!pgmn_dev->iommu_ctx_arr[i]) { + JPEG_PR_ERR("%s: No iommu fw context found\n", + __func__); + goto error; + } + j++; + } + pgmn_dev->domain_num = camera_register_domain(); + JPEG_DBG("%s:%d] dom_num 0x%x", __func__, __LINE__, + pgmn_dev->domain_num); + if (pgmn_dev->domain_num < 0) { + JPEG_PR_ERR("%s: could not register domain\n", __func__); + goto error; + } + pgmn_dev->domain = msm_get_iommu_domain(pgmn_dev->domain_num); + JPEG_DBG("%s:%d] dom 0x%x", __func__, __LINE__, + (uint32_t)pgmn_dev->domain); + if (!pgmn_dev->domain) { + JPEG_PR_ERR("%s: cannot find domain\n", __func__); + goto error; + } +#endif + + return rc; +#ifdef CONFIG_MSM_IOMMU +error: +#endif + mutex_destroy(&pgmn_dev->lock); + return -EFAULT; +} + +int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev) +{ + mutex_destroy(&pgmn_dev->lock); + kfree(pgmn_dev); + return 0; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_sync.h b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_sync.h new file mode 100644 index 0000000000000000000000000000000000000000..1698f17175c05cfac3a285e9a41741a1f7ad28a9 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/jpeg_10/msm_jpeg_sync.h @@ -0,0 +1,127 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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. + */ + + + +#ifndef MSM_JPEG_SYNC_H +#define MSM_JPEG_SYNC_H + +#include +#include +#include +#include +#include +#include +#include "msm_jpeg_hw.h" + +#define JPEG_8974_V1 0x10000000 +#define JPEG_8974_V2 0x10010000 + +enum msm_jpeg_state { + MSM_JPEG_INIT, + MSM_JPEG_RESET, + MSM_JPEG_EXECUTING, + MSM_JPEG_STOPPED, + MSM_JPEG_IDLE +}; + +struct msm_jpeg_q { + char const *name; + struct list_head q; + spinlock_t lck; + wait_queue_head_t wait; + int unblck; +}; + +struct msm_jpeg_q_entry { + struct list_head list; + void *data; +}; + +struct msm_jpeg_device { + struct platform_device *pdev; + struct resource *mem; + int irq; + void *base; + struct clk *jpeg_clk[5]; + struct regulator *jpeg_fs; + uint32_t hw_version; + + struct device *device; + struct cdev cdev; + struct mutex lock; + char open_count; + uint8_t op_mode; + + /* event queue including frame done & err indications + */ + struct msm_jpeg_q evt_q; + + /* output return queue + */ + struct msm_jpeg_q output_rtn_q; + + /* output buf queue + */ + struct msm_jpeg_q output_buf_q; + + /* input return queue + */ + struct msm_jpeg_q input_rtn_q; + + /* input buf queue + */ + struct msm_jpeg_q input_buf_q; + + struct v4l2_subdev subdev; + + struct class *msm_jpeg_class; + + dev_t msm_jpeg_devno; + + /*iommu domain and context*/ + int domain_num; + int idx; + struct iommu_domain *domain; + struct device *iommu_ctx_arr[3]; + int iommu_cnt; + int decode_flag; + struct ion_client *jpeg_client; + void *jpeg_vbif; + int release_buf; + struct msm_jpeg_hw_pingpong fe_pingpong_buf; + struct msm_jpeg_hw_pingpong we_pingpong_buf; + int we_pingpong_index; + int reset_done_ack; + spinlock_t reset_lock; + wait_queue_head_t reset_wait; + uint32_t res_size; + uint32_t jpeg_bus_client; + uint32_t num_clk; + enum msm_jpeg_state state; +}; + +int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev); +int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev); + +long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg); + +#ifdef CONFIG_COMPAT +long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev, + unsigned int cmd, unsigned long arg); +#endif + +int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev); +int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev); + +#endif /* MSM_JPEG_SYNC_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/msm.c b/drivers/media/platform/msm/camera_v2_j5/msm.c new file mode 100644 index 0000000000000000000000000000000000000000..01f0343a210b4534825a2435592b0f1467c28e1a --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm.c @@ -0,0 +1,1198 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm.h" +#include "msm_vb2.h" +#include "msm_sd.h" +#include + + +static struct v4l2_device *msm_v4l2_dev; +static struct list_head ordered_sd_list; + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) +static struct pm_qos_request msm_v4l2_pm_qos_request; +#endif + +static struct msm_queue_head *msm_session_q; + +/* config node envent queue */ +static struct v4l2_fh *msm_eventq; +spinlock_t msm_eventq_lock; + +static struct pid *msm_pid; +spinlock_t msm_pid_lock; +static int module_init_status; +struct msm_cam_dummy_queue { + wait_queue_head_t state_wait; +}; +static struct msm_cam_dummy_queue cam_dummy_queue; + +#define msm_dequeue(queue, type, member) ({ \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + node = list_first_entry(&__q->list, \ + type, member); \ + if ((node) && (&node->member) && (&node->member.next)) \ + list_del_init(&node->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + node; \ +}) + +#define msm_delete_sd_entry(queue, type, member, q_node) ({ \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if (node->sd == q_node) { \ + __q->len--; \ + list_del_init(&node->member); \ + kzfree(node); \ + break; \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +}) + +#define msm_delete_entry(queue, type, member, q_node) ({ \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if (node == q_node) { \ + __q->len--; \ + list_del_init(&node->member); \ + kzfree(node); \ + break; \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +}) + +#define msm_queue_drain(queue, type, member) do { \ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node; \ + spin_lock_irqsave(&__q->lock, flags); \ + while (!list_empty(&__q->list)) { \ + __q->len--; \ + node = list_first_entry(&__q->list, \ + type, member); \ + if (node) { \ + if (&node->member) \ + list_del_init(&node->member); \ + kzfree(node); \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +} while (0); + +typedef int (*msm_queue_func)(void *d1, void *d2); +#define msm_queue_traverse_action(queue, type, member, func, data) do {\ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + msm_queue_func __f = (func); \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if (node && __f) { \ + __f(node, data); \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ +} while (0) + +typedef int (*msm_queue_find_func)(void *d1, void *d2); +#define msm_queue_find(queue, type, member, func, data) ({\ + unsigned long flags; \ + struct msm_queue_head *__q = (queue); \ + type *node = 0; \ + typeof(node) __ret = NULL; \ + msm_queue_find_func __f = (func); \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + list_for_each_entry(node, &__q->list, member) \ + if ((__f) && __f(node, data)) { \ + __ret = node; \ + break; \ + } \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + __ret; \ +}) + +static void msm_init_queue(struct msm_queue_head *qhead) +{ + BUG_ON(!qhead); + + INIT_LIST_HEAD(&qhead->list); + spin_lock_init(&qhead->lock); + qhead->len = 0; + qhead->max = 0; +} + +static void msm_enqueue(struct msm_queue_head *qhead, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&qhead->lock, flags); + qhead->len++; + if (qhead->len > qhead->max) + qhead->max = qhead->len; + list_add_tail(entry, &qhead->list); + spin_unlock_irqrestore(&qhead->lock, flags); +} + +/* index = session id */ +static inline int __msm_queue_find_session(void *d1, void *d2) +{ + struct msm_session *session = d1; + return (session->session_id == *(unsigned int *)d2) ? 1 : 0; +} + +static inline int __msm_queue_find_stream(void *d1, void *d2) +{ + struct msm_stream *stream = d1; + return (stream->stream_id == *(unsigned int *)d2) ? 1 : 0; +} + +static inline int __msm_queue_find_command_ack_q(void *d1, void *d2) +{ + struct msm_command_ack *ack = d1; + return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0; +} + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) +static void msm_pm_qos_add_request(void) +{ + pr_err("%s: add request",__func__); + pm_qos_add_request(&msm_v4l2_pm_qos_request, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); +} + +static void msm_pm_qos_remove_request(void) +{ + pr_err("%s: remove request",__func__); + msm_v4l2_pm_qos_request.type = PM_QOS_REQ_AFFINE_CORES; + msm_v4l2_pm_qos_request.cpus_affine.bits[0] = 0xF0; + + pm_qos_remove_request(&msm_v4l2_pm_qos_request); +} + +void msm_pm_qos_update_request(int val) +{ + pr_err("%s: update request %d",__func__,val); + pm_qos_update_request(&msm_v4l2_pm_qos_request, val); +} +#endif + +struct msm_session *msm_session_find(unsigned int session_id) +{ + struct msm_session *session; + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (WARN_ON(!session)) + return NULL; + return session; +} + +int msm_create_stream(unsigned int session_id, + unsigned int stream_id, struct vb2_queue *q) +{ + struct msm_session *session; + struct msm_stream *stream; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return -EINVAL; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->stream_id = stream_id; + stream->vb2_q = q; + spin_lock_init(&stream->stream_lock); + msm_enqueue(&session->stream_q, &stream->list); + session->stream_q.len++; + + INIT_LIST_HEAD(&stream->queued_list); + + return 0; +} + +void msm_delete_stream(unsigned int session_id, unsigned int stream_id) +{ + struct msm_session *session = NULL; + struct msm_stream *stream = NULL; + unsigned long flags; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return; + + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + if (!stream) + return; + spin_lock_irqsave(&(session->stream_q.lock), flags); + list_del_init(&stream->list); + session->stream_q.len--; + spin_unlock_irqrestore(&(session->stream_q.lock), flags); + kzfree(stream); +} + +static void msm_sd_unregister_subdev(struct video_device *vdev) +{ + struct v4l2_subdev *sd = video_get_drvdata(vdev); + sd->devnode = NULL; + kzfree(vdev); +} + +static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd) +{ + int rc = 0; + struct video_device *vdev; + + if (!msm_v4l2_dev || !sd || !sd->name[0]) + return -EINVAL; + + rc = v4l2_device_register_subdev(msm_v4l2_dev, sd); + if (rc < 0) + return rc; + + /* Register a device node for every subdev marked with the + * V4L2_SUBDEV_FL_HAS_DEVNODE flag. + */ + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + return rc; + + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (!vdev) { + rc = -ENOMEM; + goto clean_up; + } + + video_set_drvdata(vdev, sd); + strlcpy(vdev->name, sd->name, sizeof(vdev->name)); + vdev->v4l2_dev = msm_v4l2_dev; + vdev->fops = &v4l2_subdev_fops; + vdev->release = msm_sd_unregister_subdev; + rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, + sd->owner); + if (rc < 0) { + kzfree(vdev); + goto clean_up; + } + +#if defined(CONFIG_MEDIA_CONTROLLER) + sd->entity.info.v4l.major = VIDEO_MAJOR; + sd->entity.info.v4l.minor = vdev->minor; + sd->entity.name = video_device_node_name(vdev); +#endif + sd->devnode = vdev; + return 0; + +clean_up: + if (sd->devnode) + video_unregister_device(sd->devnode); + return rc; +} + +static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev, + struct list_head *sd_list) +{ + struct msm_sd_subdev *temp_sd; + + list_for_each_entry(temp_sd, sd_list, list) { + if (msm_subdev->close_seq < temp_sd->close_seq) { + list_add_tail(&msm_subdev->list, &temp_sd->list); + return; + } + } + list_add_tail(&msm_subdev->list, sd_list); +} + +int msm_sd_register(struct msm_sd_subdev *msm_subdev) +{ + if (WARN_ON(!msm_subdev)) + return -EINVAL; + + if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev)) + return -EIO; + + msm_add_sd_in_position(msm_subdev, &ordered_sd_list); + return __msm_sd_register_subdev(&msm_subdev->sd); +} + +int msm_sd_unregister(struct msm_sd_subdev *msm_subdev) +{ + if (WARN_ON(!msm_subdev)) + return -EINVAL; + + v4l2_device_unregister_subdev(&msm_subdev->sd); + return 0; +} + +int msm_cam_get_module_init_status(void) +{ + int rc; + pr_warn("msm_cam_get_module_init_status : start\n"); + if (module_init_status == 1) + return 0; + while (1) { + rc = wait_event_interruptible(cam_dummy_queue.state_wait, + (module_init_status == 1)); + if (rc == -ETIMEDOUT) + continue; + else if (rc == 0) + break; + } + pr_err("msm_cam_get_module_init_status : end %d\n", rc); + return 0; +} + +int msm_create_session(unsigned int session_id, struct video_device *vdev) +{ + struct msm_session *session = NULL; + + if (!msm_session_q) { + pr_err("%s : session queue not available Line %d\n", + __func__, __LINE__); + return -ENODEV; + } + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (session) { + pr_err("%s : Session not found Line %d\n", + __func__, __LINE__); + return -EINVAL; + } + + session = kzalloc(sizeof(*session), GFP_KERNEL); + if (!session) { + pr_err("%s : Memory not available Line %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + session->session_id = session_id; + session->event_q.vdev = vdev; + msm_init_queue(&session->command_ack_q); + msm_init_queue(&session->stream_q); + msm_enqueue(msm_session_q, &session->list); + mutex_init(&session->lock); + mutex_init(&session->lock_q); + return 0; +} + +int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id) +{ + struct msm_session *session; + struct msm_command_ack *cmd_ack; + + if (!msm_session_q) { + pr_err("%s : Session queue not available Line %d\n", + __func__, __LINE__); + return -ENODEV; + } + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) { + pr_err("%s : Session not found Line %d\n", + __func__, __LINE__); + return -EINVAL; + } + mutex_lock(&session->lock); + cmd_ack = kzalloc(sizeof(*cmd_ack), GFP_KERNEL); + if (!cmd_ack) { + mutex_unlock(&session->lock); + pr_err("%s : memory not available Line %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + msm_init_queue(&cmd_ack->command_q); + INIT_LIST_HEAD(&cmd_ack->list); + init_completion(&cmd_ack->wait_complete); + cmd_ack->stream_id = stream_id; + + msm_enqueue(&session->command_ack_q, &cmd_ack->list); + session->command_ack_q.len++; + mutex_unlock(&session->lock); + return 0; +} + +void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id) +{ + struct msm_session *session; + struct msm_command_ack *cmd_ack; + unsigned long flags; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return; + mutex_lock(&session->lock); + + cmd_ack = msm_queue_find(&session->command_ack_q, + struct msm_command_ack, list, __msm_queue_find_command_ack_q, + &stream_id); + if (!cmd_ack) { + mutex_unlock(&session->lock); + return; + } + + msm_queue_drain(&cmd_ack->command_q, struct msm_command, list); + + spin_lock_irqsave(&(session->command_ack_q.lock), flags); + list_del_init(&cmd_ack->list); + kzfree(cmd_ack); + session->command_ack_q.len--; + spin_unlock_irqrestore(&(session->command_ack_q.lock), flags); + mutex_unlock(&session->lock); +} + +static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd, + struct msm_sd_close_ioctl *sd_close) +{ + struct v4l2_subdev *sd; + sd = &msm_sd->sd; + pr_debug("%s: Shutting down subdev %s", __func__, sd->name); + + v4l2_subdev_call(sd, core, ioctl, MSM_SD_SHUTDOWN, sd_close); + v4l2_subdev_call(sd, core, s_power, 0); + + return 0; +} + +static inline int __msm_destroy_session_streams(void *d1, void *d2) +{ + struct msm_stream *stream = d1; + pr_err("%s: Error: Destroyed list is not empty\n", __func__); + INIT_LIST_HEAD(&stream->queued_list); + return 0; +} + +static void msm_destroy_session_streams(struct msm_session *session) +{ + + if (!session) + return; + + msm_queue_traverse_action(&session->stream_q, struct msm_stream, list, + __msm_destroy_session_streams, NULL); + + msm_queue_drain(&session->stream_q, struct msm_stream, list); +} + +static inline int __msm_remove_session_cmd_ack_q(void *d1, void *d2) +{ + struct msm_command_ack *cmd_ack = d1; + + if (!(&cmd_ack->command_q)) + return 0; + + msm_queue_drain(&cmd_ack->command_q, struct msm_command, list); + + return 0; +} + +static void msm_remove_session_cmd_ack_q(struct msm_session *session) +{ + if ((!session) || !(&session->command_ack_q)) + return; + + mutex_lock(&session->lock); + /* to ensure error handling purpose, it needs to detach all subdevs + * which are being connected to streams */ + msm_queue_traverse_action(&session->command_ack_q, + struct msm_command_ack, list, + __msm_remove_session_cmd_ack_q, NULL); + + msm_queue_drain(&session->command_ack_q, struct msm_command_ack, list); + + mutex_unlock(&session->lock); +} + +int msm_destroy_session(unsigned int session_id) +{ + struct msm_session *session; + struct v4l2_subdev *buf_mgr_subdev; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return -EINVAL; + + msm_destroy_session_streams(session); + msm_remove_session_cmd_ack_q(session); + mutex_destroy(&session->lock); + mutex_destroy(&session->lock_q); + msm_delete_entry(msm_session_q, struct msm_session, + list, session); + buf_mgr_subdev = msm_buf_mngr_get_subdev(); + if (buf_mgr_subdev) { + v4l2_subdev_call(buf_mgr_subdev, core, ioctl, + MSM_SD_SHUTDOWN, NULL); + } else { + pr_err("%s: Buff manger device node is NULL\n", __func__); + } + + return 0; +} + +static int __msm_close_destry_session_notify_apps(void *d1, void *d2) +{ + struct v4l2_event event; + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event.u.data[0]; + struct msm_session *session = d1; + + event.type = MSM_CAMERA_V4L2_EVENT_TYPE; + event.id = MSM_CAMERA_MSM_NOTIFY; + event_data->command = MSM_CAMERA_PRIV_SHUTDOWN; + + v4l2_event_queue(session->event_q.vdev, &event); + + return 0; +} + +static long msm_private_ioctl(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + int rc = 0; + struct msm_v4l2_event_data *event_data = arg; + struct v4l2_event event; + struct msm_session *session; + unsigned int session_id; + unsigned int stream_id; + unsigned long spin_flags = 0; + + if (cmd == MSM_CAM_V4L2_IOCTL_NOTIFY_MODULE_STATUS) { + module_init_status = *(int *) arg; + if (module_init_status) + wake_up(&cam_dummy_queue.state_wait); + return rc; + } + + session_id = event_data->session_id; + stream_id = event_data->stream_id; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + + if (!session) + return -EINVAL; + + switch (cmd) { + case MSM_CAM_V4L2_IOCTL_NOTIFY: { + if (WARN_ON(!session->event_q.vdev)) { + rc = -EFAULT; + break; + } + event.type = event_data->v4l2_event_type; + event.id = event_data->v4l2_event_id; + memcpy(&event.u.data, event_data, + sizeof(struct msm_v4l2_event_data)); + v4l2_event_queue(session->event_q.vdev, + &event); + } + break; + + case MSM_CAM_V4L2_IOCTL_CMD_ACK: { + struct msm_command_ack *cmd_ack; + struct msm_command *ret_cmd; + + ret_cmd = kzalloc(sizeof(*ret_cmd), GFP_KERNEL); + if (!ret_cmd) { + rc = -ENOMEM; + break; + } + + cmd_ack = msm_queue_find(&session->command_ack_q, + struct msm_command_ack, list, + __msm_queue_find_command_ack_q, + &stream_id); + if (WARN_ON(!cmd_ack)) { + kzfree(ret_cmd); + rc = -EFAULT; + break; + } + + spin_lock_irqsave(&(session->command_ack_q.lock), + spin_flags); + event.type = event_data->v4l2_event_type; + event.id = event_data->v4l2_event_id; + memcpy(&event.u.data, event_data, + sizeof(struct msm_v4l2_event_data)); + memcpy(&ret_cmd->event, &event, sizeof(struct v4l2_event)); + msm_enqueue(&cmd_ack->command_q, &ret_cmd->list); + complete(&cmd_ack->wait_complete); + spin_unlock_irqrestore(&(session->command_ack_q.lock), + spin_flags); + } + break; + + case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR: + /* send v4l2_event to HAL next*/ + msm_queue_traverse_action(msm_session_q, + struct msm_session, list, + __msm_close_destry_session_notify_apps, NULL); + break; + + default: + rc = -ENOTTY; + break; + } + + return rc; +} + +static int msm_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static int msm_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, 5, NULL); +} + +static const struct v4l2_ioctl_ops g_msm_ioctl_ops = { + .vidioc_subscribe_event = msm_subscribe_event, + .vidioc_unsubscribe_event = msm_unsubscribe_event, + .vidioc_default = msm_private_ioctl, +}; + +static unsigned int msm_poll(struct file *f, + struct poll_table_struct *pll_table) +{ + int rc = 0; + struct v4l2_fh *eventq = f->private_data; + + BUG_ON(!eventq); + + poll_wait(f, &eventq->wait, pll_table); + + if (v4l2_event_pending(eventq)) + rc = POLLIN | POLLRDNORM; + + return rc; +} + +static void msm_print_event_error(struct v4l2_event *event) +{ + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + + pr_err("Evt_type=%x Evt_id=%d Evt_cmd=%x\n", event->type, + event->id, event_data->command); + pr_err("Evt_session_id=%d Evt_stream_id=%d Evt_arg=%d\n", + event_data->session_id, event_data->stream_id, + event_data->arg_value); +} + +/* something seriously wrong if msm_close is triggered + * !!! user space imaging server is shutdown !!! + */ +int msm_post_event(struct v4l2_event *event, int timeout) +{ + int rc = 0; + struct video_device *vdev; + struct msm_session *session; + struct msm_v4l2_event_data *event_data = + (struct msm_v4l2_event_data *)&event->u.data[0]; + struct msm_command_ack *cmd_ack; + struct msm_command *cmd; + int session_id, stream_id; + unsigned long flags = 0; + + session_id = event_data->session_id; + stream_id = event_data->stream_id; + + spin_lock_irqsave(&msm_eventq_lock, flags); + if (!msm_eventq) { + spin_unlock_irqrestore(&msm_eventq_lock, flags); + pr_err("%s : msm event queue not available Line %d\n", + __func__, __LINE__); + return -ENODEV; + } + spin_unlock_irqrestore(&msm_eventq_lock, flags); + + vdev = msm_eventq->vdev; + + /* send to imaging server and wait for ACK */ + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (WARN_ON(!session)) { + pr_err("%s : session not found Line %d\n", + __func__, __LINE__); + return -EIO; + } + mutex_lock(&session->lock); + cmd_ack = msm_queue_find(&session->command_ack_q, + struct msm_command_ack, list, + __msm_queue_find_command_ack_q, &stream_id); + if (WARN_ON(!cmd_ack)) { + mutex_unlock(&session->lock); + pr_err("%s : cmd_ack not found Line %d\n", + __func__, __LINE__); + return -EIO; + } + + /*re-init wait_complete */ + INIT_COMPLETION(cmd_ack->wait_complete); + + v4l2_event_queue(vdev, event); + + if (timeout < 0) { + mutex_unlock(&session->lock); + pr_err("%s : timeout cannot be negative Line %d\n", + __func__, __LINE__); + return rc; + } + + /* should wait on session based condition */ + rc = wait_for_completion_timeout(&cmd_ack->wait_complete, + msecs_to_jiffies(timeout)); + + + if (list_empty_careful(&cmd_ack->command_q.list)) { + if (!rc) { + pr_err("%s: Timed out\n", __func__); + msm_print_event_error(event); + rc = -ETIMEDOUT; + } else { + pr_err("%s: Error: No timeout but list empty!", + __func__); + msm_print_event_error(event); + mutex_unlock(&session->lock); + return -EINVAL; + } + } + + cmd = msm_dequeue(&cmd_ack->command_q, + struct msm_command, list); + if (!cmd) { + mutex_unlock(&session->lock); + pr_err("%s : cmd dequeue failed Line %d\n", + __func__, __LINE__); + return -EINVAL; + } + + event_data = (struct msm_v4l2_event_data *)cmd->event.u.data; + + /* compare cmd_ret and event */ + if (WARN_ON(event->type != cmd->event.type) || + WARN_ON(event->id != cmd->event.id)) { + pr_err("%s : Either event type or id didnot match Line %d\n", + __func__, __LINE__); + pr_err("%s : event->type %d event->id %d\n", __func__, + event->type, event->id); + pr_err("%s : cmd->event.type %d cmd->event.id %d\n", __func__, + cmd->event.type, cmd->event.id); + rc = -EINVAL; + } + + *event = cmd->event; + + kzfree(cmd); + mutex_unlock(&session->lock); + return rc; +} + +static int msm_close(struct file *filep) +{ + int rc = 0; + unsigned long flags; + struct msm_video_device *pvdev = video_drvdata(filep); + struct msm_sd_close_ioctl sd_close; + struct msm_sd_subdev *msm_sd; + + /*stop all hardware blocks immediately*/ + if (!list_empty(&msm_v4l2_dev->subdevs)) + list_for_each_entry(msm_sd, &ordered_sd_list, list) + __msm_sd_close_subdevs(msm_sd, &sd_close); + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) + /* remove msm_v4l2_pm_qos_request */ + msm_pm_qos_remove_request(); +#endif + + /* send v4l2_event to HAL next*/ + msm_queue_traverse_action(msm_session_q, struct msm_session, list, + __msm_close_destry_session_notify_apps, NULL); + + spin_lock_irqsave(&msm_eventq_lock, flags); + msm_eventq = NULL; + spin_unlock_irqrestore(&msm_eventq_lock, flags); + v4l2_fh_release(filep); + + spin_lock_irqsave(&msm_pid_lock, flags); + put_pid(msm_pid); + msm_pid = NULL; + spin_unlock_irqrestore(&msm_pid_lock, flags); + + atomic_set(&pvdev->opened, 0); + + return rc; +} + +static inline void msm_list_switch(struct list_head *l1, + struct list_head *l2) +{ + l1->next = l2->next; + l2->prev = l1->prev; + l1->prev->next = l2; + l2->next->prev = l1; + l1->prev = l2; + l2->next = l1; +} + +static int msm_open(struct file *filep) +{ + int rc; + unsigned long flags; + struct msm_video_device *pvdev = video_drvdata(filep); + BUG_ON(!pvdev); + + /* !!! only ONE open is allowed !!! */ + if (atomic_read(&pvdev->opened)) + return -EBUSY; + + atomic_set(&pvdev->opened, 1); + + spin_lock_irqsave(&msm_pid_lock, flags); + msm_pid = get_pid(task_pid(current)); + spin_unlock_irqrestore(&msm_pid_lock, flags); + + /* create event queue */ + rc = v4l2_fh_open(filep); + if (rc < 0) + return rc; + + spin_lock_irqsave(&msm_eventq_lock, flags); + msm_eventq = filep->private_data; + spin_unlock_irqrestore(&msm_eventq_lock, flags); + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) + /* register msm_v4l2_pm_qos_request */ + msm_pm_qos_add_request(); +#endif + + return rc; +} + +static struct v4l2_file_operations msm_fops = { + .owner = THIS_MODULE, + .open = msm_open, + .poll = msm_poll, + .release = msm_close, + .ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif +}; + +struct msm_stream *msm_get_stream(unsigned int session_id, + unsigned int stream_id) +{ + struct msm_session *session; + struct msm_stream *stream; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return ERR_PTR(-EINVAL); + + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + + if (!stream) + return ERR_PTR(-EINVAL); + + return stream; +} + +struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, + unsigned int stream_id) +{ + struct msm_session *session; + struct msm_stream *stream; + + session = msm_queue_find(msm_session_q, struct msm_session, + list, __msm_queue_find_session, &session_id); + if (!session) + return NULL; + + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + if (!stream) + return NULL; + + return stream->vb2_q; +} + +struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q) +{ + struct msm_session *session; + struct msm_stream *stream; + unsigned long flags1; + unsigned long flags2; + spin_lock_irqsave(&msm_session_q->lock, flags1); + list_for_each_entry(session, &(msm_session_q->list), list) { + spin_lock_irqsave(&(session->stream_q.lock), flags2); + list_for_each_entry( + stream, &(session->stream_q.list), list) { + if (stream->vb2_q == q) { + spin_unlock_irqrestore + (&(session->stream_q.lock), flags2); + spin_unlock_irqrestore + (&msm_session_q->lock, flags1); + return stream; + } + } + spin_unlock_irqrestore(&(session->stream_q.lock), flags2); + } + spin_unlock_irqrestore(&msm_session_q->lock, flags1); + return NULL; +} + +static struct v4l2_subdev *msm_sd_find(const char *name) +{ + unsigned long flags; + struct v4l2_subdev *subdev = NULL; + struct v4l2_subdev *subdev_out = NULL; + + spin_lock_irqsave(&msm_v4l2_dev->lock, flags); + if (!list_empty(&msm_v4l2_dev->subdevs)) { + list_for_each_entry(subdev, &msm_v4l2_dev->subdevs, list) + if (!strcmp(name, subdev->name)) { + subdev_out = subdev; + break; + } + } + spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags); + + return subdev_out; +} + +static void msm_sd_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + int rc = 0; + struct v4l2_subdev *subdev = NULL; + + BUG_ON(!sd); + BUG_ON(!arg); + + /* Check if subdev exists before processing*/ + if (!msm_sd_find(sd->name)) + return; + + switch (notification) { + case MSM_SD_NOTIFY_GET_SD: { + struct msm_sd_req_sd *get_sd = arg; + + get_sd->subdev = msm_sd_find(get_sd->name); + /* TODO: might need to add ref count on ret_sd */ + } + break; + + case MSM_SD_NOTIFY_PUT_SD: { + struct msm_sd_req_sd *put_sd = arg; + subdev = msm_sd_find(put_sd->name); + } + break; + + case MSM_SD_NOTIFY_REQ_CB: { + struct msm_sd_req_vb2_q *req_sd = arg; + rc = msm_vb2_request_cb(req_sd); + if (rc < 0) + return; + } + break; + + default: + break; + } +} + +static int msm_probe(struct platform_device *pdev) +{ + struct msm_video_device *pvdev; + int rc = 0; + + msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev), + GFP_KERNEL); + if (WARN_ON(!msm_v4l2_dev)) { + rc = -ENOMEM; + goto probe_end; + } + + pvdev = kzalloc(sizeof(struct msm_video_device), + GFP_KERNEL); + if (WARN_ON(!pvdev)) { + rc = -ENOMEM; + goto pvdev_fail; + } + + pvdev->vdev = video_device_alloc(); + if (WARN_ON(!pvdev->vdev)) { + rc = -ENOMEM; + goto video_fail; + } + +#if defined(CONFIG_MEDIA_CONTROLLER) + msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device), + GFP_KERNEL); + if (!msm_v4l2_dev->mdev) { + rc = -ENOMEM; + goto mdev_fail; + } + strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME, + sizeof(msm_v4l2_dev->mdev->model)); + msm_v4l2_dev->mdev->dev = &(pdev->dev); + + rc = media_device_register(msm_v4l2_dev->mdev); + if (WARN_ON(rc < 0)) + goto media_fail; + + if (WARN_ON((rc == media_entity_init(&pvdev->vdev->entity, + 0, NULL, 0)) < 0)) + goto entity_fail; + + pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; + pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; +#endif + + msm_v4l2_dev->notify = msm_sd_notify; + + pvdev->vdev->v4l2_dev = msm_v4l2_dev; + + rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev); + if (WARN_ON(rc < 0)) + goto register_fail; + + strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name)); + pvdev->vdev->release = video_device_release; + pvdev->vdev->fops = &msm_fops; + pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops; + pvdev->vdev->minor = -1; + pvdev->vdev->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(pvdev->vdev, + VFL_TYPE_GRABBER, -1); + if (WARN_ON(rc < 0)) + goto v4l2_fail; + +#if defined(CONFIG_MEDIA_CONTROLLER) + /* FIXME: How to get rid of this messy? */ + pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev); +#endif + + atomic_set(&pvdev->opened, 0); + video_set_drvdata(pvdev->vdev, pvdev); + + msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL); + if (WARN_ON(!msm_session_q)) + goto v4l2_fail; + + msm_init_queue(msm_session_q); + spin_lock_init(&msm_eventq_lock); + spin_lock_init(&msm_pid_lock); + INIT_LIST_HEAD(&ordered_sd_list); + init_waitqueue_head(&cam_dummy_queue.state_wait); + goto probe_end; + +v4l2_fail: + v4l2_device_unregister(pvdev->vdev->v4l2_dev); +register_fail: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&pvdev->vdev->entity); +entity_fail: + media_device_unregister(msm_v4l2_dev->mdev); +media_fail: + kzfree(msm_v4l2_dev->mdev); +mdev_fail: +#endif + video_device_release(pvdev->vdev); +video_fail: + kzfree(pvdev); +pvdev_fail: + kzfree(msm_v4l2_dev); +probe_end: + return rc; +} + +static const struct of_device_id msm_dt_match[] = { + {.compatible = "qcom,msm-cam"}, + {} +} + +MODULE_DEVICE_TABLE(of, msm_dt_match); + +static struct platform_driver msm_driver = { + .probe = msm_probe, + .driver = { + .name = "msm", + .owner = THIS_MODULE, + .of_match_table = msm_dt_match, + }, +}; + +static int __init msm_init(void) +{ + return platform_driver_register(&msm_driver); +} + +static void __exit msm_exit(void) +{ + platform_driver_unregister(&msm_driver); +} + + +module_init(msm_init); +module_exit(msm_exit); +MODULE_DESCRIPTION("MSM V4L2 Camera"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/msm.h b/drivers/media/platform/msm/camera_v2_j5/msm.h new file mode 100644 index 0000000000000000000000000000000000000000..ca07c0419458ec30ace4710b111bce3bd5692d27 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm.h @@ -0,0 +1,146 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef _MSM_H +#define _MSM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include/media/msmb_camera.h" + +#if defined CONFIG_SEC_CAMERA_TUNING +#define MSM_POST_EVT_TIMEOUT 40000 +#else +#define MSM_POST_EVT_TIMEOUT 5000 +#endif + +#if defined CONFIG_SEC_CAMERA_TUNING +enum CAMERA_TUNING +{ +NORMAL_MODE, +REAR_TUNING, +FRONT_TUNING, +REAR_FRONT_TUNING +}; +#endif + +#define MSM_POST_EVT_NOTIMEOUT 0xFFFFFFFF +#define MSM_CAMERA_STREAM_CNT_BITS 32 + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) +#define CAMERA_DISABLE_PC_LATENCY 200 +#define CAMERA_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE +#endif + +struct msm_video_device { + struct video_device *vdev; + atomic_t opened; +}; + +struct msm_queue_head { + struct list_head list; + spinlock_t lock; + int len; + int max; +}; + +/** msm_event: + * + * event sent by imaging server + **/ +struct msm_event { + struct video_device *vdev; + atomic_t on_heap; +}; + +struct msm_command { + struct list_head list; + struct v4l2_event event; + atomic_t on_heap; +}; + +/** struct msm_command_ack + * + * Object of command_ack_q, which is + * created per open operation + * + * contains struct msm_command + **/ +struct msm_command_ack { + struct list_head list; + struct msm_queue_head command_q; + struct completion wait_complete; + int stream_id; +}; + +struct msm_v4l2_subdev { + /* FIXME: for session close and error handling such + * as daemon shutdown */ + int close_sequence; +}; + +struct msm_session { + struct list_head list; + + /* session index */ + unsigned int session_id; + + /* event queue sent by imaging server */ + struct msm_event event_q; + + /* ACK by imaging server. Object type of + * struct msm_command_ack per open, + * assumption is application can send + * command on every opened video node */ + struct msm_queue_head command_ack_q; + + /* real streams(either data or metadate) owned by one + * session struct msm_stream */ + struct msm_queue_head stream_q; + struct mutex lock; + struct mutex lock_q; +}; + +#if !defined(CONFIG_ARCH_MSM8939) && !defined(CONFIG_ARCH_MSM8929) +void msm_pm_qos_update_request(int val); +#endif + +int msm_cam_get_module_init_status(void); +int msm_post_event(struct v4l2_event *event, int timeout); +int msm_create_session(unsigned int session, struct video_device *vdev); +int msm_destroy_session(unsigned int session_id); + +int msm_create_stream(unsigned int session_id, + unsigned int stream_id, struct vb2_queue *q); +void msm_delete_stream(unsigned int session_id, unsigned int stream_id); +int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id); +void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id); +struct msm_stream *msm_get_stream(unsigned int session_id, + unsigned int stream_id); +struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, + unsigned int stream_id); +struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q); +struct msm_session *msm_session_find(unsigned int session_id); +#endif /*_MSM_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/Makefile b/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c5c0b9dd70a1f5e90b6accb0a6d675101839e6b1 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/Makefile @@ -0,0 +1,2 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +obj-$(CONFIG_MSMB_CAMERA) += msm_generic_buf_mgr.o diff --git a/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/msm_generic_buf_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..eb385616d75dbafa8e962cc710d51f9e071fd439 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/msm_generic_buf_mgr.c @@ -0,0 +1,352 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 "msm_generic_buf_mgr.h" + +static struct msm_buf_mngr_device *msm_buf_mngr_dev; + +struct v4l2_subdev *msm_buf_mngr_get_subdev(void) +{ + return &msm_buf_mngr_dev->subdev.sd; +} + +static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *buf_mngr_dev, + void __user *argp) +{ + unsigned long flags; + struct msm_buf_mngr_info *buf_info = + (struct msm_buf_mngr_info *)argp; + struct msm_get_bufs *new_entry = + kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL); + + if (!new_entry) { + pr_err("%s:No mem\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&new_entry->entry); + new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id, + buf_info->stream_id); + if (!new_entry->vb2_buf) { + pr_debug("%s:Get buf is null\n", __func__); + kfree(new_entry); + return -EINVAL; + } + new_entry->session_id = buf_info->session_id; + new_entry->stream_id = buf_info->stream_id; + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead); + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); + buf_info->index = new_entry->vb2_buf->v4l2_buf.index; + return 0; +} + +static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev, + struct msm_buf_mngr_info *buf_info) +{ + unsigned long flags; + struct msm_get_bufs *bufs, *save; + int32_t ret = -EINVAL; + + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { + if ((bufs->session_id == buf_info->session_id) && + (bufs->stream_id == buf_info->stream_id) && + (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) { + bufs->vb2_buf->v4l2_buf.sequence = buf_info->frame_id; + bufs->vb2_buf->v4l2_buf.timestamp = buf_info->timestamp; + bufs->vb2_buf->v4l2_buf.reserved = 0; + ret = buf_mngr_dev->vb2_ops.buf_done + (bufs->vb2_buf, + buf_info->session_id, + buf_info->stream_id); + list_del_init(&bufs->entry); + kfree(bufs); + break; + } + } + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); + return ret; +} + + +static int32_t msm_buf_mngr_put_buf(struct msm_buf_mngr_device *buf_mngr_dev, + struct msm_buf_mngr_info *buf_info) +{ + unsigned long flags; + struct msm_get_bufs *bufs, *save; + int32_t ret = -EINVAL; + + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) { + if ((bufs->session_id == buf_info->session_id) && + (bufs->stream_id == buf_info->stream_id) && + (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) { + ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf, + buf_info->session_id, buf_info->stream_id); + list_del_init(&bufs->entry); + kfree(bufs); + break; + } + } + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); + return ret; +} + +static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev) +{ + unsigned long flags; + struct msm_get_bufs *bufs, *save; + + spin_lock_irqsave(&buf_mngr_dev->buf_q_spinlock, flags); + if (!list_empty(&buf_mngr_dev->buf_qhead)) { + list_for_each_entry_safe(bufs, + save, &buf_mngr_dev->buf_qhead, entry) { + pr_err("%s: Error delete invalid bufs =%x, ses_id=%d, str_id=%d, idx=%d\n", + __func__, (unsigned int)bufs, bufs->session_id, + bufs->stream_id, bufs->vb2_buf->v4l2_buf.index); + list_del_init(&bufs->entry); + kfree(bufs); + } + } + spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags); +} + +static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); + if (!buf_mngr_dev) { + pr_err("%s buf manager device NULL\n", __func__); + rc = -ENODEV; + return rc; + } + return rc; +} + +static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); + if (!buf_mngr_dev) { + pr_err("%s buf manager device NULL\n", __func__); + rc = -ENODEV; + return rc; + } + return rc; +} + +static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd); + void __user *argp = (void __user *)arg; + + if (!buf_mngr_dev) { + pr_err("%s buf manager device NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + switch (cmd) { + case VIDIOC_MSM_BUF_MNGR_GET_BUF: + rc = msm_buf_mngr_get_buf(buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_BUF_DONE: + rc = msm_buf_mngr_buf_done(buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_PUT_BUF: + rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_INIT: + rc = msm_generic_buf_mngr_open(sd, NULL); + break; + case VIDIOC_MSM_BUF_MNGR_DEINIT: + rc = msm_generic_buf_mngr_close(sd, NULL); + break; + case MSM_SD_SHUTDOWN: + msm_buf_mngr_sd_shutdown(buf_mngr_dev); + break; + default: + return -ENOIOCTLCMD; + } + return rc; +} + +#ifdef CONFIG_COMPAT +static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + int32_t rc = 0; + + void __user *up = compat_ptr(arg); + + struct msm_buf_mngr_info32_t *buf_info32 = NULL; + struct msm_buf_mngr_info *buf_info; + + if (copy_from_user(buf_info32, (void __user *)up, + sizeof(struct msm_buf_mngr_info32_t))) + return -EFAULT; + + buf_info->session_id = buf_info32->session_id; + buf_info->stream_id = buf_info32->stream_id; + buf_info->frame_id = buf_info32->frame_id; + buf_info->index = buf_info32->index; + buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec; + buf_info->timestamp.tv_usec = (long) buf_info32->timestamp.tv_usec; + + /* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's + * except VIDIOC_MSM_CPP_CFG32, which needs special + * processing + */ + switch (cmd) { + case VIDIOC_MSM_BUF_MNGR_GET_BUF32: + cmd = VIDIOC_MSM_BUF_MNGR_GET_BUF; + break; + case VIDIOC_MSM_BUF_MNGR_BUF_DONE32: + cmd = VIDIOC_MSM_BUF_MNGR_BUF_DONE; + break; + case VIDIOC_MSM_BUF_MNGR_PUT_BUF32: + cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF; + break; + default: + pr_debug("%s : unsupported compat type", __func__); + break; + } + + switch (cmd) { + case VIDIOC_MSM_BUF_MNGR_GET_BUF: + case VIDIOC_MSM_BUF_MNGR_BUF_DONE: + case VIDIOC_MSM_BUF_MNGR_PUT_BUF: + rc = v4l2_subdev_call(sd, core, ioctl, cmd, buf_info); + break; + default: + pr_debug("%s : unsupported compat type", __func__); + break; + } + + buf_info32->session_id = buf_info->session_id; + buf_info32->stream_id = buf_info->stream_id; + buf_info32->index = buf_info->index; + buf_info32->timestamp.tv_sec = (int32_t) buf_info->timestamp.tv_sec; + buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp.tv_usec; + + if (copy_to_user((void __user *)up, buf_info32, + sizeof(struct msm_buf_mngr_info32_t))) + return -EFAULT; + + return 0; +} +#endif + +static struct v4l2_subdev_core_ops msm_buf_mngr_subdev_core_ops = { + .ioctl = msm_buf_mngr_subdev_ioctl, +}; + +static const struct v4l2_subdev_internal_ops + msm_generic_buf_mngr_subdev_internal_ops = { + .open = msm_generic_buf_mngr_open, + .close = msm_generic_buf_mngr_close, +}; + +static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = { + .core = &msm_buf_mngr_subdev_core_ops, +}; + +static const struct of_device_id msm_buf_mngr_dt_match[] = { + {.compatible = "qcom,msm_buf_mngr"}, + {} +}; + +static struct v4l2_file_operations msm_buf_v4l2_subdev_fops; + +static long msm_bmgr_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); +} + + +static long msm_buf_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_bmgr_subdev_do_ioctl); +} + +static int32_t __init msm_buf_mngr_init(void) +{ + int32_t rc = 0; + msm_buf_mngr_dev = kzalloc(sizeof(*msm_buf_mngr_dev), + GFP_KERNEL); + if (WARN_ON(!msm_buf_mngr_dev)) { + pr_err("%s: not enough memory", __func__); + return -ENOMEM; + } + /* Sub-dev */ + v4l2_subdev_init(&msm_buf_mngr_dev->subdev.sd, + &msm_buf_mngr_subdev_ops); + + msm_buf_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_buf_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_buf_v4l2_subdev_fops.unlocked_ioctl = msm_buf_subdev_fops_ioctl; + msm_buf_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_buf_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + +#ifdef CONFIG_COMPAT + msm_buf_v4l2_subdev_fops.compat_ioctl32 = + msm_bmgr_subdev_fops_compat_ioctl; +#endif + snprintf(msm_buf_mngr_dev->subdev.sd.name, + ARRAY_SIZE(msm_buf_mngr_dev->subdev.sd.name), "msm_buf_mngr"); + msm_buf_mngr_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_set_subdevdata(&msm_buf_mngr_dev->subdev.sd, msm_buf_mngr_dev); + + media_entity_init(&msm_buf_mngr_dev->subdev.sd.entity, 0, NULL, 0); + msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + msm_buf_mngr_dev->subdev.sd.entity.group_id = + MSM_CAMERA_SUBDEV_BUF_MNGR; + msm_buf_mngr_dev->subdev.sd.internal_ops = + &msm_generic_buf_mngr_subdev_internal_ops; + msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY; + rc = msm_sd_register(&msm_buf_mngr_dev->subdev); + if (rc != 0) { + pr_err("%s: msm_sd_register error = %d\n", __func__, rc); + goto end; + } + + msm_buf_mngr_dev->subdev.sd.devnode->fops = &msm_buf_v4l2_subdev_fops; + + v4l2_subdev_notify(&msm_buf_mngr_dev->subdev.sd, MSM_SD_NOTIFY_REQ_CB, + &msm_buf_mngr_dev->vb2_ops); + + INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead); + spin_lock_init(&msm_buf_mngr_dev->buf_q_spinlock); +end: + return rc; +} + +static void __exit msm_buf_mngr_exit(void) +{ + kfree(msm_buf_mngr_dev); +} + +module_init(msm_buf_mngr_init); +module_exit(msm_buf_mngr_exit); +MODULE_DESCRIPTION("MSM Buffer Manager"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/msm_generic_buf_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..754c8a078960c81f27dc80af55e1e1d621d1fed8 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm_buf_mgr/msm_generic_buf_mgr.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_BUF_GENERIC_MNGR_H__ +#define __MSM_BUF_GENERIC_MNGR_H__ + +#include +#include +#include +#include +#include +#include "../include/media/msmb_camera.h" +#include + +#include "msm.h" +#include "msm_sd.h" + +struct msm_get_bufs { + struct list_head entry; + struct vb2_buffer *vb2_buf; + uint32_t session_id; + uint32_t stream_id; +}; + +struct msm_buf_mngr_device { + struct list_head buf_qhead; + spinlock_t buf_q_spinlock; + struct msm_sd_subdev subdev; + struct msm_sd_req_vb2_q vb2_ops; +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/msm_sd.h b/drivers/media/platform/msm/camera_v2_j5/msm_sd.h new file mode 100644 index 0000000000000000000000000000000000000000..9ab74f4a6ce136df5a5e31db58b162303a54dc65 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm_sd.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef _MSM_SD_H +#define _MSM_SD_H + +#include +#include "include/media/msmb_camera.h" + +/* NOTE: this header file should ONLY be included by subdev drivers */ + +struct msm_sd_close_ioctl { + unsigned int session; + unsigned int stream; +}; + +#define MSM_SD_CLOSE_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 26, struct msm_sd_close_ioctl) + +#define MSM_SD_CLOSE_SESSION \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 27, struct msm_sd_close_ioctl) + +#define MSM_SD_CLOSE_SESSION_AND_STREAM \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 28, struct msm_sd_close_ioctl) + +#define MSM_SD_SHUTDOWN \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 29, struct msm_sd_close_ioctl) + +/* + * This is used to install Sequence in msm_sd_register. + * During msm_close, proper close sequence will be triggered. + * For example: + * + * close_sequence = 0x00100001 (ISP) + * close_sequence = 0x00100002 (ISP) + * close_sequence = 0x00100003 (ISP) + * close_sequence = 0x00200001 (sensor) + * close_sequence = 0x00200002 (sensor) + * close_sequence = 0x00200003 (sensor) + */ +#define MSM_SD_CLOSE_1ST_CATEGORY 0x00010000 +#define MSM_SD_CLOSE_2ND_CATEGORY 0x00020000 +#define MSM_SD_CLOSE_3RD_CATEGORY 0x00030000 +#define MSM_SD_CLOSE_4TH_CATEGORY 0x00040000 + +struct msm_sd_subdev { + struct v4l2_subdev sd; + int close_seq; + struct list_head list; +}; + +struct msm_sd_req_sd { + char *name; + struct v4l2_subdev *subdev; +}; + +struct msm_sd_req_vb2_q { + struct vb2_buffer *(*get_buf)(int session_id, unsigned int stream_id); + struct vb2_queue *(*get_vb2_queue)(int session_id, + unsigned int stream_id); + int (*put_buf)(struct vb2_buffer *vb2_buf, int session_id, + unsigned int stream_id); + int (*buf_done)(struct vb2_buffer *vb2_buf, int session_id, + unsigned int stream_id); +}; + +#define MSM_SD_NOTIFY_GET_SD 0x00000001 +#define MSM_SD_NOTIFY_PUT_SD 0x00000002 +#define MSM_SD_NOTIFY_REQ_CB 0x00000003 + +int msm_sd_register(struct msm_sd_subdev *msm_subdev); +int msm_sd_unregister(struct msm_sd_subdev *sd); +struct v4l2_subdev *msm_sd_get_subdev(struct v4l2_subdev *sd, + const char *get_name); +void msm_sd_put_subdev(struct v4l2_subdev *sd, struct v4l2_subdev *put); + +#endif /*_MSM_SD_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/msm_vb2/Makefile b/drivers/media/platform/msm/camera_v2_j5/msm_vb2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d79fd4ac82bd0d01a044b7e8abdae5f89ce16077 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm_vb2/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/msm_vb2 +obj-$(CONFIG_MSMB_CAMERA) += msm_vb2.o diff --git a/drivers/media/platform/msm/camera_v2_j5/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2_j5/msm_vb2/msm_vb2.c new file mode 100644 index 0000000000000000000000000000000000000000..6e9336a20d293337e0ef169599bc47ccd2d51aef --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm_vb2/msm_vb2.c @@ -0,0 +1,311 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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 "msm_vb2.h" + +static int msm_vb2_queue_setup(struct vb2_queue *q, + const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + int i; + struct msm_v4l2_format_data *data = q->drv_priv; + + if (!data) { + pr_err("%s: drv_priv NULL\n", __func__); + return -EINVAL; + } + if (data->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (WARN_ON(data->num_planes > VIDEO_MAX_PLANES)) + return -EINVAL; + + *num_planes = data->num_planes; + + for (i = 0; i < data->num_planes; i++) + sizes[i] = data->plane_sizes[i]; + } else { + pr_err("%s: Unsupported buf type :%d\n", __func__, + data->type); + return -EINVAL; + } + return 0; +} + +int msm_vb2_buf_init(struct vb2_buffer *vb) +{ + struct msm_stream *stream; + struct msm_vb2_buffer *msm_vb2_buf; + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s: Couldn't find stream\n", __func__); + return -EINVAL; + } + msm_vb2_buf = container_of(vb, struct msm_vb2_buffer, vb2_buf); + msm_vb2_buf->in_freeq = 0; + + return 0; +} + +static void msm_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + unsigned long flags; + + msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); + + if (!msm_vb2) { + pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); + return; + } + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s:%d] NULL stream", __func__, __LINE__); + return; + } + + spin_lock_irqsave(&stream->stream_lock, flags); + list_add_tail(&msm_vb2->list, &stream->queued_list); + spin_unlock_irqrestore(&stream->stream_lock, flags); +} + +static int msm_vb2_buf_finish(struct vb2_buffer *vb) +{ + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + unsigned long flags; + struct msm_vb2_buffer *msm_vb2_entry, *temp; + + msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); + + if (!msm_vb2) { + pr_err("%s:%d] vb2_buf NULL", __func__, __LINE__); + return -EINVAL; + } + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s:%d] NULL stream", __func__, __LINE__); + return -EINVAL; + } + + spin_lock_irqsave(&stream->stream_lock, flags); + list_for_each_entry_safe(msm_vb2_entry, temp, &(stream->queued_list), + list) { + if (msm_vb2_entry == msm_vb2) { + list_del_init(&msm_vb2_entry->list); + break; + } + } + spin_unlock_irqrestore(&stream->stream_lock, flags); + return 0; +} + +static void msm_vb2_buf_cleanup(struct vb2_buffer *vb) +{ + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + unsigned long flags; + + msm_vb2 = container_of(vb, struct msm_vb2_buffer, vb2_buf); + + if (!msm_vb2) { + pr_err("%s:%d] vb2 NULL", __func__, __LINE__); + return; + } + + stream = msm_get_stream_from_vb2q(vb->vb2_queue); + if (!stream) { + pr_err("%s:%d] NULL stream", __func__, __LINE__); + return; + } + + spin_lock_irqsave(&stream->stream_lock, flags); + INIT_LIST_HEAD(&stream->queued_list); + spin_unlock_irqrestore(&stream->stream_lock, flags); +} + +static struct vb2_ops msm_vb2_get_q_op = { + .queue_setup = msm_vb2_queue_setup, + .buf_init = msm_vb2_buf_init, + .buf_queue = msm_vb2_buf_queue, + .buf_cleanup = msm_vb2_buf_cleanup, + .buf_finish = msm_vb2_buf_finish, +}; + + +struct vb2_ops *msm_vb2_get_q_ops(void) +{ + return &msm_vb2_get_q_op; +} + +static void *msm_vb2_dma_contig_get_userptr(void *alloc_ctx, + unsigned long vaddr, unsigned long size, int write) +{ + struct msm_vb2_private_data *priv; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + priv->vaddr = (void *)vaddr; + priv->size = size; + priv->alloc_ctx = alloc_ctx; + return priv; +} + +static void msm_vb2_dma_contig_put_userptr(void *buf_priv) +{ + kzfree(buf_priv); +} + +static struct vb2_mem_ops msm_vb2_get_q_mem_op = { + .get_userptr = msm_vb2_dma_contig_get_userptr, + .put_userptr = msm_vb2_dma_contig_put_userptr, +}; + +struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void) +{ + return &msm_vb2_get_q_mem_op; +} + +static struct vb2_queue *msm_vb2_get_queue(int session_id, + unsigned int stream_id) +{ + return msm_get_stream_vb2q(session_id, stream_id); +} + +static struct vb2_buffer *msm_vb2_get_buf(int session_id, + unsigned int stream_id) +{ + struct msm_stream *stream; + struct vb2_buffer *vb2_buf = NULL; + struct msm_vb2_buffer *msm_vb2 = NULL; + unsigned long flags; + + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return NULL; + + spin_lock_irqsave(&stream->stream_lock, flags); + + if (!stream->vb2_q) { + pr_err("%s: stream q not available\n", __func__); + goto end; + } + + list_for_each_entry(msm_vb2, &(stream->queued_list), list) { + vb2_buf = &(msm_vb2->vb2_buf); + if (vb2_buf->state != VB2_BUF_STATE_ACTIVE) + continue; + + if (msm_vb2->in_freeq) + continue; + + msm_vb2->in_freeq = 1; + goto end; + } + msm_vb2 = NULL; + vb2_buf = NULL; +end: + spin_unlock_irqrestore(&stream->stream_lock, flags); + return vb2_buf; +} + +static int msm_vb2_put_buf(struct vb2_buffer *vb, int session_id, + unsigned int stream_id) +{ + struct msm_stream *stream; + struct msm_vb2_buffer *msm_vb2; + int rc = 0; + unsigned long flags; + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return -EINVAL; + + spin_lock_irqsave(&stream->stream_lock, flags); + if (vb) { + msm_vb2 = + container_of(vb, struct msm_vb2_buffer, vb2_buf); + if (msm_vb2->in_freeq) { + msm_vb2->in_freeq = 0; + rc = 0; + } else + rc = -EINVAL; + } else { + pr_err("%s: VB buffer is null\n", __func__); + rc = -EINVAL; + } + spin_unlock_irqrestore(&stream->stream_lock, flags); + return rc; +} + +static int msm_vb2_buf_done(struct vb2_buffer *vb, int session_id, + unsigned int stream_id) +{ + unsigned long flags; + struct msm_vb2_buffer *msm_vb2; + struct msm_stream *stream; + struct vb2_buffer *vb2_buf = NULL; + int rc = 0; + + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return 0; + spin_lock_irqsave(&stream->stream_lock, flags); + if (vb) { + list_for_each_entry(msm_vb2, &(stream->queued_list), list) { + vb2_buf = &(msm_vb2->vb2_buf); + if (vb2_buf == vb) + break; + } + if (vb2_buf != vb) { + pr_err("%s:%d VB buffer is INVALID vb=%x, ses_id=%d, str_id=%d\n", + __func__, __LINE__, (unsigned int)vb, + session_id, stream_id); + rc = -EINVAL; + goto out; + } + msm_vb2 = + container_of(vb, struct msm_vb2_buffer, vb2_buf); + /* put buf before buf done */ + if (msm_vb2->in_freeq) { + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + msm_vb2->in_freeq = 0; + rc = 0; + } else + rc = -EINVAL; + } else { + pr_err("%s:%d VB buffer is NULL for ses_id=%d, str_id=%d\n", + __func__, __LINE__, session_id, stream_id); + rc = -EINVAL; + } +out: + spin_unlock_irqrestore(&stream->stream_lock, flags); + return rc; +} + +int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req) +{ + if (!req) { + pr_err("%s: suddev is null\n", __func__); + return -EINVAL; + } + + req->get_buf = msm_vb2_get_buf; + req->get_vb2_queue = msm_vb2_get_queue; + req->put_buf = msm_vb2_put_buf; + req->buf_done = msm_vb2_buf_done; + + return 0; +} + diff --git a/drivers/media/platform/msm/camera_v2_j5/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2_j5/msm_vb2/msm_vb2.h new file mode 100644 index 0000000000000000000000000000000000000000..e4b7c670a8d122695fad4b725dac32ccba52333a --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/msm_vb2/msm_vb2.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef _MSM_VB_H +#define _MSM_VB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/media/msmb_camera.h" +#include +#include "msm.h" +#include "msm_sd.h" + +struct msm_vb2_buffer { + /* + * vb2 buffer has to be first in the structure + * because both v4l2 frameworks and driver directly + * cast msm_vb2_buffer to a vb2_buf. + */ + struct vb2_buffer vb2_buf; + struct list_head list; + int in_freeq; +}; + +struct msm_vb2_private_data { + void *vaddr; + unsigned long size; + /* Offset of the plane inside the buffer */ + void *alloc_ctx; +}; + +struct msm_stream { + struct list_head list; + + /* stream index per session, same + * as stream_id but set through s_parm */ + unsigned int stream_id; + /* vb2 buffer handling */ + struct vb2_queue *vb2_q; + spinlock_t stream_lock; + struct list_head queued_list; +}; + +struct vb2_ops *msm_vb2_get_q_ops(void); +struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void); +int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd); + +#endif /*_MSM_VB_H */ diff --git a/drivers/media/platform/msm/camera_v2_j5/pproc/Makefile b/drivers/media/platform/msm/camera_v2_j5/pproc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4193adc173f731b45fb0b7abbf1e72c31bad1662 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/pproc/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MSMB_CAMERA) += cpp/ +obj-$(CONFIG_MSMB_CAMERA) += vpe/ diff --git a/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/Makefile b/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..96af8947ee6165bdec7c3833f9ddcf4a1aaa2db0 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/isp/ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSM_CPP) += msm_cpp.o diff --git a/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/msm_cpp.c new file mode 100644 index 0000000000000000000000000000000000000000..ad11991a9491d0e8820388957020a4e7e9e04ff2 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/msm_cpp.c @@ -0,0 +1,2292 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#define pr_fmt(fmt) "MSM-CPP %s:%d " fmt, __func__, __LINE__ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../include/media/msmb_camera.h" +#include +#include "../../include/media/msmb_pproc.h" +#include +#include "msm_cpp.h" +#include "msm_isp_util.h" +#include "msm_camera_io_util.h" +#include + +#define MSM_CPP_DRV_NAME "msm_cpp" + +#define MSM_CPP_MAX_BUFF_QUEUE 16 + +#define CONFIG_MSM_CPP_DBG 0 + +#define ENABLE_CPP_LOW 0 + +#define CPP_CMD_TIMEOUT_MS 300 + +#define MSM_CPP_CORE_CLK_IDX 4 +#define MSM_MICRO_IFACE_CLK_IDX 7 + +#define MSM_CPP_NOMINAL_CLOCK 266670000 +#define MSM_CPP_TURBO_CLOCK 320000000 + +#define CPP_FW_VERSION_1_2_0 0x10020000 +#define CPP_FW_VERSION_1_4_0 0x10040000 +#define CPP_FW_VERSION_1_6_0 0x10060000 + +/* stripe information offsets in frame command */ +#define STRIPE_BASE_FW_1_2_0 130 +#define STRIPE_BASE_FW_1_4_0 140 +#define STRIPE_BASE_FW_1_6_0 464 + + +/* dump the frame command before writing to the hardware */ +#define MSM_CPP_DUMP_FRM_CMD 0 + +#define CPP_CLK_INFO_MAX 16 + +static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, + uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info); + +#if CONFIG_MSM_CPP_DBG +#define CPP_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CPP_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define CPP_LOW(fmt, args...) do { \ + if (ENABLE_CPP_LOW) \ + pr_info(fmt, ##args); \ + } while (0) + +#define ERR_USER_COPY(to) pr_err("copy %s user\n", \ + ((to) ? "to" : "from")) +#define ERR_COPY_FROM_USER() ERR_USER_COPY(0) + +#define msm_dequeue(queue, member) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, member); \ + list_del_init(&qcmd->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + qcmd; \ +}) + +struct msm_cpp_timer_data_t { + struct cpp_device *cpp_dev; + struct msm_cpp_frame_info_t *processed_frame; +}; + +struct msm_cpp_timer_t { + atomic_t used; + struct msm_cpp_timer_data_t data; + struct timer_list cpp_timer; +}; + +struct msm_cpp_timer_t cpp_timer; + +static void msm_queue_init(struct msm_device_queue *queue, const char *name) +{ + CPP_DBG("E\n"); + spin_lock_init(&queue->lock); + queue->len = 0; + queue->max = 0; + queue->name = name; + INIT_LIST_HEAD(&queue->list); + init_waitqueue_head(&queue->wait); +} + +static void msm_enqueue(struct msm_device_queue *queue, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); + queue->len++; + if (queue->len > queue->max) { + queue->max = queue->len; + pr_info("queue %s new max is %d\n", queue->name, queue->max); + } + list_add_tail(entry, &queue->list); + wake_up(&queue->wait); + CPP_DBG("woke up %s\n", queue->name); + spin_unlock_irqrestore(&queue->lock, flags); +} + +#define msm_cpp_empty_list(queue, member) { \ + unsigned long flags; \ + struct msm_queue_cmd *qcmd = NULL; \ + if (queue) { \ + spin_lock_irqsave(&queue->lock, flags); \ + while (!list_empty(&queue->list)) { \ + queue->len--; \ + qcmd = list_first_entry(&queue->list, \ + struct msm_queue_cmd, member); \ + list_del_init(&qcmd->member); \ + kfree(qcmd); \ + } \ + spin_unlock_irqrestore(&queue->lock, flags); \ + } \ +} + +static struct msm_cam_clk_info cpp_clk_info[CPP_CLK_INFO_MAX]; + +static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev); +static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin); +static void cpp_timer_callback(unsigned long data); + +uint8_t induce_error; +static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev); + +static void msm_cpp_write(u32 data, void __iomem *cpp_base) +{ + writel_relaxed((data), cpp_base + MSM_CPP_MICRO_FIFO_RX_DATA); +} + +static uint32_t msm_cpp_read(void __iomem *cpp_base) +{ + uint32_t tmp, retry = 0; + do { + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT); + } while (((tmp & 0x2) == 0x0) && (retry++ < 10)) ; + if (retry < 10) { + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_DATA); + CPP_DBG("Read data: 0%x\n", tmp); + } else { + CPP_DBG("Read failed\n"); + tmp = 0xDEADBEEF; + } + + return tmp; +} + +static struct msm_cpp_buff_queue_info_t *msm_cpp_get_buff_queue_entry( + struct cpp_device *cpp_dev, uint32_t session_id, uint32_t stream_id) +{ + uint32_t i = 0; + struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if ((cpp_dev->buff_queue[i].used == 1) && + (cpp_dev->buff_queue[i].session_id == session_id) && + (cpp_dev->buff_queue[i].stream_id == stream_id)) { + buff_queue_info = &cpp_dev->buff_queue[i]; + break; + } + } + + if (buff_queue_info == NULL) { + pr_err("error buffer queue entry for sess:%d strm:%d not found\n", + session_id, stream_id); + } + return buff_queue_info; +} + +static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index, + uint8_t native_buff, int *fd) +{ + unsigned long phy_add = 0; + struct list_head *buff_head; + struct msm_cpp_buffer_map_list_t *buff, *save; + + if (native_buff) + buff_head = &buff_queue_info->native_buff_head; + else + buff_head = &buff_queue_info->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buff_index) { + phy_add = buff->map_info.phy_addr; + *fd = buff->map_info.buff_info.fd; + break; + } + } + + return phy_add; +} + +static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue, + struct msm_cpp_buffer_info_t *buffer_info) +{ + struct list_head *buff_head; + struct msm_cpp_buffer_map_list_t *buff, *save; + int rc = 0; + + if (buffer_info->native_buff) + buff_head = &buff_queue->native_buff_head; + else + buff_head = &buff_queue->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buffer_info->index) { + pr_err("error buffer index already queued\n"); + return -EINVAL; + } + } + + buff = kzalloc( + sizeof(struct msm_cpp_buffer_map_list_t), GFP_KERNEL); + if (!buff) { + pr_err("error allocating memory\n"); + return -EINVAL; + } + + buff->map_info.buff_info = *buffer_info; + buff->map_info.ion_handle = ion_import_dma_buf(cpp_dev->client, + buffer_info->fd); + if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) { + pr_err("ION import failed\n"); + goto QUEUE_BUFF_ERROR1; + } + rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle, + cpp_dev->domain_num, 0, SZ_4K, 0, + &buff->map_info.phy_addr, + &buff->map_info.len, 0, 0); + if (rc < 0) { + pr_err("ION mmap failed\n"); + goto QUEUE_BUFF_ERROR2; + } + + INIT_LIST_HEAD(&buff->entry); + list_add_tail(&buff->entry, buff_head); + + return buff->map_info.phy_addr; + +QUEUE_BUFF_ERROR2: + ion_free(cpp_dev->client, buff->map_info.ion_handle); +QUEUE_BUFF_ERROR1: + buff->map_info.ion_handle = NULL; + kzfree(buff); + + return 0; +} + +static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buffer_map_list_t *buff) +{ + + ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle, + cpp_dev->domain_num, 0); + ion_free(cpp_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + + list_del_init(&buff->entry); + kzfree(buff); + + return; +} + +static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id, + uint32_t stream_id, int *fd) +{ + unsigned long phy_addr = 0; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + uint8_t native_buff = buffer_info->native_buff; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return phy_addr; + } + + phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info, + buffer_info->index, native_buff, fd); + if ((phy_addr == 0) && (native_buff)) { + phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, + buffer_info); + *fd = buffer_info->fd; + } + return phy_addr; +} + +static int32_t msm_cpp_enqueue_buff_info_list(struct cpp_device *cpp_dev, + struct msm_cpp_stream_buff_info_t *stream_buff_info) +{ + uint32_t j; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + return -EINVAL; + } + + for (j = 0; j < stream_buff_info->num_buffs; j++) { + msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, + &stream_buff_info->buffer_info[j]); + } + return 0; +} + +static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue_info) +{ + struct msm_cpp_buffer_map_list_t *buff, *save; + struct list_head *buff_head; + + buff_head = &buff_queue_info->native_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_cpp_dequeue_buffer_info(cpp_dev, buff); + } + + buff_head = &buff_queue_info->vb2_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_cpp_dequeue_buffer_info(cpp_dev, buff); + } + + return 0; +} + +static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev, + uint16_t session_id, uint16_t stream_id) +{ + uint32_t i; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if (cpp_dev->buff_queue[i].used == 0) { + buff_queue_info = &cpp_dev->buff_queue[i]; + buff_queue_info->used = 1; + buff_queue_info->session_id = session_id; + buff_queue_info->stream_id = stream_id; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; + } + } + pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", + session_id, stream_id); + return -EINVAL; +} + +static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev, + uint32_t session_id, uint32_t stream_id) +{ + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return -EINVAL; + } + + buff_queue_info->used = 0; + buff_queue_info->session_id = 0; + buff_queue_info->stream_id = 0; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; +} + +static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev, + uint32_t num_buffq) +{ + struct msm_cpp_buff_queue_info_t *buff_queue; + buff_queue = kzalloc( + sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq, + GFP_KERNEL); + if (!buff_queue) { + pr_err("Buff queue allocation failure\n"); + return -ENOMEM; + } + + if (cpp_dev->buff_queue) { + pr_err("Buff queue not empty\n"); + kzfree(buff_queue); + return -EINVAL; + } else { + cpp_dev->buff_queue = buff_queue; + cpp_dev->num_buffq = num_buffq; + } + return 0; +} + +static void msm_cpp_delete_buff_queue(struct cpp_device *cpp_dev) +{ + uint32_t i; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if (cpp_dev->buff_queue[i].used == 1) { + pr_err("Queue not free sessionid: %d, streamid: %d\n", + cpp_dev->buff_queue[i].session_id, + cpp_dev->buff_queue[i].stream_id); + msm_cpp_dequeue_buff_info_list + (cpp_dev, &cpp_dev->buff_queue[i]); + msm_cpp_free_buff_queue_entry(cpp_dev, + cpp_dev->buff_queue[i].session_id, + cpp_dev->buff_queue[i].stream_id); + } + } + kzfree(cpp_dev->buff_queue); + cpp_dev->buff_queue = NULL; + cpp_dev->num_buffq = 0; + return; +} + +static void msm_cpp_poll(void __iomem *cpp_base, u32 val) +{ + uint32_t tmp, retry = 0; + do { + usleep_range(1000, 2000); + tmp = msm_cpp_read(cpp_base); + if (tmp != 0xDEADBEEF) + CPP_LOW("poll: 0%x\n", tmp); + } while ((tmp != val) && (retry++ < MSM_CPP_POLL_RETRIES)); + if (retry < MSM_CPP_POLL_RETRIES) + CPP_LOW("Poll finished\n"); + else + pr_err("Poll failed: expect: 0x%x\n", val); +} + +static void msm_cpp_poll_rx_empty(void __iomem *cpp_base) +{ + uint32_t tmp, retry = 0; + + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT); + while (((tmp & 0x2) != 0x0) && (retry++ < MSM_CPP_POLL_RETRIES)) { + /*Below usleep values are chosen based on experiments + and this was the smallest number which works. This + sleep is needed to leave enough time for Microcontroller + to read rx fifo.*/ + usleep_range(200, 300); + tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_RX_STAT); + } + + if (retry < MSM_CPP_POLL_RETRIES) + CPP_LOW("Poll rx empty\n"); + else + pr_err("Poll rx empty failed\n"); +} + +void cpp_release_ion_client(struct kref *ref) +{ + struct cpp_device *cpp_dev = container_of(ref, + struct cpp_device, refcount); + pr_err("Calling ion_client_destroy\n"); + ion_client_destroy(cpp_dev->client); +} + +static int cpp_init_mem(struct cpp_device *cpp_dev) +{ + int rc = 0; + + kref_init(&cpp_dev->refcount); + kref_get(&cpp_dev->refcount); + cpp_dev->client = msm_ion_client_create("cpp"); + + CPP_DBG("E\n"); + if (!cpp_dev->domain) { + pr_err("domain / iommu context not found\n"); + return -ENODEV; + } + + CPP_DBG("X\n"); + return rc; +} + +static void cpp_deinit_mem(struct cpp_device *cpp_dev) +{ + CPP_DBG("E\n"); + kref_put(&cpp_dev->refcount, cpp_release_ion_client); + CPP_DBG("X\n"); +} + +static irqreturn_t msm_cpp_irq(int irq_num, void *data) +{ + unsigned long flags; + uint32_t tx_level; + uint32_t irq_status; + uint32_t i; + uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; + struct cpp_device *cpp_dev = data; + struct msm_cpp_tasklet_queue_cmd *queue_cmd; + irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT); + CPP_DBG("status: 0x%x\n", irq_status); + if (irq_status & 0x8) { + tx_level = msm_camera_io_r(cpp_dev->base + + MSM_CPP_MICRO_FIFO_TX_STAT) >> 2; + for (i = 0; i < tx_level; i++) { + tx_fifo[i] = msm_camera_io_r(cpp_dev->base + + MSM_CPP_MICRO_FIFO_TX_DATA); + } + spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); + queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx]; + if (queue_cmd->cmd_used) { + pr_err("%s: cpp tasklet queue overflow\n", __func__); + list_del(&queue_cmd->list); + } else { + atomic_add(1, &cpp_dev->irq_cnt); + } + queue_cmd->irq_status = irq_status; + queue_cmd->tx_level = tx_level; + memset(&queue_cmd->tx_fifo[0], 0, sizeof(queue_cmd->tx_fifo)); + for (i = 0; i < tx_level; i++) + queue_cmd->tx_fifo[i] = tx_fifo[i]; + + queue_cmd->cmd_used = 1; + cpp_dev->taskletq_idx = + (cpp_dev->taskletq_idx + 1) % MSM_CPP_TASKLETQ_SIZE; + list_add_tail(&queue_cmd->list, &cpp_dev->tasklet_q); + spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); + + tasklet_schedule(&cpp_dev->cpp_tasklet); + } else if (irq_status & 0x7C0) { + pr_err("%s: fatal error: 0x%x\n", __func__, irq_status); + pr_err("%s: DEBUG_SP: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40)); + pr_err("%s: DEBUG_T: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44)); + pr_err("%s: DEBUG_N: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48)); + pr_err("%s: DEBUG_R: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C)); + pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50)); + pr_err("%s: DEBUG_MO: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54)); + pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60)); + pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64)); + pr_err("%s: DEBUG_GPI: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70)); + pr_err("%s: DEBUG_GPO: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74)); + pr_err("%s: DEBUG_T0: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80)); + pr_err("%s: DEBUG_R0: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84)); + pr_err("%s: DEBUG_T1: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88)); + pr_err("%s: DEBUG_R1: 0x%x\n", __func__, + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); + } + msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); + return IRQ_HANDLED; +} + +void msm_cpp_do_tasklet(unsigned long data) +{ + unsigned long flags; + uint32_t irq_status; + uint32_t tx_level; + uint32_t msg_id, cmd_len; + uint32_t i; + uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; + struct cpp_device *cpp_dev = (struct cpp_device *) data; + struct msm_cpp_tasklet_queue_cmd *queue_cmd; + struct msm_cpp_timer_t *timer = NULL; + + while (atomic_read(&cpp_dev->irq_cnt)) { + spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); + queue_cmd = list_first_entry(&cpp_dev->tasklet_q, + struct msm_cpp_tasklet_queue_cmd, list); + if (!queue_cmd) { + atomic_set(&cpp_dev->irq_cnt, 0); + spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); + return; + } + atomic_sub(1, &cpp_dev->irq_cnt); + list_del(&queue_cmd->list); + queue_cmd->cmd_used = 0; + irq_status = queue_cmd->irq_status; + tx_level = queue_cmd->tx_level; + for (i = 0; i < tx_level; i++) + tx_fifo[i] = queue_cmd->tx_fifo[i]; + + spin_unlock_irqrestore(&cpp_dev->tasklet_lock, flags); + + for (i = 0; i < tx_level; i++) { + if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) { + cmd_len = tx_fifo[i+1]; + msg_id = tx_fifo[i+2]; + if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) { + CPP_DBG("Frame done!!\n"); + /* delete CPP timer */ + CPP_DBG("delete timer.\n"); + timer = &cpp_timer; + atomic_set(&timer->used, 0); + del_timer(&timer->cpp_timer); + timer->data.processed_frame = NULL; + msm_cpp_notify_frame_done(cpp_dev); + } else if (msg_id == + MSM_CPP_MSG_ID_FRAME_NACK) { + pr_err("NACK error from hw!!\n"); + CPP_DBG("delete timer.\n"); + timer = &cpp_timer; + atomic_set(&timer->used, 0); + del_timer(&timer->cpp_timer); + timer->data.processed_frame = NULL; + msm_cpp_notify_frame_done(cpp_dev); + } + i += cmd_len + 2; + } + } + } +} +static void cpp_get_clk_freq_tbl(struct clk *clk, struct cpp_hw_info *hw_info) +{ + uint32_t count; + signed long freq_tbl_entry = 0; + + if ((clk == NULL) || (hw_info == NULL) || (clk->ops == NULL) || + (clk->ops->list_rate == NULL)) { + pr_err("Bad parameter\n"); + return; + } + + for (count = 0; count < MAX_FREQ_TBL; count++) { + freq_tbl_entry = clk->ops->list_rate(clk, count); + if (freq_tbl_entry >= 0) + hw_info->freq_tbl[count] = freq_tbl_entry; + else + break; + } + + hw_info->freq_tbl_count = count; +} + +static int cpp_init_hardware(struct cpp_device *cpp_dev) +{ + int rc = 0; + rc = msm_isp_init_bandwidth_mgr(ISP_CPP); + if (rc < 0) { + pr_err("%s: Bandwidth registration Failed!\n", __func__); + goto bus_scale_register_failed; + } + + if (cpp_dev->fs_cpp == NULL) { + cpp_dev->fs_cpp = + regulator_get(&cpp_dev->pdev->dev, "vdd"); + if (IS_ERR(cpp_dev->fs_cpp)) { + pr_err("Regulator cpp vdd get failed %ld\n", + PTR_ERR(cpp_dev->fs_cpp)); + cpp_dev->fs_cpp = NULL; + goto fs_failed; + } else if (regulator_enable(cpp_dev->fs_cpp)) { + pr_err("Regulator cpp vdd enable failed\n"); + regulator_put(cpp_dev->fs_cpp); + cpp_dev->fs_cpp = NULL; + goto fs_failed; + } + } + + if (cpp_dev->hw_info.cpp_hw_version != CPP_HW_VERSION_4_0_0) { + cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX] = + clk_get(&cpp_dev->pdev->dev, + cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name); + if (IS_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX])) { + pr_err("%s get failed\n", + cpp_clk_info[MSM_MICRO_IFACE_CLK_IDX].clk_name); + rc = + PTR_ERR(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + goto remap_failed; + } + + rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX], + CLK_RESET_ASSERT); + if (rc) { + pr_err("%s:micro_iface_clk assert failed\n", + __func__); + clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + goto remap_failed; + } + /*Below usleep values are chosen based on experiments + and this was the smallest number which works. This + sleep is needed to leave enough time for Microcontroller + to resets all its registers.*/ + usleep_range(10000, 12000); + + rc = clk_reset(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX], + CLK_RESET_DEASSERT); + if (rc) { + pr_err("%s:micro_iface_clk assert failed\n", __func__); + clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + goto remap_failed; + } + /*Below usleep values are chosen based on experiments and + this was the smallest number which works. This sleep is + needed to leave enough time for Microcontroller to + resets all its registers.*/ + usleep_range(1000, 1200); + + clk_put(cpp_dev->cpp_clk[MSM_MICRO_IFACE_CLK_IDX]); + } + + rc = msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, + cpp_dev->cpp_clk, cpp_dev->num_clk, 1); + if (rc < 0) { + pr_err("clk enable failed\n"); + goto clk_failed; + } + + cpp_dev->base = ioremap(cpp_dev->mem->start, + resource_size(cpp_dev->mem)); + if (!cpp_dev->base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto remap_failed; + } + + cpp_dev->vbif_base = ioremap(cpp_dev->vbif_mem->start, + resource_size(cpp_dev->vbif_mem)); + if (!cpp_dev->vbif_base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto vbif_remap_failed; + } + + cpp_dev->cpp_hw_base = ioremap(cpp_dev->cpp_hw_mem->start, + resource_size(cpp_dev->cpp_hw_mem)); + if (!cpp_dev->cpp_hw_base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto cpp_hw_remap_failed; + } + + if (cpp_dev->state != CPP_STATE_BOOT) { + rc = request_irq(cpp_dev->irq->start, msm_cpp_irq, + IRQF_TRIGGER_RISING, "cpp", cpp_dev); + if (rc < 0) { + pr_err("irq request fail\n"); + goto req_irq_fail; + } + cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); + + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_INIT, NULL); + if (rc < 0) { + pr_err("buf mngr init failed\n"); + free_irq(cpp_dev->irq->start, cpp_dev); + goto req_irq_fail; + } + } + + cpp_dev->hw_info.cpp_hw_version = + msm_camera_io_r(cpp_dev->cpp_hw_base); + pr_info("CPP HW Version: 0x%x\n", cpp_dev->hw_info.cpp_hw_version); + cpp_dev->hw_info.cpp_hw_caps = + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4); + cpp_get_clk_freq_tbl(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], + &cpp_dev->hw_info); + pr_debug("CPP HW Caps: 0x%x\n", cpp_dev->hw_info.cpp_hw_caps); + msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4); + cpp_dev->taskletq_idx = 0; + atomic_set(&cpp_dev->irq_cnt, 0); + msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE); + pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); + cpp_dev->stream_cnt = 0; + if (cpp_dev->hw_info.cpp_hw_version != CPP_HW_VERSION_4_0_0) { + if (cpp_dev->is_firmware_loaded == 1) { + disable_irq(cpp_dev->irq->start); + cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); + enable_irq(cpp_dev->irq->start); + msm_camera_io_w_mb(0x7C8, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w_mb(0xFFFF, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + } + } else { + msm_camera_io_w(0x1, + cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); + msm_camera_io_w_mb(0x7C8, + cpp_dev->base + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w_mb(0xFFFF, + cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); + } + return rc; +req_irq_fail: + iounmap(cpp_dev->cpp_hw_base); +cpp_hw_remap_failed: + iounmap(cpp_dev->vbif_base); +vbif_remap_failed: + iounmap(cpp_dev->base); +remap_failed: + msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, + cpp_dev->cpp_clk, cpp_dev->num_clk, 0); +clk_failed: + regulator_disable(cpp_dev->fs_cpp); + regulator_put(cpp_dev->fs_cpp); +fs_failed: + msm_isp_deinit_bandwidth_mgr(ISP_CPP); +bus_scale_register_failed: + return rc; +} + +static void cpp_release_hardware(struct cpp_device *cpp_dev) +{ + int32_t rc; + if (cpp_dev->state != CPP_STATE_BOOT) { + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_DEINIT, NULL); + if (rc < 0) { + pr_err("error in buf mngr deinit\n"); + rc = -EINVAL; + } + free_irq(cpp_dev->irq->start, cpp_dev); + tasklet_kill(&cpp_dev->cpp_tasklet); + atomic_set(&cpp_dev->irq_cnt, 0); + } + msm_cpp_delete_buff_queue(cpp_dev); + iounmap(cpp_dev->base); + iounmap(cpp_dev->vbif_base); + iounmap(cpp_dev->cpp_hw_base); + msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info, + cpp_dev->cpp_clk, cpp_dev->num_clk, 0); + regulator_disable(cpp_dev->fs_cpp); + regulator_put(cpp_dev->fs_cpp); + cpp_dev->fs_cpp = NULL; + if (cpp_dev->stream_cnt > 0) { + pr_err("error: stream count active\n"); + msm_isp_update_bandwidth(ISP_CPP, 0, 0); + } + cpp_dev->stream_cnt = 0; + msm_isp_deinit_bandwidth_mgr(ISP_CPP); +} + +static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) +{ + uint32_t i; + uint32_t *ptr_bin = NULL; + int32_t rc = -EFAULT; + const struct firmware *fw = NULL; + struct device *dev = &cpp_dev->pdev->dev; + + msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); + msm_camera_io_w(0x1, cpp_dev->base + + MSM_CPP_MICRO_BOOT_START); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + + if (fw_name_bin) { + pr_debug("%s: FW file: %s\n", __func__, fw_name_bin); + rc = request_firmware(&fw, fw_name_bin, dev); + if (rc) { + dev_err(dev, + "Fail to loc blob %s from dev %p, Error: %d\n", + fw_name_bin, dev, rc); + } + if (NULL != fw) + ptr_bin = (uint32_t *)fw->data; + + msm_camera_io_w(0x1, cpp_dev->base + + MSM_CPP_MICRO_BOOT_START); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + msm_camera_io_w(0xFFFFFFFF, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + + /*Start firmware loading*/ + msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base); + if (fw) + msm_cpp_write(fw->size, cpp_dev->base); + else + msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base); + msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base); + + if (ptr_bin) { + msm_cpp_poll_rx_empty(cpp_dev->base); + for (i = 0; i < fw->size/4; i++) { + msm_cpp_write(*ptr_bin, cpp_dev->base); + if (i % MSM_CPP_RX_FIFO_LEVEL == 0) + msm_cpp_poll_rx_empty(cpp_dev->base); + ptr_bin++; + } + } + if (fw) + release_firmware(fw); + msm_camera_io_w_mb(0x00, cpp_dev->cpp_hw_base + 0xC); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + } + + /*Trigger MC to jump to start address*/ + msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base); + msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base); + + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + msm_cpp_poll(cpp_dev->base, 0x1); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER); + + /*Get Bootloader Version*/ + msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base); + pr_info("MC Bootloader Version: 0x%x\n", + msm_cpp_read(cpp_dev->base)); + + /*Get Firmware Version*/ + msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base); + msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base); + msm_cpp_write(0x1, cpp_dev->base); + msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base); + msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base); + + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD); + msm_cpp_poll(cpp_dev->base, 0x2); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER); + cpp_dev->fw_version = msm_cpp_read(cpp_dev->base); + pr_info("CPP FW Version: 0x%08x\n", cpp_dev->fw_version); + msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER); + + /*Disable MC clock*/ + /*msm_camera_io_w(0x0, cpp_dev->base + + MSM_CPP_MICRO_CLKEN_CTL);*/ +} + +static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc; + uint32_t i; + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + CPP_DBG("E\n"); + + mutex_lock(&cpp_dev->mutex); + if (cpp_dev->cpp_open_cnt == MAX_ACTIVE_CPP_INSTANCE) { + pr_err("No free CPP instance\n"); + mutex_unlock(&cpp_dev->mutex); + return -ENODEV; + } + + for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { + if (cpp_dev->cpp_subscribe_list[i].active == 0) { + cpp_dev->cpp_subscribe_list[i].active = 1; + cpp_dev->cpp_subscribe_list[i].vfh = &fh->vfh; + break; + } + } + if (i == MAX_ACTIVE_CPP_INSTANCE) { + pr_err("No free instance\n"); + mutex_unlock(&cpp_dev->mutex); + return -ENODEV; + } + + CPP_DBG("open %d %p\n", i, &fh->vfh); + cpp_dev->cpp_open_cnt++; + if (cpp_dev->cpp_open_cnt == 1) { + rc = cpp_init_hardware(cpp_dev); + if (rc < 0) { + cpp_dev->cpp_open_cnt--; + cpp_dev->cpp_subscribe_list[i].active = 0; + cpp_dev->cpp_subscribe_list[i].vfh = NULL; + mutex_unlock(&cpp_dev->mutex); + return rc; + } + + iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx); + cpp_init_mem(cpp_dev); + cpp_dev->state = CPP_STATE_IDLE; + } + mutex_unlock(&cpp_dev->mutex); + return 0; +} + +static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + uint32_t i; + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + struct msm_device_queue *processing_q = NULL; + struct msm_device_queue *eventData_q = NULL; + + if (!cpp_dev) { + pr_err("failed: cpp_dev %p\n", cpp_dev); + return -EINVAL; + } + + mutex_lock(&cpp_dev->mutex); + + processing_q = &cpp_dev->processing_q; + eventData_q = &cpp_dev->eventData_q; + + if (cpp_dev->cpp_open_cnt == 0) { + mutex_unlock(&cpp_dev->mutex); + return 0; + } + + for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { + if (cpp_dev->cpp_subscribe_list[i].active == 1) { + cpp_dev->cpp_subscribe_list[i].active = 0; + cpp_dev->cpp_subscribe_list[i].vfh = NULL; + break; + } + } + if (i == MAX_ACTIVE_CPP_INSTANCE) { + pr_err("Invalid close\n"); + mutex_unlock(&cpp_dev->mutex); + return -ENODEV; + } + + cpp_dev->cpp_open_cnt--; + if (cpp_dev->cpp_open_cnt == 0) { + pr_debug("irq_status: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4)); + pr_debug("DEBUG_SP: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40)); + pr_debug("DEBUG_T: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44)); + pr_debug("DEBUG_N: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48)); + pr_debug("DEBUG_R: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C)); + pr_debug("DEBUG_OPPC: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50)); + pr_debug("DEBUG_MO: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54)); + pr_debug("DEBUG_TIMER0: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60)); + pr_debug("DEBUG_TIMER1: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64)); + pr_debug("DEBUG_GPI: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70)); + pr_debug("DEBUG_GPO: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74)); + pr_debug("DEBUG_T0: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80)); + pr_debug("DEBUG_R0: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84)); + pr_debug("DEBUG_T1: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88)); + pr_debug("DEBUG_R1: 0x%x\n", + msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); + msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); + cpp_deinit_mem(cpp_dev); + iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx); + cpp_release_hardware(cpp_dev); + msm_cpp_empty_list(processing_q, list_frame); + msm_cpp_empty_list(eventData_q, list_eventdata); + cpp_dev->state = CPP_STATE_OFF; + } + + mutex_unlock(&cpp_dev->mutex); + return 0; +} + +static const struct v4l2_subdev_internal_ops msm_cpp_internal_ops = { + .open = cpp_open_node, + .close = cpp_close_node, +}; + +static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, + uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) +{ + int rc = -EINVAL; + + rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl, + buff_mgr_ops, buff_mgr_info); + if (rc < 0) + pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; +} + +static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev) +{ + struct v4l2_event v4l2_evt; + struct msm_queue_cmd *frame_qcmd = NULL; + struct msm_queue_cmd *event_qcmd = NULL; + struct msm_cpp_frame_info_t *processed_frame = NULL; + struct msm_device_queue *queue = &cpp_dev->processing_q; + struct msm_buf_mngr_info buff_mgr_info; + int rc = 0; + + frame_qcmd = msm_dequeue(queue, list_frame); + if (frame_qcmd) { + processed_frame = frame_qcmd->command; + do_gettimeofday(&(processed_frame->out_time)); + kfree(frame_qcmd); + event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); + if (!event_qcmd) { + pr_err("Insufficient memory. return"); + return -ENOMEM; + } + atomic_set(&event_qcmd->on_heap, 1); + event_qcmd->command = processed_frame; + CPP_DBG("fid %d\n", processed_frame->frame_id); + msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata); + + if (!processed_frame->output_buffer_info[0].processed_divert && + !processed_frame->output_buffer_info[0].native_buff) { + memset(&buff_mgr_info, 0 , + sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = + ((processed_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = + (processed_frame->identity & 0xFFFF); + buff_mgr_info.frame_id = processed_frame->frame_id; + buff_mgr_info.timestamp = processed_frame->timestamp; + buff_mgr_info.index = + processed_frame->output_buffer_info[0].index; + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("error putting buffer\n"); + rc = -EINVAL; + } + } + + if (processed_frame->duplicate_output && + !processed_frame-> + output_buffer_info[1].processed_divert) { + memset(&buff_mgr_info, 0 , + sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = + ((processed_frame->duplicate_identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = + (processed_frame->duplicate_identity & 0xFFFF); + buff_mgr_info.frame_id = processed_frame->frame_id; + buff_mgr_info.timestamp = processed_frame->timestamp; + buff_mgr_info.index = + processed_frame->output_buffer_info[1].index; + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("error putting buffer\n"); + rc = -EINVAL; + } + } + v4l2_evt.id = processed_frame->inst_id; + v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE; + v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt); + } + return rc; +} + +#if MSM_CPP_DUMP_FRM_CMD +static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) +{ + int i; + pr_info("-- start: cpp frame cmd for identity=0x%x, frame_id=%d --\n", + frame_info->identity, + frame_info->frame_id); + for (i = 0; i < frame_info->msg_len; i++) + pr_err("msg[%03d] = 0x%08x\n", i, frame_info->cpp_cmd_msg[i]); + pr_info("-- end: cpp frame cmd for identity=0x%x, frame_id=%d --\n", + frame_info->identity, + frame_info->frame_id); + return 0; +} +#else +static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info) +{ + return 0; +} +#endif + + +static void msm_cpp_do_timeout_work(struct work_struct *work) +{ + int ret; + uint32_t i = 0; + struct msm_cpp_frame_info_t *this_frame = NULL; + + pr_err("cpp_timer_callback called. (jiffies=%lu)\n", + jiffies); + if (!work) { + pr_err("Invalid work:%p\n", work); + return; + } + if (!atomic_read(&cpp_timer.used)) { + pr_err("Delayed trigger, IRQ serviced\n"); + return; + } + + disable_irq(cpp_timer.data.cpp_dev->irq->start); + pr_err("Reloading firmware\n"); + cpp_load_fw(cpp_timer.data.cpp_dev, NULL); + pr_err("Firmware loading done\n"); + enable_irq(cpp_timer.data.cpp_dev->irq->start); + msm_camera_io_w_mb(0x8, cpp_timer.data.cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w_mb(0xFFFF, + cpp_timer.data.cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + + if (!atomic_read(&cpp_timer.used)) { + pr_err("Delayed trigger, IRQ serviced\n"); + return; + } + + this_frame = cpp_timer.data.processed_frame; + pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n", + CPP_CMD_TIMEOUT_MS, jiffies); + ret = mod_timer(&cpp_timer.cpp_timer, + jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS)); + if (ret) + pr_err("error in mod_timer\n"); + + pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n", + this_frame->identity, this_frame->frame_id); + msm_cpp_write(0x6, cpp_timer.data.cpp_dev->base); + msm_cpp_dump_frame_cmd(this_frame); + for (i = 0; i < this_frame->msg_len; i++) + msm_cpp_write(this_frame->cpp_cmd_msg[i], + cpp_timer.data.cpp_dev->base); + return; +} + +void cpp_timer_callback(unsigned long data) +{ + struct msm_cpp_work_t *work = + cpp_timer.data.cpp_dev->work; + queue_work(cpp_timer.data.cpp_dev->timer_wq, + (struct work_struct *)work); +} + +static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev, + struct msm_queue_cmd *frame_qcmd) +{ + uint32_t i; + int32_t rc = -EAGAIN; + int ret; + struct msm_cpp_frame_info_t *process_frame; + + if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) { + process_frame = frame_qcmd->command; + msm_enqueue(&cpp_dev->processing_q, + &frame_qcmd->list_frame); + + cpp_timer.data.processed_frame = process_frame; + atomic_set(&cpp_timer.used, 1); + /* install timer for cpp timeout */ + CPP_DBG("Installing cpp_timer\n"); + setup_timer(&cpp_timer.cpp_timer, + cpp_timer_callback, (unsigned long)&cpp_timer); + CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n", + CPP_CMD_TIMEOUT_MS, jiffies); + ret = mod_timer(&cpp_timer.cpp_timer, + jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS)); + if (ret) + pr_err("error in mod_timer\n"); + + msm_cpp_write(0x6, cpp_dev->base); + msm_cpp_dump_frame_cmd(process_frame); + msm_cpp_poll_rx_empty(cpp_dev->base); + for (i = 0; i < process_frame->msg_len; i++) { + if (i % MSM_CPP_RX_FIFO_LEVEL == 0) + msm_cpp_poll_rx_empty(cpp_dev->base); + if ((induce_error) && (i == 1)) { + pr_err("Induce error\n"); + msm_cpp_write(process_frame->cpp_cmd_msg[i]-1, + cpp_dev->base); + induce_error--; + } else + msm_cpp_write(process_frame->cpp_cmd_msg[i], + cpp_dev->base); + } + do_gettimeofday(&(process_frame->in_time)); + rc = 0; + } + if (rc < 0) + pr_err("process queue full. drop frame\n"); + return rc; +} + +static int msm_cpp_flush_frames(struct cpp_device *cpp_dev) +{ + return 0; +} + +static int msm_cpp_cfg(struct cpp_device *cpp_dev, + struct msm_camera_v4l2_ioctl_t *ioctl_ptr) +{ + int rc = 0; + struct msm_queue_cmd *frame_qcmd = NULL; + struct msm_cpp_frame_info_t *new_frame = + kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL); + uint32_t *cpp_frame_msg; + unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1; + uint16_t num_stripes = 0; + struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info; + int32_t status = 0; + int32_t stripe_base = 0; + + int in_fd; + + int i = 0; + if (!new_frame) { + pr_err("Insufficient memory. return\n"); + return -ENOMEM; + } + + rc = (copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + rc = -EINVAL; + goto ERROR1; + } + + if ((new_frame->msg_len == 0) || + (new_frame->msg_len > MSM_CPP_MAX_FRAME_LENGTH)) { + pr_err("%s:%d: Invalid frame len:%d\n", __func__, + __LINE__, new_frame->msg_len); + rc = -EINVAL; + goto ERROR1; + } + + cpp_frame_msg = kzalloc(sizeof(uint32_t)*new_frame->msg_len, + GFP_KERNEL); + if (!cpp_frame_msg) { + pr_err("Insufficient memory. return"); + rc = -ENOMEM; + goto ERROR1; + } + + rc = (copy_from_user(cpp_frame_msg, + (void __user *)new_frame->cpp_cmd_msg, + sizeof(uint32_t)*new_frame->msg_len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + rc = -EINVAL; + goto ERROR2; + } + + new_frame->cpp_cmd_msg = cpp_frame_msg; + + in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->input_buffer_info, + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF), &in_fd); + if (!in_phyaddr) { + pr_err("error gettting input physical address\n"); + rc = -EINVAL; + goto ERROR2; + } + + if (new_frame->output_buffer_info[0].native_buff == 0) { + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = ((new_frame->identity >> 16) & + 0xFFFF); + buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &buff_mgr_info); + if (rc < 0) { + rc = -EAGAIN; + pr_debug("error getting buffer rc:%d\n", rc); + goto ERROR2; + } + new_frame->output_buffer_info[0].index = buff_mgr_info.index; + } + + out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->output_buffer_info[0], + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF), + &new_frame->output_buffer_info[0].fd); + if (!out_phyaddr0) { + pr_err("error gettting output physical address\n"); + rc = -EINVAL; + goto ERROR3; + } + out_phyaddr1 = out_phyaddr0; + + /* get buffer for duplicate output */ + if (new_frame->duplicate_output) { + CPP_DBG("duplication enabled, dup_id=0x%x", + new_frame->duplicate_identity); + memset(&new_frame->output_buffer_info[1], 0, + sizeof(struct msm_cpp_buffer_info_t)); + memset(&dup_buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + dup_buff_mgr_info.session_id = + ((new_frame->duplicate_identity >> 16) & 0xFFFF); + dup_buff_mgr_info.stream_id = + (new_frame->duplicate_identity & 0xFFFF); + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &dup_buff_mgr_info); + if (rc < 0) { + rc = -EAGAIN; + pr_debug("error getting buffer rc:%d\n", rc); + goto ERROR3; + } + new_frame->output_buffer_info[1].index = + dup_buff_mgr_info.index; + out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->output_buffer_info[1], + ((new_frame->duplicate_identity >> 16) & 0xFFFF), + (new_frame->duplicate_identity & 0xFFFF), + &new_frame->output_buffer_info[1].fd); + if (!out_phyaddr1) { + pr_err("error gettting output physical address\n"); + rc = -EINVAL; + msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &dup_buff_mgr_info); + goto ERROR3; + } + /* set duplicate enable bit */ + cpp_frame_msg[5] |= 0x1; + CPP_DBG("out_phyaddr1= %08x\n", (uint32_t)out_phyaddr1); + } + + num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) + + ((cpp_frame_msg[12] >> 10) & 0x3FF) + + (cpp_frame_msg[12] & 0x3FF); + + if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_2_0) { + stripe_base = STRIPE_BASE_FW_1_2_0; + } else if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_4_0) { + stripe_base = STRIPE_BASE_FW_1_4_0; + } else if ((cpp_dev->fw_version & 0xffff0000) == CPP_FW_VERSION_1_6_0) { + stripe_base = STRIPE_BASE_FW_1_6_0; + } else { + pr_err("invalid fw version %08x", cpp_dev->fw_version); + goto ERROR3; + } + + for (i = 0; i < num_stripes; i++) { + cpp_frame_msg[stripe_base + 5 + i*27] += + (uint32_t) in_phyaddr; + cpp_frame_msg[stripe_base + 11 + i * 27] += + (uint32_t) out_phyaddr0; + cpp_frame_msg[stripe_base + 12 + i * 27] += + (uint32_t) out_phyaddr1; + cpp_frame_msg[stripe_base + 13 + i * 27] += + (uint32_t) out_phyaddr0; + cpp_frame_msg[stripe_base + 14 + i * 27] += + (uint32_t) out_phyaddr1; + } + + frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); + if (!frame_qcmd) { + pr_err("Insufficient memory. return\n"); + rc = -ENOMEM; + goto ERROR3; + } + + atomic_set(&frame_qcmd->on_heap, 1); + frame_qcmd->command = new_frame; + rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd); + if (rc < 0) { + pr_err("error cannot send frame to hardware\n"); + rc = -EINVAL; + goto ERROR4; + } + + ioctl_ptr->trans_code = rc; + status = rc; + rc = (copy_to_user((void __user *)new_frame->status, &status, + sizeof(int32_t)) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + rc = -EINVAL; + goto ERROR4; + } + return rc; +ERROR4: + kfree(frame_qcmd); +ERROR3: + if (new_frame->output_buffer_info[0].native_buff == 0) + msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &buff_mgr_info); +ERROR2: + kfree(cpp_frame_msg); +ERROR1: + ioctl_ptr->trans_code = rc; + status = rc; + if (copy_to_user((void __user *)new_frame->status, &status, + sizeof(int32_t))) + pr_err("error cannot copy error\n"); + kfree(new_frame); + return rc; +} + +long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + int rc = 0; + + if ((ioctl_ptr == NULL) || (ioctl_ptr->ioctl_ptr == NULL)) { + pr_err("ioctl_ptr is null\n"); + return -EINVAL; + } + if (cpp_dev == NULL) { + pr_err("cpp_dev is null\n"); + return -EINVAL; + } + mutex_lock(&cpp_dev->mutex); + CPP_DBG("E cmd: 0x%x\n", cmd); + switch (cmd) { + case VIDIOC_MSM_CPP_GET_HW_INFO: { + CPP_DBG("VIDIOC_MSM_CPP_GET_HW_INFO\n"); + if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, + &cpp_dev->hw_info, + sizeof(struct cpp_hw_info))) { + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + break; + } + + case VIDIOC_MSM_CPP_LOAD_FIRMWARE: { + CPP_DBG("VIDIOC_MSM_CPP_LOAD_FIRMWARE\n"); + if (cpp_dev->is_firmware_loaded == 0) { + if (cpp_dev->fw_name_bin != NULL) { + kfree(cpp_dev->fw_name_bin); + cpp_dev->fw_name_bin = NULL; + } + if ((ioctl_ptr->len == 0) || + (ioctl_ptr->len > MSM_CPP_MAX_FW_NAME_LEN)) { + pr_err("ioctl_ptr->len is 0\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + cpp_dev->fw_name_bin = kzalloc(ioctl_ptr->len+1, + GFP_KERNEL); + if (!cpp_dev->fw_name_bin) { + pr_err("%s:%d: malloc error\n", __func__, + __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + if (ioctl_ptr->ioctl_ptr == NULL) { + pr_err("ioctl_ptr->ioctl_ptr=NULL\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + rc = (copy_from_user(cpp_dev->fw_name_bin, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(cpp_dev->fw_name_bin); + cpp_dev->fw_name_bin = NULL; + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + *(cpp_dev->fw_name_bin+ioctl_ptr->len) = '\0'; + disable_irq(cpp_dev->irq->start); + cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); + enable_irq(cpp_dev->irq->start); + cpp_dev->is_firmware_loaded = 1; + } + break; + } + case VIDIOC_MSM_CPP_CFG: + CPP_DBG("VIDIOC_MSM_CPP_CFG\n"); + rc = msm_cpp_cfg(cpp_dev, ioctl_ptr); + break; + case VIDIOC_MSM_CPP_FLUSH_QUEUE: + CPP_DBG("VIDIOC_MSM_CPP_FLUSH_QUEUE\n"); + rc = msm_cpp_flush_frames(cpp_dev); + break; + case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO: + case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: { + struct msm_cpp_stream_buff_info_t *u_stream_buff_info; + struct msm_cpp_stream_buff_info_t k_stream_buff_info; + CPP_DBG("VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO\n"); + if (sizeof(struct msm_cpp_stream_buff_info_t) != + ioctl_ptr->len) { + pr_err("%s:%d: invalid length\n", __func__, __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); + if (!u_stream_buff_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(u_stream_buff_info, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (u_stream_buff_info->num_buffs == 0) { + pr_err("%s:%d: Invalid number of buffers\n", __func__, + __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; + k_stream_buff_info.identity = u_stream_buff_info->identity; + + if (k_stream_buff_info.num_buffs > MSM_CAMERA_MAX_STREAM_BUF) { + pr_err("%s:%d: unexpected large num buff requested\n", + __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + k_stream_buff_info.buffer_info = + kzalloc(k_stream_buff_info.num_buffs * + sizeof(struct msm_cpp_buffer_info_t), GFP_KERNEL); + if (ZERO_OR_NULL_PTR(k_stream_buff_info.buffer_info)) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(k_stream_buff_info.buffer_info, + (void __user *)u_stream_buff_info->buffer_info, + k_stream_buff_info.num_buffs * + sizeof(struct msm_cpp_buffer_info_t)) ? + -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { + rc = msm_cpp_add_buff_queue_entry(cpp_dev, + ((k_stream_buff_info.identity >> 16) & 0xFFFF), + (k_stream_buff_info.identity & 0xFFFF)); + } + if (!rc) + rc = msm_cpp_enqueue_buff_info_list(cpp_dev, + &k_stream_buff_info); + + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + + if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) { + cpp_dev->stream_cnt++; + pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); + } + break; + } + case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: { + uint32_t identity; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n"); + + if ((ioctl_ptr->len == 0) || + (ioctl_ptr->len > sizeof(uint32_t))) + return -EINVAL; + + rc = (copy_from_user(&identity, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, + ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for identity:%d\n", + identity); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + msm_cpp_dequeue_buff_info_list(cpp_dev, buff_queue_info); + rc = msm_cpp_free_buff_queue_entry(cpp_dev, + buff_queue_info->session_id, + buff_queue_info->stream_id); + if (cpp_dev->stream_cnt > 0) { + cpp_dev->stream_cnt--; + pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt); + if (cpp_dev->stream_cnt == 0) { + rc = msm_isp_update_bandwidth(ISP_CPP, 0, 0); + if (rc < 0) + pr_err("Bandwidth Reset Failed!\n"); + } + } else { + pr_err("error: stream count underflow %d\n", + cpp_dev->stream_cnt); + } + break; + } + case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: { + struct msm_device_queue *queue = &cpp_dev->eventData_q; + struct msm_queue_cmd *event_qcmd; + struct msm_cpp_frame_info_t *process_frame; + CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n"); + event_qcmd = msm_dequeue(queue, list_eventdata); + if (!event_qcmd) { + pr_err("no queue cmd available"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + process_frame = event_qcmd->command; + CPP_DBG("fid %d\n", process_frame->frame_id); + if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, + process_frame, + sizeof(struct msm_cpp_frame_info_t))) { + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + kfree(process_frame->cpp_cmd_msg); + kfree(process_frame); + kfree(event_qcmd); + break; + } + case VIDIOC_MSM_CPP_SET_CLOCK: { + struct msm_cpp_clock_settings_t clock_settings; + unsigned long clock_rate = 0; + CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n"); + if (ioctl_ptr->len == 0) { + pr_err("ioctl_ptr->len is 0\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (ioctl_ptr->ioctl_ptr == NULL) { + pr_err("ioctl_ptr->ioctl_ptr is NULL\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (ioctl_ptr->len != sizeof(struct msm_cpp_clock_settings_t)) { + pr_err("Not valid ioctl_ptr->len\n"); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(&clock_settings, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + if (clock_settings.clock_rate > 0) { + rc = msm_isp_update_bandwidth(ISP_CPP, + clock_settings.avg, + clock_settings.inst); + if (rc < 0) { + pr_err("Bandwidth Set Failed!\n"); + msm_isp_update_bandwidth(ISP_CPP, 0, 0); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + clock_rate = clk_round_rate( + cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], + clock_settings.clock_rate); + if (clock_rate != clock_settings.clock_rate) + pr_err("clock rate differ from settings\n"); + + clk_set_rate(cpp_dev->cpp_clk[MSM_CPP_CORE_CLK_IDX], + clock_rate); + } + break; + } + case MSM_SD_SHUTDOWN: + CPP_DBG("MSM_SD_SHUTDOWN\n"); + mutex_unlock(&cpp_dev->mutex); + while (cpp_dev->cpp_open_cnt != 0) + cpp_close_node(sd, NULL); + mutex_lock(&cpp_dev->mutex); + rc = 0; + break; + case VIDIOC_MSM_CPP_QUEUE_BUF: { + struct msm_pproc_queue_buf_info queue_buf_info; + CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n"); + rc = (copy_from_user(&queue_buf_info, + (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_pproc_queue_buf_info)) ? + -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + break; + } + + if (queue_buf_info.is_buf_dirty) { + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &queue_buf_info.buff_mgr_info); + } else { + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &queue_buf_info.buff_mgr_info); + } + if (rc < 0) { + pr_err("error in buf done\n"); + rc = -EINVAL; + } + + break; + } + case VIDIOC_MSM_CPP_POP_STREAM_BUFFER: { + struct msm_buf_mngr_info buff_mgr_info; + struct msm_cpp_frame_info_t frame_info; + rc = (copy_from_user(&frame_info, + (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_cpp_frame_info_t)) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + break; + } + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = + ((frame_info.identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = (frame_info.identity & 0xFFFF); + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &buff_mgr_info); + if (rc < 0) { + rc = -EAGAIN; + pr_err("error getting buffer rc:%d\n", rc); + break; + } + buff_mgr_info.frame_id = frame_info.frame_id; + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("error in buf done\n"); + rc = -EAGAIN; + } + break; + } + default: + pr_err_ratelimited("invalid value: cmd=0x%x\n", cmd); + break; + } + mutex_unlock(&cpp_dev->mutex); + CPP_DBG("X\n"); + return rc; +} + +int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + CPP_DBG("Called\n"); + return v4l2_event_subscribe(fh, sub, MAX_CPP_V4l2_EVENTS, NULL); +} + +int msm_cpp_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + CPP_DBG("Called\n"); + return v4l2_event_unsubscribe(fh, sub); +} + +static struct v4l2_subdev_core_ops msm_cpp_subdev_core_ops = { + .ioctl = msm_cpp_subdev_ioctl, + .subscribe_event = msm_cpp_subscribe_event, + .unsubscribe_event = msm_cpp_unsubscribe_event, +}; + +static const struct v4l2_subdev_ops msm_cpp_subdev_ops = { + .core = &msm_cpp_subdev_core_ops, +}; + +static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops; + +static long msm_cpp_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + + switch (cmd) { + case VIDIOC_DQEVENT: + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); + + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + + case VIDIOC_MSM_CPP_GET_INST_INFO: { + uint32_t i; + struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + struct msm_cpp_frame_info_t inst_info; + memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t)); + for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) { + if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) { + inst_info.inst_id = i; + break; + } + } + if (copy_to_user( + (void __user *)ioctl_ptr->ioctl_ptr, &inst_info, + sizeof(struct msm_cpp_frame_info_t))) { + return -EINVAL; + } + } + break; + default: + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); + } + + return 0; +} + +static long msm_cpp_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_cpp_subdev_do_ioctl); +} + +static int cpp_register_domain(void) +{ + struct msm_iova_partition cpp_fw_partition = { + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + struct msm_iova_layout cpp_fw_layout = { + .partitions = &cpp_fw_partition, + .npartitions = 1, + .client_name = "camera_cpp", + .domain_flags = 0, + }; + + return msm_register_domain(&cpp_fw_layout); +} + +static int msm_cpp_get_clk_info(struct cpp_device *cpp_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[CPP_CLK_INFO_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + + CPP_DBG("count = %d\n", count); + if (count == 0) { + pr_err("no clocks found in device tree, count=%d", count); + return 0; + } + + if (count > CPP_CLK_INFO_MAX) { + pr_err("invalid count=%d, max is %d\n", count, + CPP_CLK_INFO_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(cpp_clk_info[i].clk_name)); + CPP_DBG("clock-names[%d] = %s\n", i, cpp_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + cpp_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CPP_DBG("clk_rate[%d] = %ld\n", i, cpp_clk_info[i].clk_rate); + } + cpp_dev->num_clk = count; + return 0; +} + + +static int cpp_probe(struct platform_device *pdev) +{ + struct cpp_device *cpp_dev; + int rc = 0; + CPP_DBG("E"); + cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL); + if (!cpp_dev) { + pr_err("no enough memory\n"); + return -ENOMEM; + } + + cpp_dev->cpp_clk = kzalloc(sizeof(struct clk *) * + ARRAY_SIZE(cpp_clk_info), GFP_KERNEL); + if (!cpp_dev->cpp_clk) { + pr_err("no enough memory\n"); + rc = -ENOMEM; + goto ERROR1; + } + + v4l2_subdev_init(&cpp_dev->msm_sd.sd, &msm_cpp_subdev_ops); + cpp_dev->msm_sd.sd.internal_ops = &msm_cpp_internal_ops; + snprintf(cpp_dev->msm_sd.sd.name, ARRAY_SIZE(cpp_dev->msm_sd.sd.name), + "cpp"); + cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + cpp_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + v4l2_set_subdevdata(&cpp_dev->msm_sd.sd, cpp_dev); + platform_set_drvdata(pdev, &cpp_dev->msm_sd.sd); + mutex_init(&cpp_dev->mutex); + spin_lock_init(&cpp_dev->tasklet_lock); + + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + + cpp_dev->pdev = pdev; + + cpp_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cpp"); + if (!cpp_dev->mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->vbif_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cpp_vbif"); + if (!cpp_dev->vbif_mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->cpp_hw_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cpp_hw"); + if (!cpp_dev->cpp_hw_mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "cpp"); + if (!cpp_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto ERROR2; + } + + cpp_dev->io = request_mem_region(cpp_dev->mem->start, + resource_size(cpp_dev->mem), pdev->name); + if (!cpp_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto ERROR2; + } + + cpp_dev->domain_num = cpp_register_domain(); + if (cpp_dev->domain_num < 0) { + pr_err("%s: could not register domain\n", __func__); + rc = -ENODEV; + goto ERROR3; + } + + cpp_dev->domain = + msm_get_iommu_domain(cpp_dev->domain_num); + if (!cpp_dev->domain) { + pr_err("%s: cannot find domain\n", __func__); + rc = -ENODEV; + goto ERROR3; + } + + cpp_dev->iommu_ctx = msm_iommu_get_ctx("cpp"); + if (IS_ERR(cpp_dev->iommu_ctx)) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -EPROBE_DEFER; + goto ERROR3; + } + + if (msm_cpp_get_clk_info(cpp_dev, pdev) < 0) { + pr_err("msm_cpp_get_clk_info() failed\n"); + goto ERROR3; + } + + media_entity_init(&cpp_dev->msm_sd.sd.entity, 0, NULL, 0); + cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + cpp_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CPP; + cpp_dev->msm_sd.sd.entity.name = pdev->name; + cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY; + msm_sd_register(&cpp_dev->msm_sd); + msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_cpp_v4l2_subdev_fops.unlocked_ioctl = msm_cpp_subdev_fops_ioctl; + msm_cpp_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_cpp_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + + cpp_dev->msm_sd.sd.devnode->fops = &msm_cpp_v4l2_subdev_fops; + cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num; + cpp_dev->state = CPP_STATE_BOOT; + + rc = cpp_init_hardware(cpp_dev); + if (rc < 0) + goto CPP_PROBE_INIT_ERROR; + + msm_camera_io_w(0x0, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_MASK); + msm_camera_io_w(0xFFFF, cpp_dev->base + + MSM_CPP_MICRO_IRQGEN_CLR); + msm_camera_io_w(0x80000000, cpp_dev->base + 0xF0); + cpp_release_hardware(cpp_dev); + cpp_dev->state = CPP_STATE_OFF; + msm_cpp_enable_debugfs(cpp_dev); + + msm_queue_init(&cpp_dev->eventData_q, "eventdata"); + msm_queue_init(&cpp_dev->processing_q, "frame"); + INIT_LIST_HEAD(&cpp_dev->tasklet_q); + tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet, + (unsigned long)cpp_dev); + cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue"); + cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t), + GFP_KERNEL); + + if (!cpp_dev->work) { + pr_err("no enough memory\n"); + rc = -ENOMEM; + goto CPP_PROBE_INIT_ERROR; + } + + INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work); + cpp_dev->cpp_open_cnt = 0; + cpp_dev->is_firmware_loaded = 0; + cpp_timer.data.cpp_dev = cpp_dev; + atomic_set(&cpp_timer.used, 0); + cpp_dev->fw_name_bin = NULL; + if (rc == 0) + CPP_DBG("SUCCESS."); + else + CPP_DBG("FAILED."); + return rc; +CPP_PROBE_INIT_ERROR: + media_entity_cleanup(&cpp_dev->msm_sd.sd.entity); + msm_sd_unregister(&cpp_dev->msm_sd); +ERROR3: + release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem)); +ERROR2: + kfree(cpp_dev->cpp_clk); +ERROR1: + kfree(cpp_dev); + return rc; +} + +static const struct of_device_id msm_cpp_dt_match[] = { + {.compatible = "qcom,cpp"}, + {} +}; + +static int cpp_device_remove(struct platform_device *dev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(dev); + struct cpp_device *cpp_dev; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + cpp_dev = (struct cpp_device *)v4l2_get_subdevdata(sd); + if (!cpp_dev) { + pr_err("%s: cpp device is NULL\n", __func__); + return 0; + } + + msm_sd_unregister(&cpp_dev->msm_sd); + release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem)); + release_mem_region(cpp_dev->vbif_mem->start, + resource_size(cpp_dev->vbif_mem)); + release_mem_region(cpp_dev->cpp_hw_mem->start, + resource_size(cpp_dev->cpp_hw_mem)); + mutex_destroy(&cpp_dev->mutex); + kfree(cpp_dev->work); + destroy_workqueue(cpp_dev->timer_wq); + kfree(cpp_dev->cpp_clk); + kfree(cpp_dev); + return 0; +} + +static struct platform_driver cpp_driver = { + .probe = cpp_probe, + .remove = cpp_device_remove, + .driver = { + .name = MSM_CPP_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_cpp_dt_match, + }, +}; + +static int __init msm_cpp_init_module(void) +{ + return platform_driver_register(&cpp_driver); +} + +static void __exit msm_cpp_exit_module(void) +{ + platform_driver_unregister(&cpp_driver); +} + +static int msm_cpp_debugfs_error_s(void *data, u64 val) +{ + pr_err("setting error inducement"); + induce_error = val; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL, + msm_cpp_debugfs_error_s, "%llu\n"); + +static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev) +{ + struct dentry *debugfs_base; + debugfs_base = debugfs_create_dir("msm_cpp", NULL); + if (!debugfs_base) + return -ENOMEM; + + if (!debugfs_create_file("error", S_IRUGO | S_IWUSR, debugfs_base, + (void *)cpp_dev, &cpp_debugfs_error)) + return -ENOMEM; + + return 0; +} + +module_init(msm_cpp_init_module); +module_exit(msm_cpp_exit_module); +MODULE_DESCRIPTION("MSM CPP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/msm_cpp.h new file mode 100644 index 0000000000000000000000000000000000000000..e306335a826d0ec0a555978608d132dafe49bd5c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/pproc/cpp/msm_cpp.h @@ -0,0 +1,233 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_CPP_H__ +#define __MSM_CPP_H__ + +#include +#include +#include +#include +#include +#include +#include "msm_sd.h" + +/* hw version info: + 31:28 Major version + 27:16 Minor version + 15:0 Revision bits +**/ +#define CPP_HW_VERSION_1_1_0 0x10010000 +#define CPP_HW_VERSION_1_1_1 0x10010001 +#define CPP_HW_VERSION_2_0_0 0x20000000 +#define CPP_HW_VERSION_4_0_0 0x40000000 +#define CPP_HW_VERSION_4_1_0 0x40010000 + +#define MAX_ACTIVE_CPP_INSTANCE 8 +#define MAX_CPP_PROCESSING_FRAME 2 +#define MAX_CPP_V4l2_EVENTS 30 + +#define MSM_CPP_MICRO_BASE 0x4000 +#define MSM_CPP_MICRO_HW_VERSION 0x0000 +#define MSM_CPP_MICRO_IRQGEN_STAT 0x0004 +#define MSM_CPP_MICRO_IRQGEN_CLR 0x0008 +#define MSM_CPP_MICRO_IRQGEN_MASK 0x000C +#define MSM_CPP_MICRO_FIFO_TX_DATA 0x0010 +#define MSM_CPP_MICRO_FIFO_TX_STAT 0x0014 +#define MSM_CPP_MICRO_FIFO_RX_DATA 0x0018 +#define MSM_CPP_MICRO_FIFO_RX_STAT 0x001C +#define MSM_CPP_MICRO_BOOT_START 0x0020 +#define MSM_CPP_MICRO_BOOT_LDORG 0x0024 +#define MSM_CPP_MICRO_CLKEN_CTL 0x0030 + +#define MSM_CPP_CMD_GET_BOOTLOADER_VER 0x1 +#define MSM_CPP_CMD_FW_LOAD 0x2 +#define MSM_CPP_CMD_EXEC_JUMP 0x3 +#define MSM_CPP_CMD_RESET_HW 0x5 +#define MSM_CPP_CMD_PROCESS_FRAME 0x6 +#define MSM_CPP_CMD_FLUSH_STREAM 0x7 +#define MSM_CPP_CMD_CFG_MEM_PARAM 0x8 +#define MSM_CPP_CMD_ERROR_REQUEST 0x9 +#define MSM_CPP_CMD_GET_STATUS 0xA +#define MSM_CPP_CMD_GET_FW_VER 0xB + +#define MSM_CPP_MSG_ID_CMD 0x3E646D63 +#define MSM_CPP_MSG_ID_OK 0x0A0A4B4F +#define MSM_CPP_MSG_ID_TRAILER 0xABCDEFAA + +#define MSM_CPP_MSG_ID_JUMP_ACK 0x00000001 +#define MSM_CPP_MSG_ID_FRAME_ACK 0x00000002 +#define MSM_CPP_MSG_ID_FRAME_NACK 0x00000003 +#define MSM_CPP_MSG_ID_FLUSH_ACK 0x00000004 +#define MSM_CPP_MSG_ID_FLUSH_NACK 0x00000005 +#define MSM_CPP_MSG_ID_CFG_MEM_ACK 0x00000006 +#define MSM_CPP_MSG_ID_CFG_MEM_INV 0x00000007 +#define MSM_CPP_MSG_ID_ERROR_STATUS 0x00000008 +#define MSM_CPP_MSG_ID_INVALID_CMD 0x00000009 +#define MSM_CPP_MSG_ID_GEN_STATUS 0x0000000A +#define MSM_CPP_MSG_ID_FLUSHED 0x0000000B +#define MSM_CPP_MSG_ID_FW_VER 0x0000000C + +#define MSM_CPP_JUMP_ADDRESS 0x20 +#define MSM_CPP_START_ADDRESS 0x0 +#define MSM_CPP_END_ADDRESS 0x3F00 + +#define MSM_CPP_POLL_RETRIES 20 +#define MSM_CPP_TASKLETQ_SIZE 16 +#define MSM_CPP_TX_FIFO_LEVEL 16 +#define MSM_CPP_RX_FIFO_LEVEL 512 + +struct cpp_subscribe_info { + struct v4l2_fh *vfh; + uint32_t active; +}; + +enum cpp_state { + CPP_STATE_BOOT, + CPP_STATE_IDLE, + CPP_STATE_ACTIVE, + CPP_STATE_OFF, +}; + +enum cpp_iommu_state { + CPP_IOMMU_STATE_DETACHED, + CPP_IOMMU_STATE_ATTACHED, +}; + +enum msm_queue { + MSM_CAM_Q_CTRL, /* control command or control command status */ + MSM_CAM_Q_VFE_EVT, /* adsp event */ + MSM_CAM_Q_VFE_MSG, /* adsp message */ + MSM_CAM_Q_V4L2_REQ, /* v4l2 request */ + MSM_CAM_Q_VPE_MSG, /* vpe message */ + MSM_CAM_Q_PP_MSG, /* pp message */ +}; + +struct msm_queue_cmd { + struct list_head list_config; + struct list_head list_control; + struct list_head list_frame; + struct list_head list_pict; + struct list_head list_vpe_frame; + struct list_head list_eventdata; + enum msm_queue type; + void *command; + atomic_t on_heap; + struct timespec ts; + uint32_t error_code; + uint32_t trans_code; +}; + +struct msm_device_queue { + struct list_head list; + spinlock_t lock; + wait_queue_head_t wait; + int max; + int len; + const char *name; +}; + +struct msm_cpp_tasklet_queue_cmd { + struct list_head list; + uint32_t irq_status; + uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL]; + uint32_t tx_level; + uint8_t cmd_used; +}; + +struct msm_cpp_buffer_map_info_t { + unsigned long len; + dma_addr_t phy_addr; + struct ion_handle *ion_handle; + struct msm_cpp_buffer_info_t buff_info; +}; + +struct msm_cpp_buffer_map_list_t { + struct msm_cpp_buffer_map_info_t map_info; + struct list_head entry; +}; + +struct msm_cpp_buff_queue_info_t { + uint32_t used; + uint16_t session_id; + uint16_t stream_id; + struct list_head vb2_buff_head; + struct list_head native_buff_head; +}; + +struct msm_cpp_work_t { + struct work_struct my_work; + struct cpp_device *cpp_dev; +}; +struct msm_cpp_clock_settings_t { + long clock_rate; + uint64_t avg; + uint64_t inst; +}; + +struct cpp_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + struct resource *io; + struct resource *vbif_mem; + struct resource *vbif_io; + struct resource *cpp_hw_mem; + void __iomem *vbif_base; + void __iomem *base; + void __iomem *cpp_hw_base; + struct clk **cpp_clk; + struct regulator *fs_cpp; + struct mutex mutex; + enum cpp_state state; + enum cpp_iommu_state iommu_state; + uint8_t is_firmware_loaded; + char *fw_name_bin; + struct workqueue_struct *timer_wq; + struct msm_cpp_work_t *work; + uint32_t fw_version; + uint8_t stream_cnt; + + int domain_num; + struct iommu_domain *domain; + struct device *iommu_ctx; + struct ion_client *client; + struct kref refcount; + uint32_t num_clk; + + /* Reusing proven tasklet from msm isp */ + atomic_t irq_cnt; + uint8_t taskletq_idx; + spinlock_t tasklet_lock; + struct list_head tasklet_q; + struct tasklet_struct cpp_tasklet; + struct msm_cpp_tasklet_queue_cmd + tasklet_queue_cmd[MSM_CPP_TASKLETQ_SIZE]; + + struct cpp_subscribe_info cpp_subscribe_list[MAX_ACTIVE_CPP_INSTANCE]; + uint32_t cpp_open_cnt; + struct cpp_hw_info hw_info; + + struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ + + /* Processing Queue + * store frame info for frames sent to microcontroller + */ + struct msm_device_queue processing_q; + + struct msm_cpp_buff_queue_info_t *buff_queue; + uint32_t num_buffq; + struct v4l2_subdev *buf_mgr_subdev; +}; +#endif /* __MSM_CPP_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d3d25bfb918f32c9ee81a31349afa3346ee7c9c0 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o diff --git a/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/msm_vpe.c new file mode 100644 index 0000000000000000000000000000000000000000..d849be6c6b77bc15ab011fed5281299a35f1694d --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/msm_vpe.c @@ -0,0 +1,1655 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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. + */ + +#define pr_fmt(fmt) "MSM-VPE %s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../include/media/msmb_pproc.h" +#include "msm_vpe.h" +#include "msm_camera_io_util.h" + +#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF) +#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF) + +#define MSM_VPE_DRV_NAME "msm_vpe" + +#define MSM_VPE_MAX_BUFF_QUEUE 16 + +#define CONFIG_MSM_VPE_DBG 0 + +#if CONFIG_MSM_VPE_DBG +#define VPE_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +static void vpe_mem_dump(const char * const name, const void * const addr, + int size) +{ + char line_str[128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + VPE_DBG("%s: (%s) %p %d\n", __func__, name, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "%08x: ", (u32) p); + p_str += 10; + } + data = *p++; + snprintf(p_str, 12, "%08x ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + VPE_DBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + VPE_DBG("%s\n", line_str); +} + +static inline long long vpe_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +#define msm_dequeue(queue, member) ({ \ + unsigned long flags; \ + struct msm_device_queue *__q = (queue); \ + struct msm_queue_cmd *qcmd = 0; \ + spin_lock_irqsave(&__q->lock, flags); \ + if (!list_empty(&__q->list)) { \ + __q->len--; \ + qcmd = list_first_entry(&__q->list, \ + struct msm_queue_cmd, \ + member); \ + list_del_init(&qcmd->member); \ + } \ + spin_unlock_irqrestore(&__q->lock, flags); \ + qcmd; \ + }) + +static void msm_queue_init(struct msm_device_queue *queue, const char *name) +{ + spin_lock_init(&queue->lock); + queue->len = 0; + queue->max = 0; + queue->name = name; + INIT_LIST_HEAD(&queue->list); + init_waitqueue_head(&queue->wait); +} + +static struct msm_cam_clk_info vpe_clk_info[] = { + {"vpe_clk", 160000000}, + {"vpe_pclk", -1}, +}; + +static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev); + +static void msm_enqueue(struct msm_device_queue *queue, + struct list_head *entry) +{ + unsigned long flags; + spin_lock_irqsave(&queue->lock, flags); + queue->len++; + if (queue->len > queue->max) { + queue->max = queue->len; + pr_debug("queue %s new max is %d\n", queue->name, queue->max); + } + list_add_tail(entry, &queue->list); + wake_up(&queue->wait); + VPE_DBG("woke up %s\n", queue->name); + spin_unlock_irqrestore(&queue->lock, flags); +} + +static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry( + struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id) +{ + uint32_t i = 0; + struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL; + + for (i = 0; i < vpe_dev->num_buffq; i++) { + if ((vpe_dev->buff_queue[i].used == 1) && + (vpe_dev->buff_queue[i].session_id == session_id) && + (vpe_dev->buff_queue[i].stream_id == stream_id)) { + buff_queue_info = &vpe_dev->buff_queue[i]; + break; + } + } + + if (buff_queue_info == NULL) { + pr_err("error buffer queue entry for sess:%d strm:%d not found\n", + session_id, stream_id); + } + return buff_queue_info; +} + +static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev, + struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index, + uint8_t native_buff) +{ + unsigned long phy_add = 0; + struct list_head *buff_head; + struct msm_vpe_buffer_map_list_t *buff, *save; + + if (native_buff) + buff_head = &buff_queue_info->native_buff_head; + else + buff_head = &buff_queue_info->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buff_index) { + phy_add = buff->map_info.phy_addr; + break; + } + } + + return phy_add; +} + +static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev, + struct msm_vpe_buff_queue_info_t *buff_queue, + struct msm_vpe_buffer_info_t *buffer_info) +{ + struct list_head *buff_head; + struct msm_vpe_buffer_map_list_t *buff, *save; + int rc = 0; + + if (buffer_info->native_buff) + buff_head = &buff_queue->native_buff_head; + else + buff_head = &buff_queue->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buffer_info->index) { + pr_err("error buffer index already queued\n"); + return -EINVAL; + } + } + + buff = kzalloc( + sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL); + if (!buff) { + pr_err("error allocating memory\n"); + return -EINVAL; + } + + buff->map_info.buff_info = *buffer_info; + buff->map_info.ion_handle = ion_import_dma_buf(vpe_dev->client, + buffer_info->fd); + if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) { + pr_err("ION import failed\n"); + goto queue_buff_error1; + } + + rc = ion_map_iommu(vpe_dev->client, buff->map_info.ion_handle, + vpe_dev->domain_num, 0, SZ_4K, 0, + &buff->map_info.phy_addr, + &buff->map_info.len, 0, 0); + if (rc < 0) { + pr_err("ION mmap failed\n"); + goto queue_buff_error2; + } + + INIT_LIST_HEAD(&buff->entry); + list_add_tail(&buff->entry, buff_head); + + return buff->map_info.phy_addr; + +queue_buff_error2: + ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle, + vpe_dev->domain_num, 0); +queue_buff_error1: + ion_free(vpe_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + kzfree(buff); + + return 0; +} + +static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev, + struct msm_vpe_buffer_map_list_t *buff) +{ + ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle, + vpe_dev->domain_num, 0); + ion_free(vpe_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + + list_del_init(&buff->entry); + kzfree(buff); + + return; +} + +static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev, + struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id, + uint32_t stream_id) +{ + unsigned long phy_addr = 0; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + uint8_t native_buff = buffer_info->native_buff; + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return phy_addr; + } + + phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info, + buffer_info->index, native_buff); + if ((phy_addr == 0) && (native_buff)) { + phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, + buffer_info); + } + return phy_addr; +} + +static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev, + struct msm_vpe_stream_buff_info_t *stream_buff_info) +{ + uint32_t j; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + return -EINVAL; + } + + for (j = 0; j < stream_buff_info->num_buffs; j++) { + msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info, + &stream_buff_info->buffer_info[j]); + } + return 0; +} + +static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev, + struct msm_vpe_buff_queue_info_t *buff_queue_info) +{ + struct msm_vpe_buffer_map_list_t *buff, *save; + struct list_head *buff_head; + + buff_head = &buff_queue_info->native_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_vpe_dequeue_buffer_info(vpe_dev, buff); + } + + buff_head = &buff_queue_info->vb2_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_vpe_dequeue_buffer_info(vpe_dev, buff); + } + + return 0; +} + +static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev, + uint16_t session_id, uint16_t stream_id) +{ + uint32_t i; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + for (i = 0; i < vpe_dev->num_buffq; i++) { + if (vpe_dev->buff_queue[i].used == 0) { + buff_queue_info = &vpe_dev->buff_queue[i]; + buff_queue_info->used = 1; + buff_queue_info->session_id = session_id; + buff_queue_info->stream_id = stream_id; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; + } + } + pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", + session_id, stream_id); + return -EINVAL; +} + +static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev, + uint32_t session_id, uint32_t stream_id) +{ + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return -EINVAL; + } + + buff_queue_info->used = 0; + buff_queue_info->session_id = 0; + buff_queue_info->stream_id = 0; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; +} + +static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev, + uint32_t num_buffq) +{ + struct msm_vpe_buff_queue_info_t *buff_queue; + buff_queue = kzalloc( + sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq, + GFP_KERNEL); + if (!buff_queue) { + pr_err("Buff queue allocation failure\n"); + return -ENOMEM; + } + + if (vpe_dev->buff_queue) { + pr_err("Buff queue not empty\n"); + kzfree(buff_queue); + return -EINVAL; + } else { + vpe_dev->buff_queue = buff_queue; + vpe_dev->num_buffq = num_buffq; + } + return 0; +} + +static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev) +{ + uint32_t i; + + for (i = 0; i < vpe_dev->num_buffq; i++) { + if (vpe_dev->buff_queue[i].used == 1) { + pr_err("Queue not free sessionid: %d, streamid: %d\n", + vpe_dev->buff_queue[i].session_id, + vpe_dev->buff_queue[i].stream_id); + msm_vpe_free_buff_queue_entry(vpe_dev, + vpe_dev->buff_queue[i].session_id, + vpe_dev->buff_queue[i].stream_id); + } + } + kzfree(vpe_dev->buff_queue); + vpe_dev->buff_queue = NULL; + vpe_dev->num_buffq = 0; + return; +} + +void vpe_release_ion_client(struct kref *ref) +{ + struct vpe_device *vpe_dev = container_of(ref, + struct vpe_device, refcount); + ion_client_destroy(vpe_dev->client); +} + +static int vpe_init_mem(struct vpe_device *vpe_dev) +{ + kref_init(&vpe_dev->refcount); + kref_get(&vpe_dev->refcount); + vpe_dev->client = msm_ion_client_create("vpe"); + + if (!vpe_dev->client) { + pr_err("couldn't create ion client\n"); + return -ENODEV; + } + + return 0; +} + +static void vpe_deinit_mem(struct vpe_device *vpe_dev) +{ + kref_put(&vpe_dev->refcount, vpe_release_ion_client); +} + +static irqreturn_t msm_vpe_irq(int irq_num, void *data) +{ + unsigned long flags; + uint32_t irq_status; + struct msm_vpe_tasklet_queue_cmd *queue_cmd; + struct vpe_device *vpe_dev = (struct vpe_device *) data; + + irq_status = msm_camera_io_r_mb(vpe_dev->base + + VPE_INTR_STATUS_OFFSET); + + spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); + queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx]; + if (queue_cmd->cmd_used) { + VPE_DBG("%s: vpe tasklet queue overflow\n", __func__); + list_del(&queue_cmd->list); + } else { + atomic_add(1, &vpe_dev->irq_cnt); + } + queue_cmd->irq_status = irq_status; + + queue_cmd->cmd_used = 1; + vpe_dev->taskletq_idx = + (vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE; + list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q); + spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); + + tasklet_schedule(&vpe_dev->vpe_tasklet); + + msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); + msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); + VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status); + + return IRQ_HANDLED; +} + +static void msm_vpe_do_tasklet(unsigned long data) +{ + unsigned long flags; + struct vpe_device *vpe_dev = (struct vpe_device *)data; + struct msm_vpe_tasklet_queue_cmd *queue_cmd; + + while (atomic_read(&vpe_dev->irq_cnt)) { + spin_lock_irqsave(&vpe_dev->tasklet_lock, flags); + queue_cmd = list_first_entry(&vpe_dev->tasklet_q, + struct msm_vpe_tasklet_queue_cmd, list); + if (!queue_cmd) { + atomic_set(&vpe_dev->irq_cnt, 0); + spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); + return; + } + atomic_sub(1, &vpe_dev->irq_cnt); + list_del(&queue_cmd->list); + queue_cmd->cmd_used = 0; + + spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags); + + VPE_DBG("Frame done!!\n"); + msm_vpe_notify_frame_done(vpe_dev); + } +} + +static int vpe_init_hardware(struct vpe_device *vpe_dev) +{ + int rc = 0; + + if (vpe_dev->fs_vpe == NULL) { + vpe_dev->fs_vpe = + regulator_get(&vpe_dev->pdev->dev, "vdd"); + if (IS_ERR(vpe_dev->fs_vpe)) { + pr_err("Regulator vpe vdd get failed %ld\n", + PTR_ERR(vpe_dev->fs_vpe)); + vpe_dev->fs_vpe = NULL; + rc = -ENODEV; + goto fail; + } else if (regulator_enable(vpe_dev->fs_vpe)) { + pr_err("Regulator vpe vdd enable failed\n"); + regulator_put(vpe_dev->fs_vpe); + vpe_dev->fs_vpe = NULL; + rc = -ENODEV; + goto fail; + } + } + + rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, + vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1); + if (rc < 0) { + pr_err("clk enable failed\n"); + goto disable_and_put_regulator; + } + + vpe_dev->base = ioremap(vpe_dev->mem->start, + resource_size(vpe_dev->mem)); + if (!vpe_dev->base) { + rc = -ENOMEM; + pr_err("ioremap failed\n"); + goto disable_and_put_regulator; + } + + if (vpe_dev->state != VPE_STATE_BOOT) { + rc = request_irq(vpe_dev->irq->start, msm_vpe_irq, + IRQF_TRIGGER_RISING, + "vpe", vpe_dev); + if (rc < 0) { + pr_err("irq request fail! start=%u\n", + (uint32_t) vpe_dev->irq->start); + rc = -EBUSY; + goto unmap_base; + } else { + VPE_DBG("Got irq! %d\n", (int)vpe_dev->irq->start); + } + } else { + VPE_DBG("Skip requesting the irq since device is booting\n"); + } + vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); + + msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE); + return rc; + +unmap_base: + iounmap(vpe_dev->base); +disable_and_put_regulator: + regulator_disable(vpe_dev->fs_vpe); + regulator_put(vpe_dev->fs_vpe); +fail: + return rc; +} + +static int vpe_release_hardware(struct vpe_device *vpe_dev) +{ + if (vpe_dev->state != VPE_STATE_BOOT) { + free_irq(vpe_dev->irq->start, vpe_dev); + tasklet_kill(&vpe_dev->vpe_tasklet); + atomic_set(&vpe_dev->irq_cnt, 0); + } + + msm_vpe_delete_buff_queue(vpe_dev); + iounmap(vpe_dev->base); + msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info, + vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0); + return 0; +} + +static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + int rc = 0; + uint32_t i; + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + + mutex_lock(&vpe_dev->mutex); + if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) { + pr_err("No free VPE instance\n"); + rc = -ENODEV; + goto err_mutex_unlock; + } + + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].active == 0) { + vpe_dev->vpe_subscribe_list[i].active = 1; + vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh; + break; + } + } + if (i == MAX_ACTIVE_VPE_INSTANCE) { + pr_err("No free instance\n"); + rc = -ENODEV; + goto err_mutex_unlock; + } + + VPE_DBG("open %d %p\n", i, &fh->vfh); + vpe_dev->vpe_open_cnt++; + if (vpe_dev->vpe_open_cnt == 1) { + rc = vpe_init_hardware(vpe_dev); + if (rc < 0) { + pr_err("%s: Couldn't init vpe hardware\n", __func__); + vpe_dev->vpe_open_cnt--; + goto err_fixup_sub_list; + } + rc = vpe_init_mem(vpe_dev); + if (rc < 0) { + pr_err("%s: Couldn't init mem\n", __func__); + vpe_dev->vpe_open_cnt--; + rc = -ENODEV; + goto err_release_hardware; + } + vpe_dev->state = VPE_STATE_IDLE; + } + mutex_unlock(&vpe_dev->mutex); + + return rc; + +err_release_hardware: + vpe_release_hardware(vpe_dev); +err_fixup_sub_list: + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { + vpe_dev->vpe_subscribe_list[i].active = 0; + vpe_dev->vpe_subscribe_list[i].vfh = NULL; + break; + } + } +err_mutex_unlock: + mutex_unlock(&vpe_dev->mutex); + return rc; +} + +static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + uint32_t i; + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + mutex_lock(&vpe_dev->mutex); + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) { + vpe_dev->vpe_subscribe_list[i].active = 0; + vpe_dev->vpe_subscribe_list[i].vfh = NULL; + break; + } + } + if (i == MAX_ACTIVE_VPE_INSTANCE) { + pr_err("Invalid close\n"); + mutex_unlock(&vpe_dev->mutex); + return -ENODEV; + } + + VPE_DBG("close %d %p\n", i, &fh->vfh); + vpe_dev->vpe_open_cnt--; + if (vpe_dev->vpe_open_cnt == 0) { + vpe_deinit_mem(vpe_dev); + vpe_release_hardware(vpe_dev); + vpe_dev->state = VPE_STATE_OFF; + } + mutex_unlock(&vpe_dev->mutex); + return 0; +} + +static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = { + .open = vpe_open_node, + .close = vpe_close_node, +}; + +static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev, + uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) +{ + int rc = -EINVAL; + + rc = v4l2_subdev_call(vpe_dev->buf_mgr_subdev, core, ioctl, + buff_mgr_ops, buff_mgr_info); + if (rc < 0) + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; +} + +static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev) +{ + struct v4l2_event v4l2_evt; + struct msm_queue_cmd *frame_qcmd; + struct msm_queue_cmd *event_qcmd; + struct msm_vpe_frame_info_t *processed_frame; + struct msm_device_queue *queue = &vpe_dev->processing_q; + struct msm_buf_mngr_info buff_mgr_info; + int rc = 0; + + if (queue->len > 0) { + frame_qcmd = msm_dequeue(queue, list_frame); + processed_frame = frame_qcmd->command; + do_gettimeofday(&(processed_frame->out_time)); + kfree(frame_qcmd); + event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); + if (!event_qcmd) { + pr_err("%s: Insufficient memory\n", __func__); + return -ENOMEM; + } + atomic_set(&event_qcmd->on_heap, 1); + event_qcmd->command = processed_frame; + VPE_DBG("fid %d\n", processed_frame->frame_id); + msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata); + + if (!processed_frame->output_buffer_info.processed_divert) { + memset(&buff_mgr_info, 0 , + sizeof(buff_mgr_info)); + buff_mgr_info.session_id = + ((processed_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = + (processed_frame->identity & 0xFFFF); + buff_mgr_info.frame_id = processed_frame->frame_id; + buff_mgr_info.timestamp = processed_frame->timestamp; + buff_mgr_info.index = + processed_frame->output_buffer_info.index; + rc = msm_vpe_buffer_ops(vpe_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n", + __func__); + rc = -EINVAL; + } + } + + v4l2_evt.id = processed_frame->inst_id; + v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE; + v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt); + } + return rc; +} + +static void vpe_update_scaler_params(struct vpe_device *vpe_dev, + struct msm_vpe_frame_strip_info strip_info) +{ + uint32_t out_ROI_width, out_ROI_height; + uint32_t src_ROI_width, src_ROI_height; + + /* + * phase_step_x, phase_step_y, phase_init_x and phase_init_y + * are represented in fixed-point, unsigned 3.29 format + */ + uint32_t phase_step_x = 0; + uint32_t phase_step_y = 0; + uint32_t phase_init_x = 0; + uint32_t phase_init_y = 0; + + uint32_t src_roi, src_x, src_y, src_xy, temp; + uint32_t yscale_filter_sel, xscale_filter_sel; + uint32_t scale_unit_sel_x, scale_unit_sel_y; + uint64_t numerator, denominator; + + /* + * assumption is both direction need zoom. this can be + * improved. + */ + temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3; + msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET); + + src_ROI_width = strip_info.src_w; + src_ROI_height = strip_info.src_h; + out_ROI_width = strip_info.dst_w; + out_ROI_height = strip_info.dst_h; + + VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n", + src_ROI_width, src_ROI_height, out_ROI_width, + out_ROI_height); + src_roi = (src_ROI_height << 16) + src_ROI_width; + + msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET); + + src_x = strip_info.src_x; + src_y = strip_info.src_y; + + VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y); + + src_xy = src_y*(1<<16) + src_x; + msm_camera_io_w(src_xy, vpe_dev->base + + VPE_SRC_XY_OFFSET); + VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi); + + /* decide whether to use FIR or M/N for scaling */ + if ((out_ROI_width == 1 && src_ROI_width < 4) || + (src_ROI_width < 4 * out_ROI_width - 3)) + scale_unit_sel_x = 0;/* use FIR scalar */ + else + scale_unit_sel_x = 1;/* use M/N scalar */ + + if ((out_ROI_height == 1 && src_ROI_height < 4) || + (src_ROI_height < 4 * out_ROI_height - 3)) + scale_unit_sel_y = 0;/* use FIR scalar */ + else + scale_unit_sel_y = 1;/* use M/N scalar */ + + /* calculate phase step for the x direction */ + + /* + * if destination is only 1 pixel wide, the value of + * phase_step_x is unimportant. Assigning phase_step_x to src + * ROI width as an arbitrary value. + */ + if (out_ROI_width == 1) + phase_step_x = (uint32_t) ((src_ROI_width) << + SCALER_PHASE_BITS); + + /* if using FIR scalar */ + else if (scale_unit_sel_x == 0) { + + /* + * Calculate the quotient ( src_ROI_width - 1 ) ( + * out_ROI_width - 1) with u3.29 precision. Quotient + * is rounded up to the larger 29th decimal point + */ + numerator = (uint64_t)(src_ROI_width - 1) << + SCALER_PHASE_BITS; + /* + * never equals to 0 because of the "(out_ROI_width == + * 1 )" + */ + denominator = (uint64_t)(out_ROI_width - 1); + /* + * divide and round up to the larger 29th decimal + * point. + */ + phase_step_x = (uint32_t) vpe_do_div((numerator + + denominator - 1), denominator); + } else if (scale_unit_sel_x == 1) { /* if M/N scalar */ + /* + * Calculate the quotient ( src_ROI_width ) / ( + * out_ROI_width) with u3.29 precision. Quotient is + * rounded down to the smaller 29th decimal point. + */ + numerator = (uint64_t)(src_ROI_width) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_width); + phase_step_x = + (uint32_t) vpe_do_div(numerator, denominator); + } + /* calculate phase step for the y direction */ + + /* + * if destination is only 1 pixel wide, the value of + * phase_step_x is unimportant. Assigning phase_step_x to src + * ROI width as an arbitrary value. + */ + if (out_ROI_height == 1) + phase_step_y = + (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS); + + /* if FIR scalar */ + else if (scale_unit_sel_y == 0) { + /* + * Calculate the quotient ( src_ROI_height - 1 ) / ( + * out_ROI_height - 1) with u3.29 precision. Quotient + * is rounded up to the larger 29th decimal point. + */ + numerator = (uint64_t)(src_ROI_height - 1) << + SCALER_PHASE_BITS; + /* + * never equals to 0 because of the " ( out_ROI_height + * == 1 )" case + */ + denominator = (uint64_t)(out_ROI_height - 1); + /* + * Quotient is rounded up to the larger 29th decimal + * point. + */ + phase_step_y = + (uint32_t) vpe_do_div( + (numerator + denominator - 1), denominator); + } else if (scale_unit_sel_y == 1) { /* if M/N scalar */ + /* + * Calculate the quotient ( src_ROI_height ) ( + * out_ROI_height) with u3.29 precision. Quotient is + * rounded down to the smaller 29th decimal point. + */ + numerator = (uint64_t)(src_ROI_height) << + SCALER_PHASE_BITS; + denominator = (uint64_t)(out_ROI_height); + phase_step_y = (uint32_t) vpe_do_div( + numerator, denominator); + } + + /* decide which set of FIR coefficients to use */ + if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) + xscale_filter_sel = 0; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) + xscale_filter_sel = 1; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) + xscale_filter_sel = 2; + else + xscale_filter_sel = 3; + + if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) + yscale_filter_sel = 0; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) + yscale_filter_sel = 1; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) + yscale_filter_sel = 2; + else + yscale_filter_sel = 3; + + /* calculate phase init for the x direction */ + + /* if using FIR scalar */ + if (scale_unit_sel_x == 0) { + if (out_ROI_width == 1) + phase_init_x = + (uint32_t) ((src_ROI_width - 1) << + SCALER_PHASE_BITS); + else + phase_init_x = 0; + } else if (scale_unit_sel_x == 1) /* M over N scalar */ + phase_init_x = 0; + + /* + * calculate phase init for the y direction if using FIR + * scalar + */ + if (scale_unit_sel_y == 0) { + if (out_ROI_height == 1) + phase_init_y = + (uint32_t) ((src_ROI_height - + 1) << SCALER_PHASE_BITS); + else + phase_init_y = 0; + } else if (scale_unit_sel_y == 1) /* M over N scalar */ + phase_init_y = 0; + + strip_info.phase_step_x = phase_step_x; + strip_info.phase_step_y = phase_step_y; + strip_info.phase_init_x = phase_init_x; + strip_info.phase_init_y = phase_init_y; + VPE_DBG("phase step x = %d, step y = %d.\n", + strip_info.phase_step_x, strip_info.phase_step_y); + VPE_DBG("phase init x = %d, init y = %d.\n", + strip_info.phase_init_x, strip_info.phase_init_y); + + msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base + + VPE_SCALE_PHASEX_STEP_OFFSET); + msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base + + VPE_SCALE_PHASEY_STEP_OFFSET); + + msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base + + VPE_SCALE_PHASEX_INIT_OFFSET); + msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base + + VPE_SCALE_PHASEY_INIT_OFFSET); +} + +static void vpe_program_buffer_addresses( + struct vpe_device *vpe_dev, + unsigned long srcP0, + unsigned long srcP1, + unsigned long outP0, + unsigned long outP1) +{ + VPE_DBG("%s VPE Configured with:\n" + "Src %x, %x Dest %x, %x", + __func__, (uint32_t)srcP0, (uint32_t)srcP1, + (uint32_t)outP0, (uint32_t)outP1); + + msm_camera_io_w(srcP0, vpe_dev->base + VPE_SRCP0_ADDR_OFFSET); + msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET); + msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET); + msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET); +} + +static int vpe_start(struct vpe_device *vpe_dev) +{ + /* enable the frame irq, bit 0 = Display list 0 ROI done */ + msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); + msm_camera_io_dump(vpe_dev->base, 0x120); + msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18); + msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250); + msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20); + msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30); + msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10); + + /* + * This triggers the operation. When the VPE is done, + * msm_vpe_irq will fire. + */ + msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET); + return 0; +} + +static void vpe_config_axi_default(struct vpe_device *vpe_dev) +{ + msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET); +} + +static int vpe_reset(struct vpe_device *vpe_dev) +{ + uint32_t vpe_version; + uint32_t rc = 0; + + vpe_version = msm_camera_io_r( + vpe_dev->base + VPE_HW_VERSION_OFFSET); + VPE_DBG("vpe_version = 0x%x\n", vpe_version); + /* disable all interrupts.*/ + msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET); + /* clear all pending interrupts*/ + msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET); + /* write sw_reset to reset the core. */ + msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET); + /* then poll the reset bit, it should be self-cleared. */ + while (1) { + rc = msm_camera_io_r(vpe_dev->base + VPE_SW_RESET_OFFSET) \ + & 0x10; + if (rc == 0) + break; + cpu_relax(); + } + /* + * at this point, hardware is reset. Then pogram to default + * values. + */ + msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE, + vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET); + + msm_camera_io_w(VPE_CGC_ENABLE_VALUE, + vpe_dev->base + VPE_CGC_EN_OFFSET); + msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET); + msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE, + vpe_dev->base + VPE_OP_MODE_OFFSET); + msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG, + vpe_dev->base + VPE_SCALE_CONFIG_OFFSET); + vpe_config_axi_default(vpe_dev); + return rc; +} + +static void vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p) +{ + uint32_t i, offset; + offset = *p; + for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) { + VPE_DBG("Setting scale table %d\n", i); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_SCALE_COEFF_LSBn(i)); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_SCALE_COEFF_MSBn(i)); + } +} + +static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p) +{ + msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET); +} + +static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p) +{ + msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET); + msm_camera_io_w(*(++p), + vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET); + msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET); +} + +static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p) +{ + msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET); +} + +/** + * msm_vpe_transaction_setup() - send setup for one frame to VPE + * @vpe_dev: vpe device + * @data: packed setup commands + * + * See msm_vpe.h for the expected format of `data' + */ +static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data) +{ + int i; + void *iter = data; + + vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN); + + for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) { + vpe_update_scale_coef(vpe_dev, (uint32_t *)iter); + iter += VPE_SCALER_CONFIG_LEN; + } + vpe_input_plane_config(vpe_dev, (uint32_t *)iter); + iter += VPE_INPUT_PLANE_CFG_LEN; + vpe_output_plane_config(vpe_dev, (uint32_t *)iter); + iter += VPE_OUTPUT_PLANE_CFG_LEN; + vpe_operation_config(vpe_dev, (uint32_t *)iter); +} + +static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev, + struct msm_queue_cmd *frame_qcmd) +{ + struct msm_vpe_frame_info_t *process_frame; + + if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) { + process_frame = frame_qcmd->command; + msm_enqueue(&vpe_dev->processing_q, + &frame_qcmd->list_frame); + + vpe_update_scaler_params(vpe_dev, process_frame->strip_info); + vpe_program_buffer_addresses( + vpe_dev, + process_frame->src_phyaddr, + process_frame->src_phyaddr + + process_frame->src_chroma_plane_offset, + process_frame->dest_phyaddr, + process_frame->dest_phyaddr + + process_frame->dest_chroma_plane_offset); + vpe_start(vpe_dev); + do_gettimeofday(&(process_frame->in_time)); + } + return 0; +} + +static int msm_vpe_cfg(struct vpe_device *vpe_dev, + struct msm_camera_v4l2_ioctl_t *ioctl_ptr) +{ + int rc = 0; + struct msm_queue_cmd *frame_qcmd = NULL; + struct msm_vpe_frame_info_t *new_frame = + kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL); + unsigned long in_phyaddr, out_phyaddr; + struct msm_buf_mngr_info buff_mgr_info; + + if (!new_frame) { + pr_err("Insufficient memory. return\n"); + return -ENOMEM; + } + + rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr, + sizeof(struct msm_vpe_frame_info_t)); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + rc = -EINVAL; + goto err_free_new_frame; + } + + in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, + &new_frame->input_buffer_info, + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF)); + if (!in_phyaddr) { + pr_err("error gettting input physical address\n"); + rc = -EINVAL; + goto err_free_new_frame; + } + + memset(&new_frame->output_buffer_info, 0, + sizeof(struct msm_vpe_buffer_info_t)); + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); + rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &buff_mgr_info); + if (rc < 0) { + pr_err("error getting buffer\n"); + rc = -EINVAL; + goto err_free_new_frame; + } + + new_frame->output_buffer_info.index = buff_mgr_info.index; + out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev, + &new_frame->output_buffer_info, + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF)); + if (!out_phyaddr) { + pr_err("error gettting output physical address\n"); + rc = -EINVAL; + goto err_put_buf; + } + + new_frame->src_phyaddr = in_phyaddr; + new_frame->dest_phyaddr = out_phyaddr; + + frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL); + if (!frame_qcmd) { + pr_err("Insufficient memory. return\n"); + rc = -ENOMEM; + goto err_put_buf; + } + + atomic_set(&frame_qcmd->on_heap, 1); + frame_qcmd->command = new_frame; + rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd); + if (rc < 0) { + pr_err("error cannot send frame to hardware\n"); + rc = -EINVAL; + goto err_free_frame_qcmd; + } + + return rc; + +err_free_frame_qcmd: + kfree(frame_qcmd); +err_put_buf: + msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &buff_mgr_info); +err_free_new_frame: + kfree(new_frame); + return rc; +} + +static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + int rc = 0; + + mutex_lock(&vpe_dev->mutex); + switch (cmd) { + case VIDIOC_MSM_VPE_TRANSACTION_SETUP: { + struct msm_vpe_transaction_setup_cfg *cfg; + VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n"); + if (sizeof(*cfg) != ioctl_ptr->len) { + pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d", + __func__, cmd, ioctl_ptr->len, + sizeof(*cfg)); + rc = -EINVAL; + break; + } + + cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL); + if (!cfg) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + kfree(cfg); + break; + } + + msm_vpe_transaction_setup(vpe_dev, (void *)cfg); + kfree(cfg); + break; + } + case VIDIOC_MSM_VPE_CFG: { + VPE_DBG("VIDIOC_MSM_VPE_CFG\n"); + rc = msm_vpe_cfg(vpe_dev, ioctl_ptr); + break; + } + case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: { + struct msm_vpe_stream_buff_info_t *u_stream_buff_info; + struct msm_vpe_stream_buff_info_t k_stream_buff_info; + + VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n"); + + if (sizeof(struct msm_vpe_stream_buff_info_t) != + ioctl_ptr->len) { + pr_err("%s:%d: invalid length\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); + if (!u_stream_buff_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(u_stream_buff_info, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + if ((u_stream_buff_info->num_buffs == 0) || + (u_stream_buff_info->num_buffs > + MSM_CAMERA_MAX_STREAM_BUF)) { + pr_err("%s:%d: Invalid number of buffers\n", __func__, + __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; + k_stream_buff_info.identity = u_stream_buff_info->identity; + k_stream_buff_info.buffer_info = + kzalloc(k_stream_buff_info.num_buffs * + sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL); + if (!k_stream_buff_info.buffer_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(k_stream_buff_info.buffer_info, + (void __user *)u_stream_buff_info->buffer_info, + k_stream_buff_info.num_buffs * + sizeof(struct msm_vpe_buffer_info_t)) ? + -EFAULT : 0); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = msm_vpe_add_buff_queue_entry(vpe_dev, + ((k_stream_buff_info.identity >> 16) & 0xFFFF), + (k_stream_buff_info.identity & 0xFFFF)); + if (!rc) + rc = msm_vpe_enqueue_buff_info_list(vpe_dev, + &k_stream_buff_info); + + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + break; + } + case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: { + uint32_t identity; + struct msm_vpe_buff_queue_info_t *buff_queue_info; + + VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n"); + if (ioctl_ptr->len != sizeof(uint32_t)) { + pr_err("%s:%d Invalid len\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(&identity, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + pr_err("%s:%d copy from user\n", __func__, __LINE__); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, + ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for identity:%d\n", + identity); + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info); + rc = msm_vpe_free_buff_queue_entry(vpe_dev, + buff_queue_info->session_id, + buff_queue_info->stream_id); + break; + } + case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: { + struct msm_device_queue *queue = &vpe_dev->eventData_q; + struct msm_queue_cmd *event_qcmd; + struct msm_vpe_frame_info_t *process_frame; + VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n"); + event_qcmd = msm_dequeue(queue, list_eventdata); + process_frame = event_qcmd->command; + VPE_DBG("fid %d\n", process_frame->frame_id); + if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr, + process_frame, + sizeof(struct msm_vpe_frame_info_t))) { + mutex_unlock(&vpe_dev->mutex); + return -EINVAL; + } + + kfree(process_frame); + kfree(event_qcmd); + break; + } + } + mutex_unlock(&vpe_dev->mutex); + return rc; +} + +static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS, NULL); +} + +static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = { + .ioctl = msm_vpe_subdev_ioctl, + .subscribe_event = msm_vpe_subscribe_event, + .unsubscribe_event = msm_vpe_unsubscribe_event, +}; + +static const struct v4l2_subdev_ops msm_vpe_subdev_ops = { + .core = &msm_vpe_subdev_core_ops, +}; + +static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops; + +static long msm_vpe_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + + switch (cmd) { + case VIDIOC_DQEVENT: + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); + + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + case VIDIOC_MSM_VPE_GET_INST_INFO: { + uint32_t i; + struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd); + struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg; + struct msm_vpe_frame_info_t inst_info; + memset(&inst_info, 0, sizeof(struct msm_vpe_frame_info_t)); + for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) { + if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) { + inst_info.inst_id = i; + break; + } + } + if (copy_to_user( + (void __user *)ioctl_ptr->ioctl_ptr, &inst_info, + sizeof(struct msm_vpe_frame_info_t))) { + return -EINVAL; + } + } + default: + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); + } + + return 0; +} + +static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl); +} + +static int vpe_register_domain(void) +{ + struct msm_iova_partition vpe_iommu_partition = { + /* TODO: verify that these are correct? */ + .start = SZ_128K, + .size = SZ_2G - SZ_128K, + }; + struct msm_iova_layout vpe_iommu_layout = { + .partitions = &vpe_iommu_partition, + .npartitions = 1, + .client_name = "camera_vpe", + .domain_flags = 0, + }; + + return msm_register_domain(&vpe_iommu_layout); +} + +static int vpe_probe(struct platform_device *pdev) +{ + struct vpe_device *vpe_dev; + int rc = 0; + + vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL); + if (!vpe_dev) { + pr_err("not enough memory\n"); + return -ENOMEM; + } + + vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) * + ARRAY_SIZE(vpe_clk_info), GFP_KERNEL); + if (!vpe_dev->vpe_clk) { + pr_err("not enough memory\n"); + rc = -ENOMEM; + goto err_free_vpe_dev; + } + + v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops); + vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops; + snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name), + "vpe"); + vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev); + platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd); + mutex_init(&vpe_dev->mutex); + spin_lock_init(&vpe_dev->tasklet_lock); + + vpe_dev->pdev = pdev; + + vpe_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "vpe"); + if (!vpe_dev->mem) { + pr_err("no mem resource?\n"); + rc = -ENODEV; + goto err_free_vpe_clk; + } + + vpe_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "vpe"); + if (!vpe_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + vpe_dev->domain_num = vpe_register_domain(); + if (vpe_dev->domain_num < 0) { + pr_err("%s: could not register domain\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + vpe_dev->domain = + msm_get_iommu_domain(vpe_dev->domain_num); + if (!vpe_dev->domain) { + pr_err("%s: cannot find domain\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src"); + vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst"); + if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) { + pr_err("%s: cannot get iommu_ctx\n", __func__); + rc = -ENODEV; + goto err_release_mem; + } + + media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0); + vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE; + vpe_dev->msm_sd.sd.entity.name = pdev->name; + msm_sd_register(&vpe_dev->msm_sd); + msm_vpe_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner; + msm_vpe_v4l2_subdev_fops.open = v4l2_subdev_fops.open; + msm_vpe_v4l2_subdev_fops.unlocked_ioctl = msm_vpe_subdev_fops_ioctl; + msm_vpe_v4l2_subdev_fops.release = v4l2_subdev_fops.release; + msm_vpe_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll; + + vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops; + vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num; + vpe_dev->state = VPE_STATE_BOOT; + rc = vpe_init_hardware(vpe_dev); + if (rc < 0) { + pr_err("%s: Couldn't init vpe hardware\n", __func__); + goto err_unregister_sd; + } + vpe_reset(vpe_dev); + vpe_release_hardware(vpe_dev); + vpe_dev->state = VPE_STATE_OFF; + + rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); + if (rc < 0) { + pr_err("Couldn't attach to vpe_src context bank\n"); + rc = -ENODEV; + goto err_unregister_sd; + } + rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); + if (rc < 0) { + pr_err("Couldn't attach to vpe_dst context bank\n"); + rc = -ENODEV; + goto err_detach_src; + } + + vpe_dev->state = VPE_STATE_OFF; + + msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata"); + msm_queue_init(&vpe_dev->processing_q, "vpe-frame"); + INIT_LIST_HEAD(&vpe_dev->tasklet_q); + tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet, + (unsigned long)vpe_dev); + vpe_dev->vpe_open_cnt = 0; + + return rc; + +err_detach_src: + iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); +err_unregister_sd: + msm_sd_unregister(&vpe_dev->msm_sd); +err_release_mem: + release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); +err_free_vpe_clk: + kfree(vpe_dev->vpe_clk); +err_free_vpe_dev: + kfree(vpe_dev); + return rc; +} + +static int vpe_device_remove(struct platform_device *dev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(dev); + struct vpe_device *vpe_dev; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd); + if (!vpe_dev) { + pr_err("%s: vpe device is NULL\n", __func__); + return 0; + } + + iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst); + iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src); + msm_sd_unregister(&vpe_dev->msm_sd); + release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem)); + mutex_destroy(&vpe_dev->mutex); + kfree(vpe_dev); + return 0; +} + +static struct platform_driver vpe_driver = { + .probe = vpe_probe, + .remove = vpe_device_remove, + .driver = { + .name = MSM_VPE_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_vpe_init_module(void) +{ + return platform_driver_register(&vpe_driver); +} + +static void __exit msm_vpe_exit_module(void) +{ + platform_driver_unregister(&vpe_driver); +} + +module_init(msm_vpe_init_module); +module_exit(msm_vpe_exit_module); +MODULE_DESCRIPTION("MSM VPE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/msm_vpe.h new file mode 100644 index 0000000000000000000000000000000000000000..1a8508963493dc80fe311a45f2d95c3f1ad2751e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/pproc/vpe/msm_vpe.h @@ -0,0 +1,255 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_VPE_H__ +#define __MSM_VPE_H__ + +#include +#include +#include +#include +#include +#include "msm_sd.h" + +/*********** start of register offset *********************/ +#define VPE_INTR_ENABLE_OFFSET 0x0020 +#define VPE_INTR_STATUS_OFFSET 0x0024 +#define VPE_INTR_CLEAR_OFFSET 0x0028 +#define VPE_DL0_START_OFFSET 0x0030 +#define VPE_HW_VERSION_OFFSET 0x0070 +#define VPE_SW_RESET_OFFSET 0x0074 +#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078 +#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C +#define VPE_CGC_EN_OFFSET 0x0100 +#define VPE_CMD_STATUS_OFFSET 0x10008 +#define VPE_PROFILE_EN_OFFSET 0x10010 +#define VPE_PROFILE_COUNT_OFFSET 0x10014 +#define VPE_CMD_MODE_OFFSET 0x10060 +#define VPE_SRC_SIZE_OFFSET 0x10108 +#define VPE_SRCP0_ADDR_OFFSET 0x1010C +#define VPE_SRCP1_ADDR_OFFSET 0x10110 +#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C +#define VPE_SRC_FORMAT_OFFSET 0x10124 +#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128 +#define VPE_OP_MODE_OFFSET 0x10138 +#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C +#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140 +#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144 +#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148 +#define VPE_OUT_FORMAT_OFFSET 0x10150 +#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154 +#define VPE_OUT_SIZE_OFFSET 0x10164 +#define VPE_OUTP0_ADDR_OFFSET 0x10168 +#define VPE_OUTP1_ADDR_OFFSET 0x1016C +#define VPE_OUT_YSTRIDE1_OFFSET 0x10178 +#define VPE_OUT_XY_OFFSET 0x1019C +#define VPE_SRC_XY_OFFSET 0x10200 +#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208 +#define VPE_SCALE_CONFIG_OFFSET 0x10230 +#define VPE_DEINT_STATUS_OFFSET 0x30000 +#define VPE_DEINT_DECISION_OFFSET 0x30004 +#define VPE_DEINT_COEFF0_OFFSET 0x30010 +#define VPE_SCALE_STATUS_OFFSET 0x50000 +#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010 +#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020 +#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400 +#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404 + +#define VPE_AXI_ARB_1_OFFSET 0x00408 +#define VPE_AXI_ARB_2_OFFSET 0x0040C + +#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n)) +#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n)) +#define VPE_SCALE_COEFF_NUM 32 + +/*********** end of register offset ********************/ + + +#define VPE_HARDWARE_VERSION 0x00080308 +#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/ +#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924 +#define VPE_CMD_MODE_VALUE 0x1 +#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004 +#define VPE_CGC_ENABLE_VALUE 0xffff +#define VPE_DEFAULT_SCALE_CONFIG 0x3c + +#define VPE_NORMAL_MODE_CLOCK_RATE 150000000 +#define VPE_TURBO_MODE_CLOCK_RATE 200000000 +#define VPE_SUBDEV_MAX_EVENTS 30 + +/**************************************************/ +/*********** End of command id ********************/ +/**************************************************/ + +#define SCALER_PHASE_BITS 29 +#define HAL_MDP_PHASE_STEP_2P50 0x50000000 +#define HAL_MDP_PHASE_STEP_1P66 0x35555555 +#define HAL_MDP_PHASE_STEP_1P25 0x28000000 + + +#define MAX_ACTIVE_VPE_INSTANCE 8 +#define MAX_VPE_PROCESSING_FRAME 2 +#define MAX_VPE_V4l2_EVENTS 30 + +#define MSM_VPE_TASKLETQ_SIZE 16 + +/** + * The format of the msm_vpe_transaction_setup_cfg is as follows: + * + * - vpe_update_scale_coef (65*4 uint32_t's) + * - Each table is 65 uint32_t's long + * - 1st uint32_t in each table indicates offset + * - Following 64 uint32_t's are the data + * + * - vpe_input_plane_config (6 uint32_t's) + * - VPE_SRC_FORMAT_OFFSET + * - VPE_SRC_UNPACK_PATTERN1_OFFSET + * - VPE_SRC_IMAGE_SIZE_OFFSET + * - VPE_SRC_YSTRIDE1_OFFSET + * - VPE_SRC_SIZE_OFFSET + * - VPE_SRC_XY_OFFSET + * + * - vpe_output_plane_config (5 uint32_t's) + * - VPE_OUT_FORMAT_OFFSET + * - VPE_OUT_PACK_PATTERN1_OFFSET + * - VPE_OUT_YSTRIDE1_OFFSET + * - VPE_OUT_SIZE_OFFSET + * - VPE_OUT_XY_OFFSET + * + * - vpe_operation_config (1 uint32_t) + * - VPE_OP_MODE_OFFSET + * + */ + +#define VPE_SCALER_CONFIG_LEN 260 +#define VPE_INPUT_PLANE_CFG_LEN 24 +#define VPE_OUTPUT_PLANE_CFG_LEN 20 +#define VPE_OPERATION_MODE_CFG_LEN 4 +#define VPE_NUM_SCALER_TABLES 4 + +#define VPE_TRANSACTION_SETUP_CONFIG_LEN ( \ + (VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES) \ + + VPE_INPUT_PLANE_CFG_LEN \ + + VPE_OUTPUT_PLANE_CFG_LEN \ + + VPE_OPERATION_MODE_CFG_LEN) +/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */ + +struct msm_vpe_transaction_setup_cfg { + uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN]; +}; + +struct vpe_subscribe_info { + struct v4l2_fh *vfh; + uint32_t active; +}; + +enum vpe_state { + VPE_STATE_BOOT, + VPE_STATE_IDLE, + VPE_STATE_ACTIVE, + VPE_STATE_OFF, +}; + +struct msm_queue_cmd { + struct list_head list_config; + struct list_head list_control; + struct list_head list_frame; + struct list_head list_pict; + struct list_head list_vpe_frame; + struct list_head list_eventdata; + void *command; + atomic_t on_heap; + struct timespec ts; + uint32_t error_code; + uint32_t trans_code; +}; + +struct msm_device_queue { + struct list_head list; + spinlock_t lock; + wait_queue_head_t wait; + int max; + int len; + const char *name; +}; + +struct msm_vpe_tasklet_queue_cmd { + struct list_head list; + uint32_t irq_status; + uint8_t cmd_used; +}; + +struct msm_vpe_buffer_map_info_t { + unsigned long len; + dma_addr_t phy_addr; + struct ion_handle *ion_handle; + struct msm_vpe_buffer_info_t buff_info; +}; + +struct msm_vpe_buffer_map_list_t { + struct msm_vpe_buffer_map_info_t map_info; + struct list_head entry; +}; + +struct msm_vpe_buff_queue_info_t { + uint32_t used; + uint16_t session_id; + uint16_t stream_id; + struct list_head vb2_buff_head; + struct list_head native_buff_head; +}; + +struct vpe_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + void __iomem *base; + struct clk **vpe_clk; + struct regulator *fs_vpe; + struct mutex mutex; + enum vpe_state state; + + int domain_num; + struct iommu_domain *domain; + struct device *iommu_ctx_src; + struct device *iommu_ctx_dst; + struct ion_client *client; + struct kref refcount; + + /* Reusing proven tasklet from msm isp */ + atomic_t irq_cnt; + uint8_t taskletq_idx; + spinlock_t tasklet_lock; + struct list_head tasklet_q; + struct tasklet_struct vpe_tasklet; + struct msm_vpe_tasklet_queue_cmd + tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE]; + + struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE]; + uint32_t vpe_open_cnt; + + struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ + + /* + * Processing Queue: store frame info for frames sent to + * microcontroller + */ + struct msm_device_queue processing_q; + + struct msm_vpe_buff_queue_info_t *buff_queue; + uint32_t num_buffq; + struct v4l2_subdev *buf_mgr_subdev; +}; + +#endif /* __MSM_VPE_H__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e35948ceeb60e6b36c0152faf42dbc2422f2473f --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/Makefile @@ -0,0 +1,22 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/msm_vb2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/cci +obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/ eeprom/ +obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.o +obj-$(CONFIG_IMX132) += imx132.o +obj-$(CONFIG_IMX134) += imx134.o +obj-$(CONFIG_OV8825) += ov8825.o +obj-$(CONFIG_OV8865) += ov8865.o +obj-$(CONFIG_s5k4e1) += s5k4e1.o +obj-$(CONFIG_OV12830) += ov12830.o +obj-$(CONFIG_OV9724) += ov9724.o +obj-$(CONFIG_HI256) += hi256.o +obj-$(CONFIG_OV5648) += ov5648.o +obj-$(CONFIG_MT9M114) += mt9m114.o +obj-$(CONFIG_MT9M114) += ov5645.o +obj-$(CONFIG_SP1628) += sp1628.o +obj-$(CONFIG_GC0339) += gc0339.o + +obj-$(CONFIG_SR200PC20) += sr200pc20_yuv.o \ No newline at end of file diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3ff6ca11e6c566484fa7804096ababd32e302fe7 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/cci +obj-$(CONFIG_MSMB_CAMERA) += msm_actuator.o diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/msm_actuator.c new file mode 100644 index 0000000000000000000000000000000000000000..9ce007acdf6c8fd2b62be1d052b453e03c726c36 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/msm_actuator.c @@ -0,0 +1,1364 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ + +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include "msm_sd.h" +#include "msm_actuator.h" +#include "msm_cci.h" + +DEFINE_MSM_MUTEX(msm_actuator_mutex); + +//#define MSM_ACUTUATOR_DEBUG +#undef CDBG +#ifdef MSM_ACUTUATOR_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl); +static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl); + +static struct msm_actuator msm_vcm_actuator_table; +static struct msm_actuator msm_piezo_actuator_table; + +static struct i2c_driver msm_actuator_i2c_driver; +static struct msm_actuator *actuators[] = { + &msm_vcm_actuator_table, + &msm_piezo_actuator_table, + &msm_vcm_actuator_table, /* dummy entries */ + &msm_piezo_actuator_table, /* dummy entries */ +}; + +static int32_t msm_actuator_piezo_set_default_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t rc = 0; + struct msm_camera_i2c_reg_setting reg_setting; + CDBG("Enter\n"); + + if (a_ctrl->curr_step_pos != 0) { + a_ctrl->i2c_tbl_index = 0; + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + a_ctrl->initial_code, 0, 0); + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + a_ctrl->initial_code, 0, 0); + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + reg_setting.delay = 0; + rc = a_ctrl->i2c_client.i2c_func_tbl-> + i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("%s: i2c write error:%d\n", + __func__, rc); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + a_ctrl->curr_step_pos = 0; + } + CDBG("Exit\n"); + return rc; +} + +static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl, + int16_t next_lens_position, uint32_t hw_params, uint16_t delay) +{ + struct msm_actuator_reg_params_t *write_arr = a_ctrl->reg_tbl; + uint32_t hw_dword = hw_params; + uint16_t i2c_byte1 = 0, i2c_byte2 = 0; + uint16_t value = 0; + uint32_t size = a_ctrl->reg_tbl_size, i = 0; + struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl; + CDBG("Enter\n"); + for (i = 0; i < size; i++) { + /* check that the index into i2c_tbl cannot grow larger that + the allocated size of i2c_tbl */ + if ((a_ctrl->total_steps + 1) < (a_ctrl->i2c_tbl_index)) { + break; + } + if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) { + value = (next_lens_position << + write_arr[i].data_shift) | + ((hw_dword & write_arr[i].hw_mask) >> + write_arr[i].hw_shift); + + if (write_arr[i].reg_addr != 0xFFFF) { + i2c_byte1 = write_arr[i].reg_addr; + i2c_byte2 = value; + if (size != (i+1)) { + i2c_byte2 = value & 0xFF; + CDBG("byte1:0x%x, byte2:0x%x\n", + i2c_byte1, i2c_byte2); + i2c_tbl[a_ctrl->i2c_tbl_index]. + reg_addr = i2c_byte1; + i2c_tbl[a_ctrl->i2c_tbl_index]. + reg_data = i2c_byte2; + i2c_tbl[a_ctrl->i2c_tbl_index]. + delay = 0; + a_ctrl->i2c_tbl_index++; + i++; + i2c_byte1 = write_arr[i].reg_addr; + i2c_byte2 = (value & 0xFF00) >> 8; + } + } else { + i2c_byte1 = (value & 0xFF00) >> 8; + i2c_byte2 = value & 0xFF; + } + } else { + i2c_byte1 = write_arr[i].reg_addr; + i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >> + write_arr[i].hw_shift; + } + CDBG("i2c_byte1:0x%x, i2c_byte2:0x%x\n", i2c_byte1, i2c_byte2); + i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1; + i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2; + i2c_tbl[a_ctrl->i2c_tbl_index].delay = delay; + a_ctrl->i2c_tbl_index++; + } + CDBG("Exit\n"); +} + +static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl, + uint16_t size, struct reg_settings_t *settings) +{ + int32_t rc = -EFAULT; + int32_t i = 0; + CDBG("Enter\n"); + + for (i = 0; i < size; i++) { + switch (settings[i].i2c_operation) { + case MSM_ACT_WRITE: { + switch (settings[i].data_type) { + case MSM_ACTUATOR_BYTE_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + break; + case MSM_ACTUATOR_WORD_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_WORD_DATA); + break; + default: + pr_err("Unsupport data type: %d\n", + settings[i].i2c_operation); + break; + } + break; + } + case MSM_ACT_POLL: { + switch (settings[i].data_type) { + case MSM_ACTUATOR_BYTE_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + break; + case MSM_ACTUATOR_WORD_DATA: + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll( + &a_ctrl->i2c_client, + settings[i].reg_addr, + settings[i].reg_data, + MSM_CAMERA_I2C_WORD_DATA); + break; + default: + pr_err("Unsupport data type: %d\n", + settings[i].i2c_operation); + break; + } + break; + } + } + + if (0 != settings[i].delay) + msleep(settings[i].delay); + + if (rc < 0) + break; + } + + a_ctrl->curr_step_pos = 0; + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_vcm_init_focus(struct msm_actuator_ctrl_t *a_ctrl, + uint16_t size, struct reg_settings_t *settings) +{ + int32_t rc = -EFAULT; + int32_t i = 0; + uint16_t delay = 0; + uint16_t status_addr = 0; + uint16_t status_data = 0; + uint16_t status = 0; + uint16_t delay_count = 0; + uint16_t delay_count_limit = 0; + + CDBG("%s Enter, size %d\n", __func__, size); + + for (i = 0; i < size; i++) { + if (settings[i].reg_addr == MSM_ACTUATOR_INIT_FOCUS_DELAY) { + delay = settings[i].reg_data; + usleep_range(delay, delay + 1000); + CDBG("%s %d settings[%d].reg_addr = %d, settings[%d].reg_data = %d\n", + __func__, __LINE__,i, settings[i].reg_addr, i, settings[i].reg_data); + } + else if (settings[i].reg_addr == MSM_ACTUATOR_INIT_FOCUS_READ_STATUS) { + /* reg_data[i] = limitation for delay count for read status */ + delay_count_limit = settings[i].reg_data; + CDBG("%s %d settings[%d].reg_addr = %d, settings[%d].reg_data = %d\n", + __func__, __LINE__,i, settings[i].reg_addr, i, settings[i].reg_data); + i++; + /*reg_addr[i+1] = addr for status register*/ + status_addr = settings[i].reg_addr; + /*reg_data[i+1] = value for stopping to read the status register*/ + status_data = settings[i].reg_data; + CDBG("%s %d settings[%d].reg_addr = %d, settings[%d].reg_data = %d\n", + __func__, __LINE__,i, settings[i].reg_addr, i, settings[i].reg_data); + delay_count = 0; + do { + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &a_ctrl->i2c_client, status_addr, &status, + MSM_CAMERA_I2C_BYTE_DATA); + CDBG("%s %d status %d\n", __func__, __LINE__,status); + if (rc < 0) { + CDBG("%s Failed I2C read Line %d\n", __func__, + __LINE__); + return rc; + } + usleep_range(1000, 2000); + delay_count++; + if(delay_count >= delay_count_limit) break; + } while (status != status_data); + } + else { + CDBG("%s %d settings[%d].reg_addr = %d, settings[%d].reg_data = %d\n", + __func__, __LINE__,i, settings[i].reg_addr, i, settings[i].reg_data); + + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &a_ctrl->i2c_client, settings[i].reg_addr, + settings[i].reg_data, MSM_CAMERA_I2C_BYTE_DATA); + if(rc < 0){ + pr_err("%s:%d I2C write failure size[%d] writen[%d]\n", + __func__, __LINE__, size, i); + break; + } + } + } + + CDBG("Exit\n"); + return 0; +} + +static void msm_actuator_write_focus( + struct msm_actuator_ctrl_t *a_ctrl, + uint16_t curr_lens_pos, + struct damping_params_t *damping_params, + int8_t sign_direction, + int16_t code_boundary) +{ + int16_t next_lens_pos = 0; + uint16_t damping_code_step = 0; + uint16_t wait_time = 0; + CDBG("Enter\n"); + + damping_code_step = damping_params->damping_step; + wait_time = damping_params->damping_delay; + + /* Write code based on damping_code_step in a loop */ + for (next_lens_pos = + curr_lens_pos + (sign_direction * damping_code_step); + (sign_direction * next_lens_pos) <= + (sign_direction * code_boundary); + next_lens_pos = + (next_lens_pos + + (sign_direction * damping_code_step))) { + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + next_lens_pos, damping_params->hw_params, wait_time); + curr_lens_pos = next_lens_pos; + } + + if (curr_lens_pos != code_boundary) { + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + code_boundary, damping_params->hw_params, wait_time); + } + CDBG("Exit\n"); +} + +static int32_t msm_actuator_piezo_move_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t dest_step_position = move_params->dest_step_pos; + struct damping_params_t ringing_params_kernel; + int32_t rc = 0; + int32_t num_steps = move_params->num_steps; + struct msm_camera_i2c_reg_setting reg_setting; + CDBG("Enter\n"); + + if (copy_from_user(&ringing_params_kernel, + &(move_params->ringing_params[0]), + sizeof(struct damping_params_t))) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + + if (num_steps == 0) + return rc; + + a_ctrl->i2c_tbl_index = 0; + a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl, + (num_steps * + a_ctrl->region_params[0].code_per_step), + ringing_params_kernel.hw_params, 0); + + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + reg_setting.delay = 0; + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("i2c write error:%d\n", rc); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + a_ctrl->curr_step_pos = dest_step_position; + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_move_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t rc = 0; + struct damping_params_t ringing_params_kernel; + int8_t sign_dir = move_params->sign_dir; + uint16_t step_boundary = 0; + uint16_t target_step_pos = 0; + uint16_t target_lens_pos = 0; + int16_t dest_step_pos = move_params->dest_step_pos; + uint16_t curr_lens_pos = 0; + int dir = move_params->dir; + int32_t num_steps = move_params->num_steps; + struct msm_camera_i2c_reg_setting reg_setting; + + if (copy_from_user(&ringing_params_kernel, + &(move_params->ringing_params[a_ctrl->curr_region_index]), + sizeof(struct damping_params_t))) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + + + CDBG("called, dir %d, num_steps %d\n", dir, num_steps); + + if (dest_step_pos == a_ctrl->curr_step_pos) + return rc; + + if ((sign_dir > MSM_ACTUATOR_MOVE_SIGNED_NEAR) || + (sign_dir < MSM_ACTUATOR_MOVE_SIGNED_FAR)) { + pr_err("Invalid sign_dir = %d\n", sign_dir); + return -EFAULT; + } + if ((dir > MOVE_FAR) || (dir < MOVE_NEAR)) { + pr_err("Invalid direction = %d\n", dir); + return -EFAULT; + } + if (dest_step_pos > a_ctrl->total_steps) { + pr_err("Step pos greater than total steps = %d\n", + dest_step_pos); + return -EFAULT; + } + curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos]; + a_ctrl->i2c_tbl_index = 0; + CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n", + a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos); + + while (a_ctrl->curr_step_pos != dest_step_pos) { + step_boundary = + a_ctrl->region_params[a_ctrl->curr_region_index]. + step_bound[dir]; + if ((dest_step_pos * sign_dir) <= + (step_boundary * sign_dir)) { + + target_step_pos = dest_step_pos; + target_lens_pos = + a_ctrl->step_position_table[target_step_pos]; + a_ctrl->func_tbl->actuator_write_focus(a_ctrl, + curr_lens_pos, + &ringing_params_kernel, + sign_dir, + target_lens_pos); + curr_lens_pos = target_lens_pos; + + } else { + target_step_pos = step_boundary; + target_lens_pos = + a_ctrl->step_position_table[target_step_pos]; + a_ctrl->func_tbl->actuator_write_focus(a_ctrl, + curr_lens_pos, + &ringing_params_kernel, + sign_dir, + target_lens_pos); + curr_lens_pos = target_lens_pos; + + a_ctrl->curr_region_index += sign_dir; + } + a_ctrl->curr_step_pos = target_step_pos; + } + + move_params->curr_lens_pos = curr_lens_pos; + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + reg_setting.delay = 0; + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("i2c write error:%d\n", rc); + return rc; + } + a_ctrl->i2c_tbl_index = 0; + CDBG("Exit\n"); + + return rc; +} + +static int32_t msm_actuator_vcm_init_step_table(struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_set_info_t *set_info) +{ + int16_t code_per_step = 0; + int16_t cur_code = 0; + int16_t step_index = 0, region_index = 0; + uint16_t step_boundary = 0; + uint32_t max_code_size = 1; + uint16_t data_size = set_info->actuator_params.data_size; + CDBG("Enter\n"); + for (; data_size > 0; data_size--) + max_code_size *= 2; + kfree(a_ctrl->step_position_table); + a_ctrl->step_position_table = NULL; + a_ctrl->step_position_table = + kmalloc(sizeof(uint16_t) * + (set_info->af_tuning_params.total_steps + 1), GFP_KERNEL); + if (a_ctrl->step_position_table == NULL) + return -ENOMEM; + cur_code = set_info->af_tuning_params.initial_code; + a_ctrl->step_position_table[step_index++] = cur_code; + for (region_index = 0; + region_index < a_ctrl->region_size; + region_index++) { + code_per_step = + a_ctrl->region_params[region_index].code_per_step; + step_boundary = + a_ctrl->region_params[region_index]. + step_bound[MOVE_NEAR]; + if (step_boundary > set_info->af_tuning_params.total_steps - 1) { + CDBG("%s: Error af steps mismatch!", __func__); + return -EFAULT; + } + for (; step_index <= step_boundary; + step_index++) { + cur_code += code_per_step; + if (cur_code < max_code_size) + a_ctrl->step_position_table[step_index] = + cur_code; + else { + for (; step_index < + set_info->af_tuning_params.total_steps; + step_index++) + a_ctrl-> + step_position_table[ + step_index] = + max_code_size; + } + } + } + for (step_index = 0; + step_index < set_info->af_tuning_params.total_steps; + step_index++) { + CDBG("step_position_table[%d] = %d", step_index, + a_ctrl->step_position_table[step_index]); + } + CDBG("Exit\n"); + return 0; +} + +static int32_t msm_actuator_set_default_focus( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t rc = 0; + CDBG("Enter\n"); + + if (a_ctrl->curr_step_pos != 0) + rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, move_params); + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_vreg_control(struct msm_actuator_ctrl_t *a_ctrl, + int config) +{ + int rc = 0, i, cnt; + struct msm_actuator_vreg *vreg_cfg; + + vreg_cfg = &a_ctrl->vreg_cfg; + cnt = vreg_cfg->num_vreg; + if (!cnt) + return 0; + + if (cnt >= MSM_ACTUATOT_MAX_VREGS) { + pr_err("%s failed %d cnt %d\n", __func__, __LINE__, cnt); + return -EINVAL; + } + + for (i = 0; i < cnt; i++) { + rc = msm_camera_config_single_vreg(&(a_ctrl->pdev->dev), + &vreg_cfg->cam_vreg[i], + (struct regulator **)&vreg_cfg->data[i], + config); + } + return rc; +} + +static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl) +{ + int32_t rc = 0; + CDBG("Enter\n"); + if (a_ctrl->actuator_state != ACTUATOR_POWER_DOWN) { + if (a_ctrl->vcm_enable) { + rc = gpio_direction_output(a_ctrl->vcm_pwd, 0); + if (!rc) + gpio_free(a_ctrl->vcm_pwd); + } + + rc = msm_actuator_vreg_control(a_ctrl, 0); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + + kfree(a_ctrl->step_position_table); + a_ctrl->step_position_table = NULL; + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + a_ctrl->i2c_tbl_index = 0; + a_ctrl->actuator_state = ACTUATOR_POWER_DOWN; + } + CDBG("Exit\n"); + return rc; +} + +static void msm_actuator_set_position_tbl( + struct msm_actuator_ctrl_t *a_ctrl, + uint16_t pos, uint16_t delay) +{ + uint16_t msb, lsb, reg_addr; + reg_addr = a_ctrl->reg_tbl[0].reg_addr; + CDBG("%s reg_addr = %d\n", __func__, reg_addr); + + msb = (pos>>8)&0x00ff; + lsb = pos&0x00ff; + + CDBG("%s pos=%d msb= 0x%X, lsb=0x%X\n", __func__, pos, msb, lsb); + a_ctrl->i2c_reg_tbl[a_ctrl->i2c_tbl_index].reg_addr = reg_addr; + a_ctrl->i2c_reg_tbl[a_ctrl->i2c_tbl_index].reg_data = msb; + a_ctrl->i2c_reg_tbl[a_ctrl->i2c_tbl_index].delay = 0; + a_ctrl->i2c_tbl_index++; + + a_ctrl->i2c_reg_tbl[a_ctrl->i2c_tbl_index].reg_addr = reg_addr+1; + a_ctrl->i2c_reg_tbl[a_ctrl->i2c_tbl_index].reg_data = lsb; + a_ctrl->i2c_reg_tbl[a_ctrl->i2c_tbl_index].delay = delay; + a_ctrl->i2c_tbl_index++; + +} + +static int32_t msm_actuator_vcm_set_position( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_set_position_t *set_pos) +{ + + int32_t rc = 0; + int32_t index; + uint16_t pos, delay; + struct msm_camera_i2c_reg_setting reg_setting; + + CDBG("%s Enter : steps = %d\n", __func__, set_pos->number_of_steps); + + if (set_pos->number_of_steps == 0) + return rc; + + a_ctrl->i2c_tbl_index = 0; + + for (index = 0; index < set_pos->number_of_steps; index++) { + pos = a_ctrl->step_position_table[set_pos->pos[index]]; + delay = set_pos->delay[index]; + msm_actuator_set_position_tbl(a_ctrl, pos, delay); + } + + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("%s Failed I2C write Line %d\n", __func__, __LINE__); + return rc; + } + + CDBG("%s exit %d\n", __func__, __LINE__); + return rc; +} + +static int32_t msm_actuator_set_param(struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_set_info_t *set_info) { + struct reg_settings_t *init_settings = NULL; + int32_t rc = -EFAULT; + uint16_t i = 0; + struct msm_camera_cci_client *cci_client = NULL; + CDBG("Enter\n"); + + for (i = 0; i < ARRAY_SIZE(actuators); i++) { + if (set_info->actuator_params.act_type == + actuators[i]->act_type) { + a_ctrl->func_tbl = &actuators[i]->func_tbl; + rc = 0; + } + } + + if (rc < 0) { + pr_err("Actuator function table not found : act_type = %d\n", set_info->actuator_params.act_type); + return rc; + } + if (set_info->af_tuning_params.total_steps + > MAX_ACTUATOR_AF_TOTAL_STEPS) { + pr_err("Max actuator totalsteps exceeded = %d\n", + set_info->af_tuning_params.total_steps); + return -EFAULT; + } + if (set_info->af_tuning_params.region_size + > MAX_ACTUATOR_REGION) { + pr_err("MAX_ACTUATOR_REGION is exceeded.\n"); + return -EFAULT; + } + + a_ctrl->region_size = set_info->af_tuning_params.region_size; + a_ctrl->pwd_step = set_info->af_tuning_params.pwd_step; + a_ctrl->total_steps = set_info->af_tuning_params.total_steps; + + if (copy_from_user(&a_ctrl->region_params, + (void *)set_info->af_tuning_params.region_params, + a_ctrl->region_size * sizeof(struct region_params_t))) + return -EFAULT; + + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + cci_client = a_ctrl->i2c_client.cci_client; + cci_client->sid = + set_info->actuator_params.i2c_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->cci_i2c_master = a_ctrl->cci_master; + } else { + a_ctrl->i2c_client.client->addr = + set_info->actuator_params.i2c_addr; + } + + a_ctrl->i2c_data_type = set_info->actuator_params.i2c_data_type; + a_ctrl->i2c_client.addr_type = set_info->actuator_params.i2c_addr_type; + if (set_info->actuator_params.reg_tbl_size <= + MAX_ACTUATOR_REG_TBL_SIZE) { + a_ctrl->reg_tbl_size = set_info->actuator_params.reg_tbl_size; + } else { + a_ctrl->reg_tbl_size = 0; + pr_err("MAX_ACTUATOR_REG_TBL_SIZE is exceeded.\n"); + return -EFAULT; + } + + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + a_ctrl->i2c_reg_tbl = + kmalloc(sizeof(struct msm_camera_i2c_reg_array) * + (set_info->af_tuning_params.total_steps + 1), GFP_KERNEL); + if (!a_ctrl->i2c_reg_tbl) { + pr_err("kmalloc fail\n"); + return -ENOMEM; + } + + if (copy_from_user(&a_ctrl->reg_tbl, + (void *)set_info->actuator_params.reg_tbl_params, + a_ctrl->reg_tbl_size * + sizeof(struct msm_actuator_reg_params_t))) { + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + return -EFAULT; + } + + if (set_info->actuator_params.init_setting_size && + set_info->actuator_params.init_setting_size + <= MAX_ACTUATOR_REG_TBL_SIZE) { + if (a_ctrl->func_tbl->actuator_init_focus) { + init_settings = kmalloc(sizeof(struct reg_settings_t) * + (set_info->actuator_params.init_setting_size), + GFP_KERNEL); + if (init_settings == NULL) { + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + pr_err("Error allocating memory for init_settings\n"); + return -EFAULT; + } + if (copy_from_user(init_settings, + (void *)set_info->actuator_params.init_settings, + set_info->actuator_params.init_setting_size * + sizeof(struct reg_settings_t))) { + kfree(init_settings); + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + pr_err("Error copying init_settings\n"); + return -EFAULT; + } + rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl, + set_info->actuator_params.init_setting_size, + init_settings); + kfree(init_settings); + if (rc < 0) { + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + pr_err("Error actuator_init_focus\n"); + return -EFAULT; + } + } + } + + a_ctrl->initial_code = set_info->af_tuning_params.initial_code; + if (a_ctrl->func_tbl->actuator_init_step_table) + rc = a_ctrl->func_tbl-> + actuator_init_step_table(a_ctrl, set_info); + + a_ctrl->curr_step_pos = 0; + a_ctrl->curr_region_index = 0; + a_ctrl->actuator_state = ACTUATOR_POWER_UP; + CDBG("Exit\n"); + + return rc; +} + +static int32_t msm_actuator_vcm_sw_landing( + struct msm_actuator_ctrl_t *a_ctrl, + struct msm_actuator_move_params_t *move_params) +{ + int32_t rc = 0; + struct msm_camera_i2c_reg_setting reg_setting; + struct damping_params_t *damping_params; + struct damping_params_t damping_params_k; + struct damping_params_t damping_params_sacoff; + + int16_t pos_index, First_damping_lens_pos, Second_damping_lens_pos, damp_delay, damp_step, lens_pos; + + if(a_ctrl == NULL || a_ctrl->step_position_table == NULL || move_params == NULL || move_params->ringing_params == NULL) + { + pr_err("%s %d NULL Pointer\n", __func__, __LINE__); + return 0; + } + + CDBG("%s Enter %d\n", __func__, __LINE__); + /*get first and second damping position, damp delay and step*/ + if (copy_from_user(&damping_params_k,&move_params->ringing_params[2],sizeof(struct damping_params_t))) { + pr_err("%s:copy from user failed\n",__func__); + return -EFAULT; + } + + if (copy_from_user(&damping_params_sacoff,&move_params->ringing_params[3],sizeof(struct damping_params_t))) { + pr_err("%s:copy from user failed\n",__func__); + return -EFAULT; + } + + damping_params = &damping_params_k; + damp_delay = damping_params->damping_delay; + damp_step = damping_params->damping_step; + pos_index = (damping_params->hw_params&0xffff); // low 4byte : ker index, high 4byte : dac + + if (pos_index > a_ctrl->total_steps) { + pr_err("Step pos greater than total steps = %d\n", pos_index); + return -EFAULT; + } + First_damping_lens_pos = a_ctrl->step_position_table[pos_index];// + Second_damping_lens_pos = (First_damping_lens_pos>>2) ; // for old version + + CDBG("%s %d First damping index =%d, First_damping_lens_pos=%d, Second_damping_lens_pos=%d\n", + __func__,__LINE__, pos_index, First_damping_lens_pos, Second_damping_lens_pos); + CDBG("%s %d damp_delay=%d, damp_step=%d\n", __func__, __LINE__, damp_delay, damp_step); + /*set the starting lens pos to first damping lens pos*/ + lens_pos = First_damping_lens_pos;// + CDBG("%s %d curr_lens_pos=%d\n", __func__, __LINE__, lens_pos); + + /*set the landing position in the table*/ + CDBG("%s %d set the landing position in the table\n", __func__, __LINE__); + + // 1. Go to pan_focus// + if(damping_params_sacoff.damping_step & 0x1 ) + { + Second_damping_lens_pos = ((damping_params->hw_params>>16)&0xffff); // default 0, dac value + if (Second_damping_lens_pos < 0) + Second_damping_lens_pos = 0; + CDBG("%s %d First damping index new =%d, First_damping_lens_pos=%d, Second_damping_lens_pos=%d\n", + __func__,__LINE__, pos_index, First_damping_lens_pos, Second_damping_lens_pos); + a_ctrl->i2c_tbl_index = 0; + msm_actuator_set_position_tbl(a_ctrl, lens_pos, damp_delay); + CDBG("%s %d i2c_tbl_index %d\n", __func__, __LINE__, a_ctrl->i2c_tbl_index); + + /*write i2c */ + CDBG("%s %d write i2c\n", __func__, __LINE__); + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + //reg_setting.delay = 0; + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("%s Failed I2C write Line %d\n", __func__, __LINE__); + return rc; + } + CDBG("%s %d Go to pan_focus, lens_pos=%d\n", __func__, __LINE__, lens_pos); + } + + // 2. SAC mode off// + if(damping_params_sacoff.damping_step & 0x02 ) + { + + uint16_t addr, data ; + addr = ((damping_params_sacoff.hw_params>>16)&0xffff); // 0x02 + data = ((damping_params_sacoff.hw_params)&0xffff); // 0x00 + usleep_range(damping_params_sacoff.damping_delay , damping_params_sacoff.damping_delay+1000); //10 msec + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &a_ctrl->i2c_client, addr,data, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s Failed I2C write Line %d\n", __func__, __LINE__); + return rc; + } + CDBG("%s SAC mode off delay=%d, addr=0x%x, data =0x%x \n", __func__, damping_params_sacoff.damping_delay, addr, data); + } + + // 3. Start SW landing// + /*set the landing position in the table*/ + CDBG("%s %d set the landing position in the table\n", __func__, __LINE__); + a_ctrl->i2c_tbl_index = 0; + do{ + if(lens_pos < Second_damping_lens_pos + damp_step) break; + else{ + lens_pos -= damp_step; + msm_actuator_set_position_tbl(a_ctrl, lens_pos, damp_delay); + } + }while(lens_pos > Second_damping_lens_pos); + + /*set final position*/ + CDBG("%s %d set the final position in the table\n", __func__, __LINE__); + lens_pos = 0; + msm_actuator_set_position_tbl(a_ctrl, lens_pos, damp_delay); + + /*write i2c */ + CDBG("%s %d write i2c\n", __func__, __LINE__); + reg_setting.reg_setting = a_ctrl->i2c_reg_tbl; + reg_setting.data_type = a_ctrl->i2c_data_type; + reg_setting.size = a_ctrl->i2c_tbl_index; + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay( + &a_ctrl->i2c_client, ®_setting); + if (rc < 0) { + pr_err("%s Failed I2C write Line %d\n", __func__, __LINE__); + return rc; + } + + return rc; +} + +static int msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + CDBG("Enter\n"); + if (!a_ctrl) { + pr_err("failed\n"); + return -EINVAL; + } + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util( + &a_ctrl->i2c_client, MSM_CCI_INIT); + if (rc < 0) + pr_err("cci_init failed\n"); + } + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl, + void __user *argp) +{ + struct msm_actuator_cfg_data *cdata = + (struct msm_actuator_cfg_data *)argp; + int32_t rc = 0; + + if (!a_ctrl) + return -1; + + mutex_lock(a_ctrl->actuator_mutex); + CDBG("Enter\n"); + CDBG("%s type %d\n", __func__, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_ACTUATOR_INIT: + rc = msm_actuator_init(a_ctrl); + if (rc < 0) + pr_err("msm_actuator_init failed %d\n", rc); + break; + case CFG_GET_ACTUATOR_INFO: + cdata->is_af_supported = 1; + cdata->cfg.cam_name = a_ctrl->cam_name; + break; + + case CFG_SET_ACTUATOR_INFO: + rc = msm_actuator_set_param(a_ctrl, &cdata->cfg.set_info); + if (rc < 0) + pr_err("init table failed %d\n", rc); + break; + + case CFG_SET_DEFAULT_FOCUS: + rc = a_ctrl->func_tbl->actuator_set_default_focus(a_ctrl, + &cdata->cfg.move); + if (rc < 0) + pr_err("move focus failed %d\n", rc); + break; + + case CFG_MOVE_FOCUS: + rc = a_ctrl->func_tbl->actuator_move_focus(a_ctrl, + &cdata->cfg.move); + if (rc < 0) + pr_err("move focus failed %d\n", rc); + break; + case CFG_ACTUATOR_POWERDOWN: + rc = msm_actuator_power_down(a_ctrl); + if (rc < 0) + pr_err("msm_actuator_power_down failed %d\n", rc); + break; + + case CFG_SET_POSITION: + rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl, + &cdata->cfg.setpos); + if (rc < 0) + pr_err("actuator_set_position failed %d\n", rc); + break; + + case CFG_SET_ACTUATOR_SW_LANDING: + if (a_ctrl && a_ctrl->func_tbl && a_ctrl->func_tbl->actuator_sw_landing) { + rc = a_ctrl->func_tbl->actuator_sw_landing(a_ctrl, &cdata->cfg.move); + if (rc < 0) + pr_err("actuator_sw_landing failed %d\n", rc); + } + + case CFG_ACTUATOR_POWERUP: + rc = msm_actuator_power_up(a_ctrl); + if (rc < 0) + pr_err("Failed actuator power up%d\n", rc); + break; + + default: + break; + } + mutex_unlock(a_ctrl->actuator_mutex); + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_get_subdev_id(struct msm_actuator_ctrl_t *a_ctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + CDBG("Enter\n"); + if (!subdev_id) { + pr_err("failed\n"); + return -EINVAL; + } + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) + *subdev_id = a_ctrl->pdev->id; + else + *subdev_id = a_ctrl->subdev_id; + + CDBG("subdev_id %d\n", *subdev_id); + CDBG("Exit\n"); + return 0; +} + +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, + .i2c_poll = msm_camera_qup_i2c_poll, +}; + +static int msm_actuator_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); + CDBG("Enter\n"); + if (!a_ctrl) { + pr_err("failed\n"); + return -EINVAL; + } + if (a_ctrl->act_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_util( + &a_ctrl->i2c_client, MSM_CCI_RELEASE); + if (rc < 0) + pr_err("cci_init failed\n"); + } + kfree(a_ctrl->i2c_reg_tbl); + a_ctrl->i2c_reg_tbl = NULL; + + CDBG("Exit\n"); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_actuator_internal_ops = { + .close = msm_actuator_close, +}; + +static long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); + void __user *argp = (void __user *)arg; + CDBG("Enter\n"); + CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, a_ctrl, argp); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return msm_actuator_get_subdev_id(a_ctrl, argp); + case VIDIOC_MSM_ACTUATOR_CFG: + return msm_actuator_config(a_ctrl, argp); + case MSM_SD_SHUTDOWN: + msm_actuator_close(sd, NULL); + return 0; + default: + return -ENOIOCTLCMD; + } +} + +static int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + CDBG("%s called\n", __func__); + + CDBG("vcm info: %d %d\n", a_ctrl->vcm_pwd, + a_ctrl->vcm_enable); + + rc = msm_actuator_vreg_control(a_ctrl, 1); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return rc; + } + + if (a_ctrl->vcm_enable) { + rc = gpio_request(a_ctrl->vcm_pwd, "msm_actuator"); + if (!rc) { + CDBG("Enable VCM PWD\n"); + gpio_direction_output(a_ctrl->vcm_pwd, 1); + } + } + CDBG("Exit\n"); + return rc; +} + +static int32_t msm_actuator_power(struct v4l2_subdev *sd, int on) +{ + int rc = 0; + struct msm_actuator_ctrl_t *a_ctrl = v4l2_get_subdevdata(sd); + CDBG("Enter\n"); + mutex_lock(a_ctrl->actuator_mutex); + if (on) + rc = msm_actuator_power_up(a_ctrl); + else + rc = msm_actuator_power_down(a_ctrl); + mutex_unlock(a_ctrl->actuator_mutex); + CDBG("Exit\n"); + return rc; +} + +static struct v4l2_subdev_core_ops msm_actuator_subdev_core_ops = { + .ioctl = msm_actuator_subdev_ioctl, + .s_power = msm_actuator_power, +}; + +static struct v4l2_subdev_ops msm_actuator_subdev_ops = { + .core = &msm_actuator_subdev_core_ops, +}; + +static const struct i2c_device_id msm_actuator_i2c_id[] = { + {"qcom,actuator", (kernel_ulong_t)NULL}, + { } +}; + +static int32_t msm_actuator_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct msm_actuator_ctrl_t *act_ctrl_t = NULL; + pr_err("msm_actuator_i2c_probe: Enter\n"); + + if (client == NULL) { + pr_err("msm_actuator_i2c_probe: client is null\n"); + rc = -EINVAL; + goto probe_failure; + } + + act_ctrl_t = kzalloc(sizeof(struct msm_actuator_ctrl_t), + GFP_KERNEL); + if (!act_ctrl_t) { + pr_err("%s:%d failed no memory\n", __func__, __LINE__); + return -ENOMEM; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality failed\n"); + kfree(act_ctrl_t); + goto probe_failure; + } + + CDBG("client = 0x%p\n", client); + + rc = of_property_read_u32(client->dev.of_node, "cell-index", + &act_ctrl_t->subdev_id); + CDBG("cell-index %d, rc %d\n", act_ctrl_t->subdev_id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + kfree(act_ctrl_t); + return rc; + } + + act_ctrl_t->i2c_driver = &msm_actuator_i2c_driver; + act_ctrl_t->i2c_client.client = client; + act_ctrl_t->curr_step_pos = 0, + act_ctrl_t->curr_region_index = 0, + /* Set device type as I2C */ + act_ctrl_t->act_device_type = MSM_CAMERA_I2C_DEVICE; + act_ctrl_t->i2c_client.i2c_func_tbl = &msm_sensor_qup_func_tbl; + act_ctrl_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; + act_ctrl_t->actuator_mutex = &msm_actuator_mutex; + + act_ctrl_t->cam_name = act_ctrl_t->subdev_id; + CDBG("act_ctrl_t->cam_name: %d", act_ctrl_t->cam_name); + /* Assign name for sub device */ + snprintf(act_ctrl_t->msm_sd.sd.name, sizeof(act_ctrl_t->msm_sd.sd.name), + "%s", act_ctrl_t->i2c_driver->driver.name); + + /* Initialize sub device */ + v4l2_i2c_subdev_init(&act_ctrl_t->msm_sd.sd, + act_ctrl_t->i2c_client.client, + act_ctrl_t->act_v4l2_subdev_ops); + v4l2_set_subdevdata(&act_ctrl_t->msm_sd.sd, act_ctrl_t); + act_ctrl_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops; + act_ctrl_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL, 0); + act_ctrl_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + act_ctrl_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR; + act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; + msm_sd_register(&act_ctrl_t->msm_sd); + pr_info("msm_actuator_i2c_probe: succeeded\n"); + pr_err("msm_actuator_i2c_probe: Exit\n"); + +probe_failure: + return rc; +} + +static int32_t msm_actuator_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct msm_camera_cci_client *cci_client = NULL; + struct msm_actuator_ctrl_t *msm_actuator_t = NULL; + struct msm_actuator_vreg *vreg_cfg; + pr_err("msm_actuator_platform_probe: Enter\n"); + + if (!pdev->dev.of_node) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + + msm_actuator_t = kzalloc(sizeof(struct msm_actuator_ctrl_t), + GFP_KERNEL); + if (!msm_actuator_t) { + pr_err("%s:%d failed no memory\n", __func__, __LINE__); + return -ENOMEM; + } + rc = of_property_read_u32((&pdev->dev)->of_node, "cell-index", + &pdev->id); + CDBG("cell-index %d, rc %d\n", pdev->id, rc); + if (rc < 0) { + kfree(msm_actuator_t); + pr_err("failed rc %d\n", rc); + return rc; + } + + rc = of_property_read_u32((&pdev->dev)->of_node, "qcom,cci-master", + &msm_actuator_t->cci_master); + CDBG("qcom,cci-master %d, rc %d\n", msm_actuator_t->cci_master, rc); + if (rc < 0) { + kfree(msm_actuator_t); + pr_err("failed rc %d\n", rc); + return rc; + } + + if (of_find_property((&pdev->dev)->of_node, + "qcom,cam-vreg-name", NULL)) { + vreg_cfg = &msm_actuator_t->vreg_cfg; + rc = msm_camera_get_dt_vreg_data((&pdev->dev)->of_node, + &vreg_cfg->cam_vreg, &vreg_cfg->num_vreg); + if (rc < 0) { + kfree(msm_actuator_t); + pr_err("failed rc %d\n", rc); + return rc; + } + } + + msm_actuator_t->act_v4l2_subdev_ops = &msm_actuator_subdev_ops; + msm_actuator_t->actuator_mutex = &msm_actuator_mutex; + msm_actuator_t->cam_name = pdev->id; + + /* Set platform device handle */ + msm_actuator_t->pdev = pdev; + /* Set device type as platform device */ + msm_actuator_t->act_device_type = MSM_CAMERA_PLATFORM_DEVICE; + msm_actuator_t->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl; + msm_actuator_t->i2c_client.cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!msm_actuator_t->i2c_client.cci_client) { + kfree(msm_actuator_t->vreg_cfg.cam_vreg); + kfree(msm_actuator_t); + pr_err("failed no memory\n"); + return -ENOMEM; + } + + cci_client = msm_actuator_t->i2c_client.cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = MASTER_MAX; + v4l2_subdev_init(&msm_actuator_t->msm_sd.sd, + msm_actuator_t->act_v4l2_subdev_ops); + v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t); + msm_actuator_t->msm_sd.sd.internal_ops = &msm_actuator_internal_ops; + msm_actuator_t->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(msm_actuator_t->msm_sd.sd.name, + ARRAY_SIZE(msm_actuator_t->msm_sd.sd.name), "msm_actuator"); + media_entity_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL, 0); + msm_actuator_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + msm_actuator_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR; + msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; + msm_sd_register(&msm_actuator_t->msm_sd); + pr_err("msm_actuator_platform_probe: Exit\n"); + return rc; +} + +static const struct of_device_id msm_actuator_i2c_dt_match[] = { + {.compatible = "qcom,actuator"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_actuator_i2c_dt_match); + +static struct i2c_driver msm_actuator_i2c_driver = { + .id_table = msm_actuator_i2c_id, + .probe = msm_actuator_i2c_probe, + .remove = __exit_p(msm_actuator_i2c_remove), + .driver = { + .name = "qcom,actuator", + .owner = THIS_MODULE, + .of_match_table = msm_actuator_i2c_dt_match, + }, +}; + +static const struct of_device_id msm_actuator_dt_match[] = { + {.compatible = "qcom,actuator", .data = NULL}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_actuator_dt_match); + +static struct platform_driver msm_actuator_platform_driver = { + .driver = { + .name = "qcom,actuator", + .owner = THIS_MODULE, + .of_match_table = msm_actuator_dt_match, + }, +}; + +static int __init msm_actuator_init_module(void) +{ + int32_t rc = 0; + pr_err("msm_actuator_init_module: Enter\n"); + rc = platform_driver_probe(&msm_actuator_platform_driver, + msm_actuator_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&msm_actuator_i2c_driver); +} + +static struct msm_actuator msm_vcm_actuator_table = { + .act_type = ACTUATOR_VCM, + .func_tbl = { + .actuator_init_step_table = msm_actuator_vcm_init_step_table, + .actuator_move_focus = msm_actuator_move_focus, + .actuator_write_focus = msm_actuator_write_focus, + .actuator_set_default_focus = msm_actuator_set_default_focus, + .actuator_init_focus = msm_actuator_vcm_init_focus, + .actuator_parse_i2c_params = msm_actuator_parse_i2c_params, + .actuator_set_position = msm_actuator_vcm_set_position, + .actuator_sw_landing = msm_actuator_vcm_sw_landing, + }, +}; + +static struct msm_actuator msm_piezo_actuator_table = { + .act_type = ACTUATOR_PIEZO, + .func_tbl = { + .actuator_init_step_table = NULL, + .actuator_move_focus = msm_actuator_piezo_move_focus, + .actuator_write_focus = NULL, + .actuator_set_default_focus = + msm_actuator_piezo_set_default_focus, + .actuator_init_focus = msm_actuator_init_focus, + .actuator_parse_i2c_params = msm_actuator_parse_i2c_params, + }, +}; + +module_init(msm_actuator_init_module); +MODULE_DESCRIPTION("MSM ACTUATOR"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/msm_actuator.h new file mode 100644 index 0000000000000000000000000000000000000000..198cc70669074dc8224a677107170756cb2f92ee --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/actuator/msm_actuator.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ +#ifndef MSM_ACTUATOR_H +#define MSM_ACTUATOR_H + +#include +#include +#include "../../include/soc/qcom/camera2.h" +#include +#include "../../include/media/msmb_camera.h" +#include "msm_camera_i2c.h" +#include "msm_camera_dt_util.h" +#include "msm_camera_io_util.h" + + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define MSM_ACTUATOT_MAX_VREGS (10) + +struct msm_actuator_ctrl_t; + +enum msm_actuator_state_t { + ACTUATOR_POWER_UP, + ACTUATOR_POWER_DOWN, +}; + +struct msm_actuator_func_tbl { + int32_t (*actuator_i2c_write_b_af)(struct msm_actuator_ctrl_t *, + uint8_t, + uint8_t); + int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *, + struct msm_actuator_set_info_t *); + int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *, + uint16_t, struct reg_settings_t *); + int32_t (*actuator_set_default_focus) (struct msm_actuator_ctrl_t *, + struct msm_actuator_move_params_t *); + int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *, + struct msm_actuator_move_params_t *); + void (*actuator_parse_i2c_params)(struct msm_actuator_ctrl_t *, + int16_t, uint32_t, uint16_t); + void (*actuator_write_focus)(struct msm_actuator_ctrl_t *, + uint16_t, + struct damping_params_t *, + int8_t, + int16_t); + int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *, + struct msm_actuator_set_position_t *); + int32_t (*actuator_sw_landing)(struct msm_actuator_ctrl_t *, + struct msm_actuator_move_params_t *); +}; + +struct msm_actuator { + enum actuator_type act_type; + struct msm_actuator_func_tbl func_tbl; +}; + +struct msm_actuator_vreg { + struct camera_vreg_t *cam_vreg; + void *data[MSM_ACTUATOT_MAX_VREGS]; + int num_vreg; +}; + +struct msm_actuator_ctrl_t { + struct i2c_driver *i2c_driver; + struct platform_driver *pdriver; + struct platform_device *pdev; + struct msm_camera_i2c_client i2c_client; + enum msm_camera_device_type_t act_device_type; + struct msm_sd_subdev msm_sd; + enum af_camera_name cam_name; + struct mutex *actuator_mutex; + struct msm_actuator_func_tbl *func_tbl; + enum msm_actuator_data_type i2c_data_type; + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *act_v4l2_subdev_ops; + + int16_t curr_step_pos; + uint16_t curr_region_index; + uint16_t *step_position_table; + struct region_params_t region_params[MAX_ACTUATOR_REGION]; + uint16_t reg_tbl_size; + struct msm_actuator_reg_params_t reg_tbl[MAX_ACTUATOR_REG_TBL_SIZE]; + uint16_t region_size; + void *user_data; + uint32_t vcm_pwd; + uint32_t vcm_enable; + uint32_t total_steps; + uint16_t pwd_step; + uint16_t initial_code; + struct msm_camera_i2c_reg_array *i2c_reg_tbl; + uint16_t i2c_tbl_index; + enum cci_i2c_master_t cci_master; + uint32_t subdev_id; + enum msm_actuator_state_t actuator_state; + struct msm_actuator_vreg vreg_cfg; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/cci/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b1a31efbdacac0bedd3e776c2bc03625bdbb77c2 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSM_CCI) += msm_cci.o diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cam_cci_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..059633bfd54abae1d5aa553feef38d15bfd200f1 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cam_cci_hwreg.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_CAM_CCI_HWREG__ +#define __MSM_CAM_CCI_HWREG__ + +#define CCI_HW_VERSION_ADDR 0x00000000 +#define CCI_RESET_CMD_ADDR 0x00000004 +#define CCI_RESET_CMD_RMSK 0x0f73f3f7 +#define CCI_M0_RESET_RMSK 0x3F1 +#define CCI_M1_RESET_RMSK 0x3F001 +#define CCI_QUEUE_START_ADDR 0x00000008 +#define CCI_SET_CID_SYNC_TIMER_0_ADDR 0x00000010 +#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100 +#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104 +#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108 +#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c +#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118 +#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110 +#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C +#define CCI_HALT_REQ_ADDR 0x00000034 +#define CCI_M0_HALT_REQ_RMSK 0x1 +#define CCI_M1_HALT_REQ_RMSK 0x2 +#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200 +#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204 +#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208 +#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c +#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210 +#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304 +#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308 +#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300 +#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310 +#define CCI_IRQ_MASK_0_ADDR 0x00000c04 +#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7 +#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08 +#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000 +#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 +#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 +#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 +#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00 +#endif /* __MSM_CAM_CCI_HWREG__ */ diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cci.c new file mode 100644 index 0000000000000000000000000000000000000000..e1b36c9af3414f2f620a05204cdde6e22ff8332e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cci.c @@ -0,0 +1,1366 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include "msm_sd.h" +#include "msm_cci.h" +#include "msm_cam_cci_hwreg.h" +#include "msm_camera_io_util.h" + +#define V4L2_IDENT_CCI 50005 +#define CCI_I2C_QUEUE_0_SIZE 64 +#define CCI_I2C_QUEUE_1_SIZE 16 +#define CYCLES_PER_MICRO_SEC 4915 +#define CCI_MAX_DELAY 10000 + +#define CCI_TIMEOUT msecs_to_jiffies(100) + +/* TODO move this somewhere else */ +#define MSM_CCI_DRV_NAME "msm_cci" + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do {} while (0) +#endif + +/* Max bytes that can be read per CCI read transaction */ +#define CCI_READ_MAX 12 +#define CCI_I2C_READ_MAX_RETRIES 3 +#define CCI_I2C_MAX_READ 8192 +#define CCI_I2C_MAX_WRITE 8192 +#define CCI_NUM_CLK_MAX 16 + +static struct v4l2_subdev *g_cci_subdev; + +static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_MAX]; + +static void msm_cci_set_clk_param(struct cci_device *cci_dev, + struct msm_camera_cci_ctrl *c_ctrl) +{ + struct msm_cci_clk_params_t *clk_params = NULL; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; + + if (cci_dev->master_clk_init[master]) + return; + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; + + if (MASTER_0 == master) { + msm_camera_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR); + msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR); + msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR); + msm_camera_io_w_mb(clk_params->hw_tbuf, + cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR); + msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR); + } else if (MASTER_1 == master) { + msm_camera_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR); + msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR); + msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR); + msm_camera_io_w_mb(clk_params->hw_tbuf, + cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR); + msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR); + } + cci_dev->master_clk_init[master] = 1; + return; +} + +static void msm_cci_flush_queue(struct cci_device *cci_dev, + enum cci_i2c_master_t master) +{ + int32_t rc = 0; + + msm_camera_io_w_mb(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR); + rc = wait_for_completion_interruptible_timeout( + &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc < 0) { + pr_err("%s:%d wait failed\n", __func__, __LINE__); + } else if (rc == 0) { + pr_err("%s:%d wait timeout\n", __func__, __LINE__); + + /* Set reset pending flag to TRUE */ + cci_dev->cci_master_info[master].reset_pending = TRUE; + + /* Set proper mask to RESET CMD address based on MASTER */ + if (master == MASTER_0) + msm_camera_io_w_mb(CCI_M0_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + else + msm_camera_io_w_mb(CCI_M1_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + + /* wait for reset done irq */ + rc = wait_for_completion_interruptible_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) + pr_err("%s:%d wait failed %d\n", __func__, __LINE__, + rc); + } + return; +} + +static int32_t msm_cci_validate_queue(struct cci_device *cci_dev, + uint32_t len, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t read_val = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + read_val = msm_camera_io_r_mb(cci_dev->base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d\n", + __func__, __LINE__, read_val, len, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); + if ((read_val + len + 1) > cci_dev-> + cci_i2c_queue_info[master][queue].max_queue_size) { + uint32_t reg_val = 0; + uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); + CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__); + msm_camera_io_w_mb(report_val, + cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + read_val++; + CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d\n", + __func__, __LINE__, read_val); + msm_camera_io_w_mb(read_val, cci_dev->base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + reg_val = 1 << ((master * 2) + queue); + CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__); + msm_camera_io_w_mb(reg_val, cci_dev->base + + CCI_QUEUE_START_ADDR); + CDBG("%s line %d wait_for_completion_interruptible\n", + __func__, __LINE__); + rc = wait_for_completion_interruptible_timeout(&cci_dev-> + cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_interruptible_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + msm_cci_flush_queue(cci_dev, master); + return rc; + } + rc = cci_dev->cci_master_info[master].status; + if (rc < 0) + pr_err("%s failed rc %d\n", __func__, rc); + } + return rc; +} + +static int32_t msm_cci_data_queue(struct cci_device *cci_dev, + struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, uint8_t is_burst) +{ + uint16_t i = 0, j = 0, k = 0, h = 0, len = 0; + int32_t rc = 0; + uint32_t cmd = 0, delay = 0; + uint8_t data[11]; + uint16_t reg_addr = 0; + struct msm_camera_i2c_reg_setting *i2c_msg = + &c_ctrl->cfg.cci_i2c_write_cfg; + uint16_t cmd_size = i2c_msg->size; + struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + + if (i2c_cmd == NULL) { + pr_err("%s:%d Failed line\n", __func__, + __LINE__); + return -EINVAL; + } + + if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) { + pr_err("%s:%d Failed line\n", __func__, __LINE__); + return -EINVAL; + } + + CDBG("%s addr type %d data type %d\n", __func__, + i2c_msg->addr_type, i2c_msg->data_type); + + if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return -EINVAL; + } + if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return -EINVAL; + } + /* assume total size within the max queue */ + while (cmd_size) { + CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__, + cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data); + delay = i2c_cmd->delay; + data[i++] = CCI_I2C_WRITE_CMD; + if (i2c_msg->data_type == MSM_CAMERA_I2C_BURST_DATA) { + if (i2c_cmd->reg_addr) { + reg_addr = i2c_cmd->reg_addr; + } + } + else { + reg_addr = i2c_cmd->reg_addr; + } + /* either byte or word addr */ + if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) + data[i++] = reg_addr; + else { + data[i++] = (reg_addr & 0xFF00) >> 8; + data[i++] = reg_addr & 0x00FF; + } + /* max of 10 data bytes */ + do { + if ((i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) || + (i2c_msg->data_type == MSM_CAMERA_I2C_BURST_DATA)) { + data[i++] = i2c_cmd->reg_data; + if (!is_burst) + reg_addr++; + } else { + if ((i + 1) <= 10) { + data[i++] = (i2c_cmd->reg_data & + 0xFF00) >> 8; /* MSB */ + data[i++] = i2c_cmd->reg_data & + 0x00FF; /* LSB */ + if (!is_burst) + reg_addr += 2; + } else + break; + } + i2c_cmd++; + } while (--cmd_size && !i2c_cmd->reg_addr && (i <= 10)); + data[0] |= ((i-1) << 4); + len = ((i-1)/4) + 1; + rc = msm_cci_validate_queue(cci_dev, len, master, queue); + if (rc < 0) { + pr_err("%s: failed %d", __func__, __LINE__); + return rc; + } + for (h = 0, k = 0; h < len; h++) { + cmd = 0; + for (j = 0; (j < 4 && k < i); j++) + cmd |= (data[k++] << (j * 8)); + CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n", + __func__, cmd); + msm_camera_io_w_mb(cmd, cci_dev->base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + } + if ((delay > 0) && (delay < CCI_MAX_DELAY)) { + cmd = (uint32_t)((delay * CYCLES_PER_MICRO_SEC) / + 0x100); + cmd <<= 4; + cmd |= CCI_I2C_WAIT_CMD; + CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n", + __func__, cmd); + msm_camera_io_w_mb(cmd, cci_dev->base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + } + i = 0; + } + return rc; +} + +static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev, + uint32_t val, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cci_validate_queue(cci_dev, 1, master, queue); + if (rc < 0) { + pr_err("%s: failed %d", __func__, __LINE__); + return rc; + } + CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n", + __func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset, val); + msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + return rc; +} + +static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + uint32_t val = 0; + int32_t read_words = 0, exp_words = 0; + int32_t index = 0, first_byte = 0; + uint32_t i = 0; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_1; + struct cci_device *cci_dev = NULL; + struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; + CDBG("%s line %d\n", __func__, __LINE__); + cci_dev = v4l2_get_subdevdata(sd); + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + mutex_lock(&cci_dev->cci_master_info[master].mutex); + + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_read call. This is to + * avoid overflow / underflow of queue + */ + rc = msm_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + pr_err("%s:%d Initial validataion failed rc %d\n", __func__, + __LINE__, rc); + goto ERROR; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + pr_err("%s:%d More than max retries\n", __func__, + __LINE__); + goto ERROR; + } + + if (read_cfg->data == NULL) { + pr_err("%s:%d Data ptr is NULL\n", __func__, + __LINE__); + goto ERROR; + } + + CDBG("%s master %d, queue %d\n", __func__, master, queue); + CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_LOCK_CMD; + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) | + ((read_cfg->addr & 0xFF) << 8); + if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR) + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) | + (((read_cfg->addr & 0xFF00) >> 8) << 8) | + ((read_cfg->addr & 0xFF) << 16); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_UNLOCK_CMD; + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CDBG("%s cur word cnt 0x%x\n", __func__, val); + msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR); + CDBG("%s:%d E wait_for_completion_interruptible_timeout\n", __func__, + __LINE__); + rc = wait_for_completion_interruptible_timeout(&cci_dev-> + cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_interruptible_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + msm_cci_flush_queue(cci_dev, master); + goto ERROR; + } else { + rc = 0; + } + CDBG("%s:%d E wait_for_completion_interruptible_timeout\n", __func__, + __LINE__); + + read_words = msm_camera_io_r_mb(cci_dev->base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + exp_words = ((read_cfg->num_byte / 4) + 1); + if (read_words != exp_words) { + pr_err("%s:%d read_words = %d, exp words = %d\n", __func__, + __LINE__, read_words, exp_words); + memset(read_cfg->data, 0, read_cfg->num_byte); + rc = -EINVAL; + goto ERROR; + } + index = 0; + CDBG("%s index %d num_type %d\n", __func__, index, + read_cfg->num_byte); + first_byte = 0; + do { + val = msm_camera_io_r_mb(cci_dev->base + + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); + CDBG("%s read val 0x%x\n", __func__, val); + for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) { + CDBG("%s i %d index %d\n", __func__, i, index); + if (!first_byte) { + CDBG("%s sid 0x%x\n", __func__, val & 0xFF); + first_byte++; + } else { + read_cfg->data[index] = + (val >> (i * 8)) & 0xFF; + CDBG("%s data[%d] 0x%x\n", __func__, index, + read_cfg->data[index]); + index++; + } + } + } while (--read_words > 0); +ERROR: + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + return rc; +} + +static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev = NULL; + enum cci_i2c_master_t master; + struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL; + uint16_t read_bytes = 0; + + if (!sd || !c_ctrl) { + pr_err("%s:%d sd %p c_ctrl %p\n", __func__, + __LINE__, sd, c_ctrl); + return -EINVAL; + } + if (!c_ctrl->cci_info) { + pr_err("%s:%d cci_info NULL\n", __func__, __LINE__); + return -EINVAL; + } + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev) { + pr_err("%s:%d cci_dev NULL\n", __func__, __LINE__); + return -EINVAL; + } + + if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); + return -EINVAL; + } + + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) { + pr_err("%s:%d read num bytes 0\n", __func__, __LINE__); + rc = -EINVAL; + goto ERROR; + } + + read_bytes = read_cfg->num_byte; + do { + if (read_bytes > CCI_READ_MAX) + read_cfg->num_byte = CCI_READ_MAX; + else + read_cfg->num_byte = read_bytes; + rc = msm_cci_i2c_read(sd, c_ctrl); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + goto ERROR; + } + if (read_bytes > CCI_READ_MAX) { + read_cfg->addr += CCI_READ_MAX; + read_cfg->data += CCI_READ_MAX; + read_bytes -= CCI_READ_MAX; + } else { + read_bytes = 0; + } + } while (read_bytes); +ERROR: + return rc; +} + +static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl, uint8_t is_burst) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + uint32_t val; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_0; + cci_dev = v4l2_get_subdevdata(sd); + + master = c_ctrl->cci_info->cci_i2c_master; + if (master >= MASTER_MAX + || master < 0) { + pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__); + return -EINVAL; + } + CDBG("%s master %d, queue %d\n", __func__, master, queue); + CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__, + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + mutex_lock(&cci_dev->cci_master_info[master].mutex); + + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_write call. This is to + * avoid overflow / underflow of queue + */ + rc = msm_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + pr_err("%s:%d Initial validataion failed rc %d\n", __func__, + __LINE__, rc); + goto ERROR; + } + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + pr_err("%s:%d More than max retries\n", __func__, + __LINE__); + goto ERROR; + } + + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + CDBG("%s:%d CCI_I2C_SET_PARAM_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_LOCK_CMD; + CDBG("%s:%d CCI_I2C_LOCK_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + rc = msm_cci_data_queue(cci_dev, c_ctrl, queue, is_burst); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + val = CCI_I2C_UNLOCK_CMD; + CDBG("%s:%d CCI_I2C_UNLOCK_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = CCI_I2C_REPORT_CMD | (1 << 8); + CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__); + rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CDBG("%s failed line %d\n", __func__, __LINE__); + goto ERROR; + } + + val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CDBG("%s:%d cur word count %d\n", __func__, __LINE__, val); + CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR\n", __func__, __LINE__); + msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__); + msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR); + + CDBG("%s:%d E wait_for_completion_interruptible\n", + __func__, __LINE__); + rc = wait_for_completion_interruptible_timeout(&cci_dev-> + cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_interruptible_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + msm_cci_flush_queue(cci_dev, master); + goto ERROR; + } else { + rc = cci_dev->cci_master_info[master].status; + } + CDBG("%s:%d X wait_for_completion_interruptible\n", __func__, + __LINE__); + +ERROR: + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + return rc; +} + +static int msm_cci_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + if (!chip) { + pr_err("%s:%d: NULL pointer supplied for chip ident\n", + __func__, __LINE__); + return -EINVAL; + } + chip->ident = V4L2_IDENT_CCI; + chip->revision = 0; + return 0; +} + +static int32_t msm_cci_pinctrl_init(struct cci_device *cci_dev) +{ + struct msm_pinctrl_info *cci_pctrl = NULL; + + cci_pctrl = &cci_dev->cci_pinctrl; + cci_pctrl->pinctrl = devm_pinctrl_get(&cci_dev->pdev->dev); + if (IS_ERR_OR_NULL(cci_pctrl->pinctrl)) { + pr_err("%s:%d devm_pinctrl_get cci_pinctrl failed\n", + __func__, __LINE__); + return -EINVAL; + } + cci_pctrl->gpio_state_active = pinctrl_lookup_state( + cci_pctrl->pinctrl, + CCI_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_active)) { + pr_err("%s:%d look up state for active state failed\n", + __func__, __LINE__); + return -EINVAL; + } + cci_pctrl->gpio_state_suspend = pinctrl_lookup_state( + cci_pctrl->pinctrl, + CCI_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(cci_pctrl->gpio_state_suspend)) { + pr_err("%s:%d look up state for suspend state failed\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + +static int32_t msm_cci_init(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *c_ctrl) +{ + uint8_t i = 0; + int32_t rc = 0, ret = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + pr_err("%s:%d failed: invalid params %p %p\n", __func__, + __LINE__, cci_dev, c_ctrl); + rc = -ENOMEM; + return rc; + } + if (cci_dev->ref_count++) { + CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count); + master = c_ctrl->cci_info->cci_i2c_master; + CDBG("%s:%d master %d\n", __func__, __LINE__, master); + if (master < MASTER_MAX && master >= 0) { + mutex_lock(&cci_dev->cci_master_info[master].mutex); + /* Set reset pending flag to TRUE */ + cci_dev->cci_master_info[master].reset_pending = TRUE; + /* Set proper mask to RESET CMD address */ + if (master == MASTER_0) + msm_camera_io_w_mb(CCI_M0_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + else + msm_camera_io_w_mb(CCI_M1_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + /* wait for reset done irq */ + rc = wait_for_completion_interruptible_timeout( + &cci_dev->cci_master_info[master]. + reset_complete, + CCI_TIMEOUT); + if (rc <= 0) + pr_err("%s:%d wait failed %d\n", __func__, + __LINE__, rc); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + } + return 0; + } + ret = msm_cci_pinctrl_init(cci_dev); + if (ret < 0) { + pr_err("%s:%d Initialization of pinctrl failed\n", + __func__, __LINE__); + cci_dev->cci_pinctrl_status = 0; + } else { + cci_dev->cci_pinctrl_status = 1; + } + rc = msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, + cci_dev->cci_gpio_tbl_size, 1); + if (cci_dev->cci_pinctrl_status) { + ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, + cci_dev->cci_pinctrl.gpio_state_active); + if (ret) + pr_err("%s:%d cannot set pin to active state\n", + __func__, __LINE__); + } + if (rc < 0) { + cci_dev->ref_count--; + CDBG("%s: request gpio failed\n", __func__); + goto request_gpio_failed; + } + rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, + cci_dev->cci_clk, cci_dev->num_clk, 1); + if (rc < 0) { + cci_dev->ref_count--; + CDBG("%s: clk enable failed\n", __func__); + goto clk_enable_failed; + } + enable_irq(cci_dev->irq->start); + cci_dev->hw_version = msm_camera_io_r_mb(cci_dev->base + + CCI_HW_VERSION_ADDR); + pr_info("%s:%d: hw_version = 0x%x\n", __func__, __LINE__, + cci_dev->hw_version); + cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + msm_camera_io_w_mb(CCI_RESET_CMD_RMSK, cci_dev->base + + CCI_RESET_CMD_ADDR); + msm_camera_io_w_mb(0x1, cci_dev->base + CCI_RESET_CMD_ADDR); + rc = wait_for_completion_interruptible_timeout( + &cci_dev->cci_master_info[MASTER_0].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) { + pr_err("%s: wait_for_completion_interruptible_timeout %d\n", + __func__, __LINE__); + if (rc == 0) + rc = -ETIMEDOUT; + goto reset_complete_failed; + } + for (i = 0; i < MASTER_MAX; i++) + cci_dev->master_clk_init[i] = 0; + msm_cci_set_clk_param(cci_dev, c_ctrl); + msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, + cci_dev->base + CCI_IRQ_MASK_0_ADDR); + msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK, + cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); + msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + cci_dev->cci_state = CCI_STATE_ENABLED; + + return 0; + +reset_complete_failed: + disable_irq(cci_dev->irq->start); + msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, + cci_dev->cci_clk, cci_dev->num_clk, 0); +clk_enable_failed: + if (cci_dev->cci_pinctrl_status) { + ret = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, + cci_dev->cci_pinctrl.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state\n", + __func__, __LINE__); + } + msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, + cci_dev->cci_gpio_tbl_size, 0); +request_gpio_failed: + cci_dev->ref_count--; + return rc; +} + +static int32_t msm_cci_release(struct v4l2_subdev *sd) +{ + uint8_t i = 0, rc = 0; + struct cci_device *cci_dev; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { + pr_err("%s invalid ref count %d / cci state %d\n", + __func__, cci_dev->ref_count, cci_dev->cci_state); + return -EINVAL; + } + if (--cci_dev->ref_count) { + CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count); + return 0; + } + disable_irq(cci_dev->irq->start); + msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info, + cci_dev->cci_clk, cci_dev->num_clk, 0); + if (cci_dev->cci_pinctrl_status) { + rc = pinctrl_select_state(cci_dev->cci_pinctrl.pinctrl, + cci_dev->cci_pinctrl.gpio_state_suspend); + if (rc) + pr_err("%s:%d cannot set pin to active state\n", + __func__, __LINE__); + } + cci_dev->cci_pinctrl_status = 0; + msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl, + cci_dev->cci_gpio_tbl_size, 0); + for (i = 0; i < MASTER_MAX; i++) + cci_dev->master_clk_init[i] = 0; + cci_dev->cci_state = CCI_STATE_DISABLED; + + return 0; +} + +static int32_t msm_cci_config(struct v4l2_subdev *sd, + struct msm_camera_cci_ctrl *cci_ctrl) +{ + int32_t rc = 0; + CDBG("%s line %d cmd %d\n", __func__, __LINE__, + cci_ctrl->cmd); + switch (cci_ctrl->cmd) { + case MSM_CCI_INIT: + rc = msm_cci_init(sd, cci_ctrl); + break; + case MSM_CCI_RELEASE: + rc = msm_cci_release(sd); + break; + case MSM_CCI_I2C_READ: + rc = msm_cci_i2c_read_bytes(sd, cci_ctrl); + break; + case MSM_CCI_I2C_WRITE: + rc = msm_cci_i2c_write(sd, cci_ctrl, 0); + break; + case MSM_CCI_I2C_WRITE_BURST: + rc = msm_cci_i2c_write(sd, cci_ctrl, 1); + break; + case MSM_CCI_GPIO_WRITE: + break; + default: + rc = -ENOIOCTLCMD; + } + CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); + cci_ctrl->status = rc; + return rc; +} + +static irqreturn_t msm_cci_irq(int irq_num, void *data) +{ + uint32_t irq; + struct cci_device *cci_dev = data; + irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR); + msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR); + msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + msm_camera_io_w_mb(0x0, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + CDBG("%s CCI_I2C_M0_STATUS_ADDR = 0x%x\n", __func__, irq); + if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + cci_dev->cci_master_info[MASTER_0].reset_pending = + FALSE; + complete(&cci_dev->cci_master_info[MASTER_0]. + reset_complete); + } + if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + cci_dev->cci_master_info[MASTER_1].reset_pending = + FALSE; + complete(&cci_dev->cci_master_info[MASTER_1]. + reset_complete); + } + } + if ((irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + } + if ((irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) || + (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE; + msm_camera_io_w_mb(CCI_M0_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE; + msm_camera_io_w_mb(CCI_M1_RESET_RMSK, + cci_dev->base + CCI_RESET_CMD_ADDR); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { + pr_err("%s:%d MASTER_0 error 0x%x\n", __func__, __LINE__, irq); + cci_dev->cci_master_info[MASTER_0].status = -EINVAL; + msm_camera_io_w_mb(CCI_M0_HALT_REQ_RMSK, + cci_dev->base + CCI_HALT_REQ_ADDR); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { + pr_err("%s:%d MASTER_1 error 0x%x\n", __func__, __LINE__, irq); + cci_dev->cci_master_info[MASTER_1].status = -EINVAL; + msm_camera_io_w_mb(CCI_M1_HALT_REQ_RMSK, + cci_dev->base + CCI_HALT_REQ_ADDR); + } + return IRQ_HANDLED; +} + +static int msm_cci_irq_routine(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + irqreturn_t ret; + CDBG("%s line %d\n", __func__, __LINE__); + ret = msm_cci_irq(cci_dev->irq->start, cci_dev); + CDBG("%s: msm_cci_irq return %d\n", __func__, ret); + *handled = TRUE; + return 0; +} + +static long msm_cci_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + CDBG("%s line %d\n", __func__, __LINE__); + switch (cmd) { + case VIDIOC_MSM_CCI_CFG: + rc = msm_cci_config(sd, arg); + break; + case MSM_SD_SHUTDOWN: { + return rc; + } + default: + rc = -ENOIOCTLCMD; + } + CDBG("%s line %d rc %d\n", __func__, __LINE__, rc); + return rc; +} + +static struct v4l2_subdev_core_ops msm_cci_subdev_core_ops = { + .g_chip_ident = &msm_cci_subdev_g_chip_ident, + .ioctl = &msm_cci_subdev_ioctl, + .interrupt_service_routine = msm_cci_irq_routine, +}; + +static const struct v4l2_subdev_ops msm_cci_subdev_ops = { + .core = &msm_cci_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_cci_internal_ops; + +static void msm_cci_init_cci_params(struct cci_device *new_cci_dev) +{ + uint8_t i = 0, j = 0; + for (i = 0; i < NUM_MASTERS; i++) { + new_cci_dev->cci_master_info[i].status = 0; + mutex_init(&new_cci_dev->cci_master_info[i].mutex); + init_completion(&new_cci_dev-> + cci_master_info[i].reset_complete); + for (j = 0; j < NUM_QUEUES; j++) { + if (j == QUEUE_0) + new_cci_dev->cci_i2c_queue_info[i][j]. + max_queue_size = CCI_I2C_QUEUE_0_SIZE; + else + new_cci_dev->cci_i2c_queue_info[i][j]. + max_queue_size = CCI_I2C_QUEUE_1_SIZE; + } + } + return; +} + +static int32_t msm_cci_init_gpio_params(struct cci_device *cci_dev) +{ + int32_t rc = 0, i = 0; + uint32_t *val_array = NULL; + uint8_t tbl_size = 0; + struct device_node *of_node = cci_dev->pdev->dev.of_node; + struct gpio *gpio_tbl = NULL; + + cci_dev->cci_gpio_tbl_size = tbl_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, tbl_size); + if (!tbl_size) { + pr_err("%s:%d gpio count 0\n", __func__, __LINE__); + return 0; + } + + gpio_tbl = cci_dev->cci_gpio_tbl = + kzalloc(sizeof(struct gpio) * tbl_size, GFP_KERNEL); + if (!gpio_tbl) { + pr_err("%s failed %d\n", __func__, __LINE__); + return 0; + } + + for (i = 0; i < tbl_size; i++) { + gpio_tbl[i].gpio = of_get_gpio(of_node, i); + CDBG("%s gpio_tbl[%d].gpio = %d\n", __func__, i, + gpio_tbl[i].gpio); + } + + val_array = kzalloc(sizeof(uint32_t) * tbl_size, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-tbl-flags", + val_array, tbl_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < tbl_size; i++) { + gpio_tbl[i].flags = val_array[i]; + CDBG("%s gpio_tbl[%d].flags = %ld\n", __func__, i, + gpio_tbl[i].flags); + } + + for (i = 0; i < tbl_size; i++) { + rc = of_property_read_string_index(of_node, + "qcom,gpio-tbl-label", i, &gpio_tbl[i].label); + CDBG("%s gpio_tbl[%d].label = %s\n", __func__, i, + gpio_tbl[i].label); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + } + + kfree(val_array); + return rc; + +ERROR2: + kfree(val_array); +ERROR1: + kfree(cci_dev->cci_gpio_tbl); + cci_dev->cci_gpio_tbl = NULL; + cci_dev->cci_gpio_tbl_size = 0; + return rc; +} + +static void msm_cci_init_default_clk_params(struct cci_device *cci_dev, + uint8_t index) +{ + /* default clock params are for 100Khz */ + cci_dev->cci_clk_params[index].hw_thigh = 78; + cci_dev->cci_clk_params[index].hw_tlow = 114; + cci_dev->cci_clk_params[index].hw_tsu_sto = 28; + cci_dev->cci_clk_params[index].hw_tsu_sta = 28; + cci_dev->cci_clk_params[index].hw_thd_dat = 10; + cci_dev->cci_clk_params[index].hw_thd_sta = 77; + cci_dev->cci_clk_params[index].hw_tbuf = 118; + cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0; + cci_dev->cci_clk_params[index].hw_trdhld = 6; + cci_dev->cci_clk_params[index].hw_tsp = 1; +} + +static void msm_cci_init_clk_params(struct cci_device *cci_dev) +{ + int32_t rc = 0; + uint32_t val = 0; + uint8_t count = 0; + struct device_node *of_node = cci_dev->pdev->dev.of_node; + struct device_node *src_node = NULL; + + for (count = 0; count < I2C_MAX_MODES; count++) { + + if (I2C_STANDARD_MODE == count) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_standard_mode"); + else if (I2C_FAST_MODE == count) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_fast_mode"); + else + src_node = of_find_node_by_name(of_node, + "qcom,i2c_custom_mode"); + + rc = of_property_read_u32(src_node, "qcom,hw-thigh", &val); + CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc); + if (!rc) { + cci_dev->cci_clk_params[count].hw_thigh = val; + rc = of_property_read_u32(src_node, "qcom,hw-tlow", + &val); + CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tlow = val; + rc = of_property_read_u32(src_node, "qcom,hw-tsu-sto", + &val); + CDBG("%s qcom,hw-tsu-sto %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sto = val; + rc = of_property_read_u32(src_node, "qcom,hw-tsu-sta", + &val); + CDBG("%s qcom,hw-tsu-sta %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sta = val; + rc = of_property_read_u32(src_node, "qcom,hw-thd-dat", + &val); + CDBG("%s qcom,hw-thd-dat %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_dat = val; + rc = of_property_read_u32(src_node, "qcom,hw-thd-sta", + &val); + CDBG("%s qcom,hw-thd-sta %d, rc %d\n", __func__, + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_sta = val; + rc = of_property_read_u32(src_node, "qcom,hw-tbuf", + &val); + CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tbuf = val; + rc = of_property_read_u32(src_node, + "qcom,hw-scl-stretch-en", &val); + CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_scl_stretch_en = val; + rc = of_property_read_u32(src_node, "qcom,hw-trdhld", + &val); + CDBG("%s qcom,hw-trdhld %d, rc %d\n", + __func__, val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_trdhld = val; + rc = of_property_read_u32(src_node, "qcom,hw-tsp", + &val); + CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc); + } + if (!rc) + cci_dev->cci_clk_params[count].hw_tsp = val; + else + msm_cci_init_default_clk_params(cci_dev, count); + of_node_put(src_node); + src_node = NULL; + } + return; +} + +struct v4l2_subdev *msm_cci_get_subdev(void) +{ + return g_cci_subdev; +} + +static int msm_cci_get_clk_info(struct cci_device *cci_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[CCI_NUM_CLK_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + cci_dev->num_clk = count; + + CDBG("%s: count = %d\n", __func__, count); + if (count == 0) { + pr_err("%s: no clocks found in device tree, count=%d", + __func__, count); + return 0; + } + + if (count > CCI_NUM_CLK_MAX) { + pr_err("%s: invalid count=%d, max is %d\n", __func__, + count, CCI_NUM_CLK_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(cci_clk_info[i].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + i, cci_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + cci_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, + cci_clk_info[i].clk_rate); + } + return 0; +} + +static int msm_cci_probe(struct platform_device *pdev) +{ + struct cci_device *new_cci_dev; + int rc = 0; + pr_err("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id); + new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL); + if (!new_cci_dev) { + CDBG("%s: no enough memory\n", __func__); + return -ENOMEM; + } + v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops); + new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops; + snprintf(new_cci_dev->msm_sd.sd.name, + ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci"); + v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev); + platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd); + CDBG("%s sd %p\n", __func__, &new_cci_dev->msm_sd.sd); + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + + rc = msm_cci_get_clk_info(new_cci_dev, pdev); + if (rc < 0) { + pr_err("%s: msm_cci_get_clk_info() failed", __func__); + return -EFAULT; + } + + new_cci_dev->ref_count = 0; + new_cci_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "cci"); + if (!new_cci_dev->mem) { + CDBG("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto cci_no_resource; + } + new_cci_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "cci"); + CDBG("%s line %d cci irq start %d end %d\n", __func__, + __LINE__, + (int) new_cci_dev->irq->start, + (int) new_cci_dev->irq->end); + if (!new_cci_dev->irq) { + CDBG("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto cci_no_resource; + } + new_cci_dev->io = request_mem_region(new_cci_dev->mem->start, + resource_size(new_cci_dev->mem), pdev->name); + if (!new_cci_dev->io) { + CDBG("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto cci_no_resource; + } + + new_cci_dev->base = ioremap(new_cci_dev->mem->start, + resource_size(new_cci_dev->mem)); + if (!new_cci_dev->base) { + rc = -ENOMEM; + goto cci_release_mem; + } + rc = request_irq(new_cci_dev->irq->start, msm_cci_irq, + IRQF_TRIGGER_RISING, "cci", new_cci_dev); + if (rc < 0) { + CDBG("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto cci_release_mem; + } + disable_irq(new_cci_dev->irq->start); + new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6; + msm_sd_register(&new_cci_dev->msm_sd); + new_cci_dev->pdev = pdev; + msm_cci_init_cci_params(new_cci_dev); + msm_cci_init_clk_params(new_cci_dev); + msm_cci_init_gpio_params(new_cci_dev); + rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (rc) + pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc); + new_cci_dev->cci_state = CCI_STATE_DISABLED; + g_cci_subdev = &new_cci_dev->msm_sd.sd; + CDBG("%s cci subdev %p\n", __func__, &new_cci_dev->msm_sd.sd); + CDBG("%s line %d\n", __func__, __LINE__); + return 0; + +cci_release_mem: + release_mem_region(new_cci_dev->mem->start, + resource_size(new_cci_dev->mem)); +cci_no_resource: + kfree(new_cci_dev); + return 0; +} + +static int __exit msm_cci_exit(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev = platform_get_drvdata(pdev); + struct cci_device *cci_dev = + v4l2_get_subdevdata(subdev); + release_mem_region(cci_dev->mem->start, resource_size(cci_dev->mem)); + kfree(cci_dev); + return 0; +} + +static const struct of_device_id msm_cci_dt_match[] = { + {.compatible = "qcom,cci"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_cci_dt_match); + +static struct platform_driver cci_driver = { + .probe = msm_cci_probe, + .remove = msm_cci_exit, + .driver = { + .name = MSM_CCI_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_cci_dt_match, + }, +}; + +static int __init msm_cci_init_module(void) +{ + return platform_driver_register(&cci_driver); +} + +static void __exit msm_cci_exit_module(void) +{ + platform_driver_unregister(&cci_driver); +} + +module_init(msm_cci_init_module); +module_exit(msm_cci_exit_module); +MODULE_DESCRIPTION("MSM CCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cci.h new file mode 100644 index 0000000000000000000000000000000000000000..1e50388cc3ff0aa5d7769c57d4df6dc85f2e50cd --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/cci/msm_cci.h @@ -0,0 +1,189 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CCI_H +#define MSM_CCI_H + +#include +#include +#include +#include +#include "../../include/media/msm_cam_sensor.h" +#include "../../include/soc/qcom/camera2.h" +#include "msm_sd.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#define CCI_PINCTRL_STATE_DEFAULT "cci_default" +#define CCI_PINCTRL_STATE_SLEEP "cci_suspend" +#define CCI_NUM_CLK_MAX 16 + + +enum cci_i2c_queue_t { + QUEUE_0, + QUEUE_1, +}; + +struct msm_camera_cci_client { + struct v4l2_subdev *cci_subdev; + uint32_t freq; + enum i2c_freq_mode_t i2c_freq_mode; + enum cci_i2c_master_t cci_i2c_master; + uint16_t sid; + uint16_t cid; + uint32_t timeout; + uint16_t retries; + uint16_t id_map; +}; + +enum msm_cci_cmd_type { + MSM_CCI_INIT, + MSM_CCI_RELEASE, + MSM_CCI_SET_SID, + MSM_CCI_SET_FREQ, + MSM_CCI_SET_SYNC_CID, + MSM_CCI_I2C_READ, + MSM_CCI_I2C_WRITE, + MSM_CCI_GPIO_WRITE, + MSM_CCI_I2C_WRITE_BURST, +}; + +struct msm_camera_cci_wait_sync_cfg { + uint16_t line; + uint16_t delay; +}; + +struct msm_camera_cci_gpio_cfg { + uint16_t gpio_queue; + uint16_t i2c_queue; +}; + +struct msm_camera_cci_i2c_read_cfg { + uint16_t addr; + enum msm_camera_i2c_reg_addr_type addr_type; + uint8_t *data; + uint16_t num_byte; +}; + +struct msm_camera_cci_i2c_queue_info { + uint32_t max_queue_size; + uint32_t report_id; + uint32_t irq_en; + uint32_t capture_rep_data; +}; + +struct msm_camera_cci_ctrl { + int32_t status; + struct msm_camera_cci_client *cci_info; + enum msm_cci_cmd_type cmd; + union { + struct msm_camera_i2c_reg_setting cci_i2c_write_cfg; + struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg; + struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg; + struct msm_camera_cci_gpio_cfg gpio_cfg; + } cfg; +}; + +struct msm_camera_cci_master_info { + uint32_t status; + uint8_t reset_pending; + struct mutex mutex; + struct completion reset_complete; +}; + +struct msm_cci_clk_params_t { + uint16_t hw_thigh; + uint16_t hw_tlow; + uint16_t hw_tsu_sto; + uint16_t hw_tsu_sta; + uint16_t hw_thd_dat; + uint16_t hw_thd_sta; + uint16_t hw_tbuf; + uint8_t hw_scl_stretch_en; + uint8_t hw_trdhld; + uint8_t hw_tsp; +}; + +enum msm_cci_state_t { + CCI_STATE_ENABLED, + CCI_STATE_DISABLED, +}; + +struct cci_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *irq; + struct resource *io; + void __iomem *base; + + uint32_t hw_version; + uint8_t ref_count; + enum msm_cci_state_t cci_state; + uint32_t num_clk; + + struct clk *cci_clk[CCI_NUM_CLK_MAX]; + struct msm_camera_cci_i2c_queue_info + cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; + struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS]; + struct msm_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; + struct gpio *cci_gpio_tbl; + uint8_t cci_gpio_tbl_size; + uint8_t master_clk_init[MASTER_MAX]; + struct msm_pinctrl_info cci_pinctrl; + uint8_t cci_pinctrl_status; +}; + +enum msm_cci_i2c_cmd_type { + CCI_I2C_SET_PARAM_CMD = 1, + CCI_I2C_WAIT_CMD, + CCI_I2C_WAIT_SYNC_CMD, + CCI_I2C_WAIT_GPIO_EVENT_CMD, + CCI_I2C_TRIG_I2C_EVENT_CMD, + CCI_I2C_LOCK_CMD, + CCI_I2C_UNLOCK_CMD, + CCI_I2C_REPORT_CMD, + CCI_I2C_WRITE_CMD, + CCI_I2C_READ_CMD, + CCI_I2C_WRITE_DISABLE_P_CMD, + CCI_I2C_READ_DISABLE_P_CMD, + CCI_I2C_WRITE_CMD2, + CCI_I2C_WRITE_CMD3, + CCI_I2C_REPEAT_CMD, + CCI_I2C_INVALID_CMD, +}; + +enum msm_cci_gpio_cmd_type { + CCI_GPIO_SET_PARAM_CMD = 1, + CCI_GPIO_WAIT_CMD, + CCI_GPIO_WAIT_SYNC_CMD, + CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD, + CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD, + CCI_GPIO_OUT_CMD, + CCI_GPIO_TRIG_EVENT_CMD, + CCI_GPIO_REPORT_CMD, + CCI_GPIO_REPEAT_CMD, + CCI_GPIO_CONTINUE_CMD, + CCI_GPIO_INVALID_CMD, +}; + +struct v4l2_subdev *msm_cci_get_subdev(void); + +#define VIDIOC_MSM_CCI_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *) + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..842167192b7090686eedf4781652bc45f626a311 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSM_CSID) += msm_csid.o diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_2_0_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_2_0_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..7bfeb200c80ae9ad99ffd65b35f8a1178abd41e4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_2_0_hwreg.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSID_2_0_HWREG_H +#define MSM_CSID_2_0_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v2_0 = { + + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x4, + 0x8, + 0xc, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x5c, + 0x60, + 0x64, + 0x68, + 0x6c, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x9C, + 0xA0, + 0xA8, + 0xAC, + 0xB0, + 11, + 0x7FFF, + 0x2, + 17, + 0x02000011, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_2_2_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_2_2_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..4ad1c2924b1f21f2b530154347b7f645f5b04ab3 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_2_2_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSID_2_2_HWREG_H +#define MSM_CSID_2_2_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v2_2 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x4, + 0x8, + 0xc, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x5c, + 0x60, + 0x64, + 0x68, + 0x6c, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x9C, + 0xA0, + 0xA8, + 0xAC, + 0xB0, + 11, + 0x7FFF, + 0x2, + 17, + 0x02001000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_0_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_0_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..980f497e4596e3a5f5bf9d0bc73a8fe00168606a --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_0_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSID_3_0_HWREG_H +#define MSM_CSID_3_0_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v3_0 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30000000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_1_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_1_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..d53867f5e5c5f84561bb3e014e69d86abc4eef8a --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_1_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSID_3_1_HWREG_H +#define MSM_CSID_3_1_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v3_1 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30010000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_2_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_2_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..b002d78e6f043a261e53b138028a007ce670862e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/include/msm_csid_3_2_hwreg.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSID_3_2_HWREG_H +#define MSM_CSID_3_2_HWREG_H + +#include "msm_csid.h" + +struct csid_reg_parms_t csid_v3_2 = { + /* MIPI CSID registers */ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x14, + 0x18, + 0x1C, + 0x20, + 0x60, + 0x64, + 0x68, + 0x6C, + 0x70, + 0x74, + 0x78, + 0x7C, + 0x80, + 0x84, + 0x88, + 0x8C, + 0x90, + 0x94, + 0x98, + 0xA0, + 0xA4, + 0xAC, + 0xB0, + 0xB4, + 11, + 0x7FFF, + 0x4, + 17, + 0x30020000, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/msm_csid.c new file mode 100644 index 0000000000000000000000000000000000000000..4be76b94903b893c79e634d8b986447d09a189f4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/msm_csid.c @@ -0,0 +1,844 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include "msm_csid.h" +#include "msm_sd.h" +#include "msm_camera_io_util.h" +#include "include/msm_csid_2_0_hwreg.h" +#include "include/msm_csid_2_2_hwreg.h" +#include "include/msm_csid_3_0_hwreg.h" +#include "include/msm_csid_3_1_hwreg.h" +#include "include/msm_csid_3_2_hwreg.h" + +#define V4L2_IDENT_CSID 50002 +#define CSID_VERSION_V20 0x02000011 +#define CSID_VERSION_V22 0x02001000 +#define CSID_VERSION_V30 0x30000000 +#define CSID_VERSION_V31 0x30010000 +#define CSID_VERSION_V31_1 0x30010001 +#define CSID_VERSION_V32 0x30020000 +#define CSID_VERSION_V33 0x30030000 +#define CSID_VERSION_V34 0x30040000 +#define CSID_VERSION_V40 0x40000000 +#define MSM_CSID_DRV_NAME "msm_csid" + +#define DBG_CSID 0 + +#define TRUE 1 +#define FALSE 0 + +#define CSID_NUM_CLK_MAX 16 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif +static struct msm_cam_clk_info csid_clk_info[CSID_NUM_CLK_MAX]; +static struct msm_cam_clk_info csid_clk_src_info[CSID_NUM_CLK_MAX]; + +static struct camera_vreg_t csid_vreg_info[] = { + {"qcom,mipi-csi-vdd", REG_LDO, 0, 0, 12000}, +}; + +static struct camera_vreg_t csid_8960_vreg_info[] = { + {"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000}, +}; + +static int msm_csid_cid_lut( + struct msm_camera_csid_lut_params *csid_lut_params, + struct csid_device *csid_dev) +{ + int rc = 0, i = 0; + uint32_t val = 0; + + if (!csid_lut_params) { + pr_err("%s:%d csid_lut_params NULL\n", __func__, __LINE__); + return -EINVAL; + } + for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) { + if (csid_lut_params->vc_cfg[i]->cid >= + csid_lut_params->num_cid || + csid_lut_params->vc_cfg[i]->cid < 0) { + pr_err("%s: cid outside range %d\n", + __func__, csid_lut_params->vc_cfg[i]->cid); + return -EINVAL; + } + CDBG("%s lut params num_cid = %d, cid = %d\n", + __func__, + csid_lut_params->num_cid, + csid_lut_params->vc_cfg[i]->cid); + CDBG("%s lut params dt = 0x%x, df = %d\n", __func__, + csid_lut_params->vc_cfg[i]->dt, + csid_lut_params->vc_cfg[i]->decode_format); + if (csid_lut_params->vc_cfg[i]->dt < 0x12 || + csid_lut_params->vc_cfg[i]->dt > 0x37) { + pr_err("%s: unsupported data type 0x%x\n", + __func__, csid_lut_params->vc_cfg[i]->dt); + return rc; + } + val = msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + + (csid_lut_params->vc_cfg[i]->cid >> 2) * 4) + & ~(0xFF << ((csid_lut_params->vc_cfg[i]->cid % 4) * + 8)); + val |= (csid_lut_params->vc_cfg[i]->dt << + ((csid_lut_params->vc_cfg[i]->cid % 4) * 8)); + msm_camera_io_w(val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_cid_lut_vc_0_addr + + (csid_lut_params->vc_cfg[i]->cid >> 2) * 4); + + val = (csid_lut_params->vc_cfg[i]->decode_format << 4) | 0x3; + msm_camera_io_w(val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_cid_n_cfg_addr + + (csid_lut_params->vc_cfg[i]->cid * 4)); + } + return rc; +} + +#if DBG_CSID +static void msm_csid_set_debug_reg(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) +{ + uint32_t val = 0; + val = ((1 << csid_params->lane_cnt) - 1) << 20; + msm_camera_io_w(0x7f010800 | val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); + msm_camera_io_w(0x7f010800 | val, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); +} +#else +static void msm_csid_set_debug_reg(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) {} +#endif + +static void msm_csid_reset(struct csid_device *csid_dev) +{ + msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all, + csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr); + wait_for_completion(&csid_dev->reset_complete); + return; +} + +static int msm_csid_config(struct csid_device *csid_dev, + struct msm_camera_csid_params *csid_params) +{ + int rc = 0; + uint32_t val = 0; + void __iomem *csidbase; + csidbase = csid_dev->base; + if (!csidbase || !csid_params) { + pr_err("%s:%d csidbase %p, csid params %p\n", __func__, + __LINE__, csidbase, csid_params); + return -EINVAL; + } + + CDBG("%s csid_params, lane_cnt = %d, lane_assign = 0x%x\n", + __func__, + csid_params->lane_cnt, + csid_params->lane_assign); + CDBG("%s csid_params phy_sel = %d\n", __func__, + csid_params->phy_sel); + + msm_csid_reset(csid_dev); + + val = csid_params->lane_cnt - 1; + val |= csid_params->lane_assign << + csid_dev->ctrl_reg->csid_reg.csid_dl_input_sel_shift; + if (csid_dev->hw_version < 0x30000000) { + val |= (0xF << 10); + msm_camera_io_w(val, csidbase + + csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); + } else { + msm_camera_io_w(val, csidbase + + csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_0_addr); + val = csid_params->phy_sel << + csid_dev->ctrl_reg->csid_reg.csid_phy_sel_shift; + val |= 0xF; + msm_camera_io_w(val, csidbase + + csid_dev->ctrl_reg->csid_reg.csid_core_ctrl_1_addr); + } + + rc = msm_csid_cid_lut(&csid_params->lut_params, csid_dev); + if (rc < 0) + return rc; + + msm_csid_set_debug_reg(csid_dev, csid_params); + return rc; +} + +static irqreturn_t msm_csid_irq(int irq_num, void *data) +{ + uint32_t irq; + struct csid_device *csid_dev; + void __iomem *csidbase; + + if (!data) { + pr_err("%s:%d data NULL\n", __func__, __LINE__); + return IRQ_HANDLED; + }//prevent + csid_dev = data ; + if (!csid_dev->base) { + pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__); + return IRQ_HANDLED; + } + csidbase = csid_dev->base; + irq = msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); + CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n", + __func__, csid_dev->pdev->id, irq); + if (irq & (0x1 << + csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift)) + complete(&csid_dev->reset_complete); + msm_camera_io_w(irq, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); + return IRQ_HANDLED; +} + +static int msm_csid_irq_routine(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct csid_device *csid_dev = v4l2_get_subdevdata(sd); + irqreturn_t ret; + CDBG("%s E\n", __func__); + ret = msm_csid_irq(csid_dev->irq->start, csid_dev); + *handled = TRUE; + return 0; +} + +static int msm_csid_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_CSID; + chip->revision = 0; + return 0; +} + +static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version) +{ + int rc = 0; + + if (!csid_version) { + pr_err("%s:%d csid_version NULL\n", __func__, __LINE__); + rc = -EINVAL; + return rc; + } + + if (csid_dev->csid_state == CSID_POWER_UP) { + pr_err("%s: csid invalid state %d\n", __func__, + csid_dev->csid_state); + rc = -EINVAL; + return rc; + } + + csid_dev->base = ioremap(csid_dev->mem->start, + resource_size(csid_dev->mem)); + if (!csid_dev->base) { + pr_err("%s csid_dev->base NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + pr_info("%s: CSID_VERSION = 0x%x\n", __func__, + csid_dev->ctrl_reg->csid_reg.csid_version); + /* power up */ + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + rc = msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } else { + rc = msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } + if (rc < 0) { + pr_err("%s: regulator on failed\n", __func__); + goto vreg_config_failed; + } + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } else { + rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 1); + } + if (rc < 0) { + pr_err("%s: regulator enable failed\n", __func__); + goto vreg_enable_failed; + } + + if (csid_dev->ctrl_reg->csid_reg.csid_version == CSID_VERSION_V22) + msm_cam_clk_sel_src(&csid_dev->pdev->dev, + &csid_clk_info[3], csid_clk_src_info, + csid_dev->num_clk_src_info); + + + rc = msm_cam_clk_enable(&csid_dev->pdev->dev, + csid_clk_info, csid_dev->csid_clk, + csid_dev->num_clk, 1); + if (rc < 0) { + pr_err("%s:%d clock enable failed\n", + __func__, __LINE__); + goto clk_enable_failed; + } + CDBG("%s:%d called\n", __func__, __LINE__); + csid_dev->hw_version = + msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_hw_version_addr); + CDBG("%s:%d called csid_dev->hw_version %x\n", __func__, __LINE__, + csid_dev->hw_version); + *csid_version = csid_dev->hw_version; + + init_completion(&csid_dev->reset_complete); + + enable_irq(csid_dev->irq->start); + + msm_csid_reset(csid_dev); + csid_dev->csid_state = CSID_POWER_UP; + return rc; + +clk_enable_failed: + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else { + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } +vreg_enable_failed: + if (csid_dev->ctrl_reg->csid_reg.csid_version < CSID_VERSION_V22) { + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else { + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } +vreg_config_failed: + iounmap(csid_dev->base); + csid_dev->base = NULL; + return rc; +} + +static int msm_csid_release(struct csid_device *csid_dev) +{ + uint32_t irq; + + if (csid_dev->csid_state != CSID_POWER_UP) { + pr_err("%s: csid invalid state %d\n", __func__, + csid_dev->csid_state); + return -EINVAL; + } + + CDBG("%s:%d, hw_version = 0x%x\n", __func__, __LINE__, + csid_dev->hw_version); + + irq = msm_camera_io_r(csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr); + msm_camera_io_w(irq, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr); + msm_camera_io_w(0, csid_dev->base + + csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr); + + disable_irq(csid_dev->irq->start); + + if (csid_dev->hw_version == CSID_VERSION_V20) { + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, csid_dev->num_clk, 0); + + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else if (csid_dev->hw_version == CSID_VERSION_V22) { + msm_cam_clk_enable(&csid_dev->pdev->dev, + csid_clk_info, + csid_dev->csid_clk, + csid_dev->num_clk, 0); + + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else if ((csid_dev->hw_version >= CSID_VERSION_V30 && + csid_dev->hw_version < CSID_VERSION_V31) || + (csid_dev->hw_version == CSID_VERSION_V40) || + (csid_dev->hw_version == CSID_VERSION_V31_1)) { + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, csid_dev->num_clk, 0); + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else if ((csid_dev->hw_version == CSID_VERSION_V31) || + (csid_dev->hw_version == CSID_VERSION_V32) || + (csid_dev->hw_version == CSID_VERSION_V33) || + (csid_dev->hw_version == CSID_VERSION_V34)) { + msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info, + csid_dev->csid_clk, csid_dev->num_clk, 0); + msm_camera_enable_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + + msm_camera_config_vreg(&csid_dev->pdev->dev, + csid_vreg_info, ARRAY_SIZE(csid_vreg_info), + NULL, 0, &csid_dev->csi_vdd, 0); + } else { + pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, + csid_dev->hw_version); + return -EINVAL; + } + + iounmap(csid_dev->base); + csid_dev->base = NULL; + csid_dev->csid_state = CSID_POWER_DOWN; + return 0; +} + +static int32_t msm_csid_cmd(struct csid_device *csid_dev, void *arg) +{ + int rc = 0; + struct csid_cfg_data *cdata = (struct csid_cfg_data *)arg; + + if (!csid_dev || !cdata) { + pr_err("%s:%d csid_dev %p, cdata %p\n", __func__, __LINE__, + csid_dev, cdata); + return -EINVAL; + } + CDBG("%s cfgtype = %d\n", __func__, cdata->cfgtype); + switch (cdata->cfgtype) { + case CSID_INIT: + rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version); + CDBG("%s csid version 0x%x\n", __func__, + cdata->cfg.csid_version); + break; + case CSID_CFG: { + struct msm_camera_csid_params csid_params; + struct msm_camera_csid_vc_cfg *vc_cfg = NULL; + int8_t i = 0; + if (copy_from_user(&csid_params, + (void *)cdata->cfg.csid_params, + sizeof(struct msm_camera_csid_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + if (csid_params.lut_params.num_cid < 1 || + csid_params.lut_params.num_cid > 16) { + pr_err("%s: %d num_cid outside range\n", + __func__, __LINE__); + rc = -EINVAL; + break; + } + for (i = 0; i < csid_params.lut_params.num_cid; i++) { + vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg), + GFP_KERNEL); + if (!vc_cfg) { + pr_err("%s: %d failed\n", __func__, __LINE__); + for (i--; i >= 0; i--) + kfree(csid_params.lut_params.vc_cfg[i]); + rc = -ENOMEM; + break; + } + if (copy_from_user(vc_cfg, + (void *)csid_params.lut_params.vc_cfg[i], + sizeof(struct msm_camera_csid_vc_cfg))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + kfree(vc_cfg); + for (i--; i >= 0; i--) + kfree(csid_params.lut_params.vc_cfg[i]); + rc = -EFAULT; + break; + } + csid_params.lut_params.vc_cfg[i] = vc_cfg; + } + rc = msm_csid_config(csid_dev, &csid_params); + for (i--; i >= 0; i--) + kfree(csid_params.lut_params.vc_cfg[i]); + break; + } + case CSID_RELEASE: + rc = msm_csid_release(csid_dev); + break; + default: + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -ENOIOCTLCMD; + break; + } + return rc; +} + +static int32_t msm_csid_get_subdev_id(struct csid_device *csid_dev, void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EINVAL; + } + *subdev_id = csid_dev->pdev->id; + pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); + return 0; +} + +static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = -ENOIOCTLCMD; + struct csid_device *csid_dev = v4l2_get_subdevdata(sd); + mutex_lock(&csid_dev->mutex); + CDBG("%s:%d id %d\n", __func__, __LINE__, csid_dev->pdev->id); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + rc = msm_csid_get_subdev_id(csid_dev, arg); + break; + case VIDIOC_MSM_CSID_IO_CFG: + rc = msm_csid_cmd(csid_dev, arg); + break; + case VIDIOC_MSM_CSID_RELEASE: + case MSM_SD_SHUTDOWN: + rc = msm_csid_release(csid_dev); + break; + default: + pr_err_ratelimited("%s: command not found\n", __func__); + } + CDBG("%s:%d\n", __func__, __LINE__); + mutex_unlock(&csid_dev->mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_csid_internal_ops; + +static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = { + .g_chip_ident = &msm_csid_subdev_g_chip_ident, + .ioctl = &msm_csid_subdev_ioctl, + .interrupt_service_routine = msm_csid_irq_routine, +}; + +static const struct v4l2_subdev_ops msm_csid_subdev_ops = { + .core = &msm_csid_subdev_core_ops, +}; + +static int msm_csid_get_clk_info(struct csid_device *csid_dev, + struct platform_device *pdev) +{ + uint32_t count; + uint32_t cnt = 0; + int i, rc; + int ii = 0; + uint32_t rates[CSID_NUM_CLK_MAX]; + const char *clock_name; + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + csid_dev->num_clk = count; + + CDBG("%s: count = %d\n", __func__, count); + if (count == 0) { + pr_err("%s: no clocks found in device tree, count=%d", + __func__, count); + return -EINVAL; + } + + if (count > CSID_NUM_CLK_MAX) { + pr_err("%s: invalid count=%d, max is %d\n", __func__, + count, CSID_NUM_CLK_MAX); + return -EINVAL; + } + + if (csid_dev->hw_dts_version == CSID_VERSION_V22) { + cnt = count; + count = 0; + CDBG("%s: cnt = %d\n", __func__, cnt); + if (cnt == 0) { + pr_err("%s: no clocks found in device tree, cnt=%d", + __func__, cnt); + return -EINVAL; + } + + if (cnt > CSID_NUM_CLK_MAX) { + pr_err("%s: invalid cnt=%d, max is %d\n", __func__, + cnt, CSID_NUM_CLK_MAX); + return -EINVAL; + } + + for (i = 0; i < cnt; i++) { + count++; + rc = of_property_read_string_index(of_node, + "clock-names", i, &clock_name); + CDBG("%s: clock_names[%d] = %s\n", __func__, + i, clock_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + if (strcmp(clock_name, "csi_phy_src_clk") == 0) + break; + } + csid_dev->num_clk = count; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(csid_clk_info[i].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + i, csid_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + csid_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, + csid_clk_info[i].clk_rate); + } + + if (csid_dev->hw_dts_version == CSID_VERSION_V22) { + csid_dev->num_clk_src_info = cnt - count; + CDBG("%s: count = %d\n", __func__, (cnt - count)); + + for (i = count; i < cnt; i++) { + ii++; + rc = of_property_read_string_index(of_node, + "clock-names", i, + &(csid_clk_src_info[ii].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + ii, csid_clk_src_info[ii].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + ii = 0; + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, cnt); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = count; i < cnt; i++) { + ii++; + csid_clk_src_info[ii].clk_rate = rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, ii, + csid_clk_src_info[ii].clk_rate); + } + } + return 0; +} + +static int csid_probe(struct platform_device *pdev) +{ + struct csid_device *new_csid_dev; + uint32_t csi_vdd_voltage = 0; + int rc = 0; + new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL); + if (!new_csid_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + new_csid_dev->ctrl_reg = NULL; + new_csid_dev->ctrl_reg = kzalloc(sizeof(struct csid_ctrl_t), + GFP_KERNEL); + if (!new_csid_dev->ctrl_reg) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + kfree(new_csid_dev); + return -ENOMEM; + } + + v4l2_subdev_init(&new_csid_dev->msm_sd.sd, &msm_csid_subdev_ops); + v4l2_set_subdevdata(&new_csid_dev->msm_sd.sd, new_csid_dev); + platform_set_drvdata(pdev, &new_csid_dev->msm_sd.sd); + mutex_init(&new_csid_dev->mutex); + + if (pdev->dev.of_node) { + rc = of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + if (rc < 0) { + pr_err("%s:%d failed to read cell-index\n", __func__, + __LINE__); + rc = -ENODEV; + goto csid_no_resource; + } + CDBG("%s device id %d\n", __func__, pdev->id); + + rc = of_property_read_u32((&pdev->dev)->of_node, + "qcom,csi-vdd-voltage", &csi_vdd_voltage); + if (rc < 0) { + pr_err("%s:%d failed to read qcom,csi-vdd-voltage\n", + __func__, __LINE__); + rc = -ENODEV; + goto csid_no_resource; + } + CDBG("%s:%d reading mipi_csi_vdd is %d\n", __func__, __LINE__, + csi_vdd_voltage); + + csid_vreg_info[0].min_voltage = csi_vdd_voltage; + csid_vreg_info[0].max_voltage = csi_vdd_voltage; + } + + rc = msm_csid_get_clk_info(new_csid_dev, pdev); + if (rc < 0) { + pr_err("%s: msm_csid_get_clk_info() failed", __func__); + rc = -ENODEV; + goto csid_no_resource; + } + + + new_csid_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csid"); + if (!new_csid_dev->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto csid_no_resource; + } + new_csid_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "csid"); + if (!new_csid_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto csid_no_resource; + } + new_csid_dev->io = request_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem), pdev->name); + if (!new_csid_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto csid_no_resource; + } + + new_csid_dev->pdev = pdev; + new_csid_dev->msm_sd.sd.internal_ops = &msm_csid_internal_ops; + new_csid_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(new_csid_dev->msm_sd.sd.name, + ARRAY_SIZE(new_csid_dev->msm_sd.sd.name), "msm_csid"); + media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0); + new_csid_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + new_csid_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSID; + new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5; + msm_sd_register(&new_csid_dev->msm_sd); + + rc = request_irq(new_csid_dev->irq->start, msm_csid_irq, + IRQF_TRIGGER_RISING, "csid", new_csid_dev); + if (rc < 0) { + release_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem)); + pr_err("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto csid_no_resource; + } + disable_irq(new_csid_dev->irq->start); + if (rc < 0) { + release_mem_region(new_csid_dev->mem->start, + resource_size(new_csid_dev->mem)); + pr_err("%s Error registering irq ", __func__); + goto csid_no_resource; + } + + if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v2.0")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v2_0; + new_csid_dev->hw_dts_version = CSID_VERSION_V20; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v2.2")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v2_2; + new_csid_dev->hw_dts_version = CSID_VERSION_V22; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.0")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; + new_csid_dev->hw_dts_version = CSID_VERSION_V30; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v4.0")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_0; + new_csid_dev->hw_dts_version = CSID_VERSION_V40; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.1")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_1; + new_csid_dev->hw_dts_version = CSID_VERSION_V31; + } else if (of_device_is_compatible(new_csid_dev->pdev->dev.of_node, + "qcom,csid-v3.2")) { + new_csid_dev->ctrl_reg->csid_reg = csid_v3_2; + new_csid_dev->hw_dts_version = CSID_VERSION_V32; + } else { + pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, + new_csid_dev->hw_dts_version); + rc = -ENODEV; + goto csid_no_resource; + } + + new_csid_dev->csid_state = CSID_POWER_DOWN; + return 0; + +csid_no_resource: + mutex_destroy(&new_csid_dev->mutex); + kfree(new_csid_dev->ctrl_reg); + kfree(new_csid_dev); + return rc; +} + +static const struct of_device_id msm_csid_dt_match[] = { + {.compatible = "qcom,csid"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_csid_dt_match); + +static struct platform_driver csid_driver = { + .probe = csid_probe, + .driver = { + .name = MSM_CSID_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_csid_dt_match, + }, +}; + +static int __init msm_csid_init_module(void) +{ + return platform_driver_register(&csid_driver); +} + +static void __exit msm_csid_exit_module(void) +{ + platform_driver_unregister(&csid_driver); +} + +module_init(msm_csid_init_module); +module_exit(msm_csid_exit_module); +MODULE_DESCRIPTION("MSM CSID driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csid/msm_csid.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/msm_csid.h new file mode 100644 index 0000000000000000000000000000000000000000..d53fd9133fd550e79530361bfdc3afde0a583406 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csid/msm_csid.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSID_H +#define MSM_CSID_H + +#include +#include +#include +#include +#include "../../include/media/msm_cam_sensor.h" +#include "msm_sd.h" + +struct csid_reg_parms_t { +/* MIPI CSID registers */ + uint32_t csid_hw_version_addr; + uint32_t csid_core_ctrl_0_addr; + uint32_t csid_core_ctrl_1_addr; + uint32_t csid_rst_cmd_addr; + uint32_t csid_cid_lut_vc_0_addr; + uint32_t csid_cid_lut_vc_1_addr; + uint32_t csid_cid_lut_vc_2_addr; + uint32_t csid_cid_lut_vc_3_addr; + uint32_t csid_cid_n_cfg_addr; + uint32_t csid_irq_clear_cmd_addr; + uint32_t csid_irq_mask_addr; + uint32_t csid_irq_status_addr; + uint32_t csid_captured_unmapped_long_pkt_hdr_addr; + uint32_t csid_captured_mmaped_long_pkt_hdr_addr; + uint32_t csid_captured_short_pkt_addr; + uint32_t csid_captured_long_pkt_hdr_addr; + uint32_t csid_captured_long_pkt_ftr_addr; + uint32_t csid_pif_misr_dl0_addr; + uint32_t csid_pif_misr_dl1_addr; + uint32_t csid_pif_misr_dl2_addr; + uint32_t csid_pif_misr_dl3_addr; + uint32_t csid_stats_total_pkts_rcvd_addr; + uint32_t csid_stats_ecc_addr; + uint32_t csid_stats_crc_addr; + uint32_t csid_tg_ctrl_addr; + uint32_t csid_tg_vc_cfg_addr; + uint32_t csid_tg_dt_n_cfg_0_addr; + uint32_t csid_tg_dt_n_cfg_1_addr; + uint32_t csid_tg_dt_n_cfg_2_addr; + uint32_t csid_rst_done_irq_bitshift; + uint32_t csid_rst_stb_all; + uint32_t csid_dl_input_sel_shift; + uint32_t csid_phy_sel_shift; + uint32_t csid_version; +}; + +struct csid_ctrl_t { + struct csid_reg_parms_t csid_reg; +}; + +enum msm_csid_state_t { + CSID_POWER_UP, + CSID_POWER_DOWN, +}; + +struct csid_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct resource *mem; + struct resource *irq; + struct resource *io; + struct regulator *csi_vdd; + void __iomem *base; + struct mutex mutex; + struct completion reset_complete; + uint32_t hw_version; + uint32_t hw_dts_version; + enum msm_csid_state_t csid_state; + struct csid_ctrl_t *ctrl_reg; + uint32_t num_clk; + uint32_t num_clk_src_info; + + struct clk *csid_clk[11]; +}; + +#define VIDIOC_MSM_CSID_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*) +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0e8071525eb4e35143cc69da11775739f29f9da8 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSM_CSIPHY) += msm_csiphy.o diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..5abf99123365c10b009bcabd8cca871455abe6ad --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_2_0_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSIPHY_2_0_HWREG_H +#define MSM_CSIPHY_2_0_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v2_0 = { + /*MIPI CSI PHY registers*/ + 0x17C, + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x180, + 0x1A0, + 0x6F, + 0x1A4, + 0x1C0, + 0x1C4, + 0x4, + 0x1E0, + 0x1E8, + 0x0, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..8682478f7e989a1a107b55d435bb8f42574096c6 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_2_2_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSIPHY_2_2_HWREG_H +#define MSM_CSIPHY_2_2_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v2_2 = { + /*MIPI CSI PHY registers*/ + 0x17C, + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x180, + 0x1A0, + 0x6F, + 0x1A4, + 0x1C0, + 0x1C4, + 0x4, + 0x1E0, + 0x1E8, + 0x1, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..af4d3e03a7cebf51bb9bf3d0ebfefa499b5562b5 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_0_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSIPHY_3_0_HWREG_H +#define MSM_CSIPHY_3_0_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v3_0 = { + /*MIPI CSI PHY registers*/ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x188, + 0x18C, + 0x1AC, + 0x3F, + 0x1AC, + 0x1CC, + 0x1CC, + 0x4, + 0x1EC, + 0x1F4, + 0x10, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..c80a7c748fc61b40da3ac73cd5c5e87642d71bb3 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_1_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSIPHY_3_1_HWREG_H +#define MSM_CSIPHY_3_1_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v3_1 = { + /*MIPI CSI PHY registers*/ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x188, + 0x18C, + 0x1AC, + 0x3F, + 0x1AC, + 0x1CC, + 0x1CC, + 0x4, + 0x1EC, + 0x1F4, + 0x31, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..19f14e73a92cb759881959568388c1f44faf8794 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/include/msm_csiphy_3_2_hwreg.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSIPHY_3_2_HWREG_H +#define MSM_CSIPHY_3_2_HWREG_H + +#include "msm_csiphy.h" + +struct csiphy_reg_parms_t csiphy_v3_2 = { + /*MIPI CSI PHY registers*/ + 0x0, + 0x4, + 0x8, + 0xC, + 0x10, + 0x100, + 0x104, + 0x108, + 0x10C, + 0x110, + 0x128, + 0x140, + 0x144, + 0x164, + 0x188, + 0x18C, + 0x1AC, + 0x3F, + 0x1AC, + 0x1CC, + 0x1CC, + 0x4, + 0x1EC, + 0x1F4, + 0x32, +}; +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/msm_csiphy.c new file mode 100644 index 0000000000000000000000000000000000000000..83a53ed80a6d509bb4480b8822b44a6f3a044ab9 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/msm_csiphy.c @@ -0,0 +1,937 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include +#include "msm_csiphy.h" +#include "msm_sd.h" +#include "msm_camera_io_util.h" +#include "include/msm_csiphy_2_0_hwreg.h" +#include "include/msm_csiphy_2_2_hwreg.h" +#include "include/msm_csiphy_3_0_hwreg.h" +#include "include/msm_csiphy_3_1_hwreg.h" +#include "include/msm_csiphy_3_2_hwreg.h" + +#define DBG_CSIPHY 0 + +#define V4L2_IDENT_CSIPHY 50003 +#define CSIPHY_VERSION_V22 0x01 +#define CSIPHY_VERSION_V20 0x00 +#define CSIPHY_VERSION_V30 0x10 +#define CSIPHY_VERSION_V31 0x31 +#define CSIPHY_VERSION_V32 0x32 +#define MSM_CSIPHY_DRV_NAME "msm_csiphy" + +#define CSIPHY_NUM_CLK_MAX 16 + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif +static struct msm_cam_clk_info csiphy_clk_info[CSIPHY_NUM_CLK_MAX]; + +static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, + struct msm_camera_csiphy_params *csiphy_params) +{ + int rc = 0; + int j = 0; + uint32_t val = 0; + uint8_t lane_cnt = 0; + uint16_t lane_mask = 0; + void __iomem *csiphybase; + uint8_t csiphy_id = csiphy_dev->pdev->id; + csiphybase = csiphy_dev->base; + if (!csiphybase) { + pr_err("%s: csiphybase NULL\n", __func__); + return -EINVAL; + } + + csiphy_dev->lane_mask[csiphy_id] |= csiphy_params->lane_mask; + lane_mask = csiphy_dev->lane_mask[csiphy_id]; + lane_cnt = csiphy_params->lane_cnt; + if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) { + pr_err("%s: unsupported lane cnt %d\n", + __func__, csiphy_params->lane_cnt); + return rc; + } + + CDBG("%s csiphy_params, mask = 0x%x cnt = %d\n", + __func__, + csiphy_params->lane_mask, + csiphy_params->lane_cnt); + CDBG("%s csiphy_params, settle cnt = 0x%x csid %d\n", + __func__, csiphy_params->settle_cnt, + csiphy_params->csid_core); + + if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30) { + val = msm_camera_io_r(csiphy_dev->clk_mux_base); + if (csiphy_params->combo_mode && + (csiphy_params->lane_mask & 0x18)) { + val &= ~0xf0; + val |= csiphy_params->csid_core << 4; + } else { + val &= ~0xf; + val |= csiphy_params->csid_core; + } + msm_camera_io_w(val, csiphy_dev->clk_mux_base); + CDBG("%s clk mux addr %p val 0x%x\n", __func__, + csiphy_dev->clk_mux_base, val); + mb(); + } + msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_t_init_cfg0_addr); + msm_camera_io_w(0x1, csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_t_wakeup_cfg0_addr); + + if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { + val = 0x3; + msm_camera_io_w((lane_mask << 2) | val, + csiphybase + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + msm_camera_io_w(0x10, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnck_cfg2_addr); + msm_camera_io_w(csiphy_params->settle_cnt, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnck_cfg3_addr); + msm_camera_io_w(0xff, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnck_cfg4_addr); + msm_camera_io_w(0x24, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_interrupt_mask0_addr); + msm_camera_io_w(0x24, + csiphybase + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_interrupt_clear0_addr); + } else { + val = 0x1; + msm_camera_io_w((lane_mask << 1) | val, + csiphybase + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + msm_camera_io_w(csiphy_params->combo_mode << + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_mode_config_shift, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_glbl_reset_addr); + msm_camera_io_w(0xff, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg4_addr + 0x40); + } + + lane_mask &= 0x1f; + while (lane_mask & 0x1f) { + if (!(lane_mask & 0x1)) { + j++; + lane_mask >>= 1; + continue; + } + msm_camera_io_w(0x10, + csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*j); + msm_camera_io_w(csiphy_params->settle_cnt, + csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg3_addr + 0x40*j); + msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_mask_val, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_mask_addr + 0x4*j); + msm_camera_io_w(csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_mask_val, csiphybase + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_clear_addr + 0x4*j); + msm_camera_io_w(0xff, + csiphybase + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg4_addr + 0x40*j); + j++; + lane_mask >>= 1; + } + return rc; +} + +static irqreturn_t msm_csiphy_irq(int irq_num, void *data) +{ + uint32_t irq; + int i; + struct csiphy_device *csiphy_dev = data; + + for (i = 0; i < 8; i++) { + irq = msm_camera_io_r( + csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_status0_addr + 0x4*i); + msm_camera_io_w(irq, + csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_clear0_addr + 0x4*i); + pr_err("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n", + __func__, csiphy_dev->pdev->id, i, irq); + msm_camera_io_w(0x1, csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); + msm_camera_io_w(0x0, + csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_clear0_addr + 0x4*i); + } + return IRQ_HANDLED; +} + +static void msm_csiphy_reset(struct csiphy_device *csiphy_dev) +{ + msm_camera_io_w(0x1, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); + usleep_range(5000, 8000); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_reset_addr); +} + +static int msm_csiphy_subdev_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + BUG_ON(!chip); + chip->ident = V4L2_IDENT_CSIPHY; + chip->revision = 0; + return 0; +} + +static int msm_csiphy_recovery(struct csiphy_device *csiphy_dev) +{ + int i = 0; + uint16_t csi_lane_mask; + + pr_err("msm_csiphy_recovery: E\n"); + + if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { + csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; + for (i = 0; i < 4; i++) + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } else { + csi_lane_mask = 0x1f; + + csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= + ~(csi_lane_mask); + i = 0; + while (csi_lane_mask) { + if (csi_lane_mask & 0x1) { + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } + csi_lane_mask >>= 1; + i++; + } + } + + csiphy_dev->ref_count = 0; + + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_lnck_cfg2_addr); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + + if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + iounmap(csiphy_dev->clk_mux_base); + } + + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; + pr_err("msm_csiphy_recovery: X\n"); + return 0; +} + +#if DBG_CSIPHY +static int msm_csiphy_init(struct csiphy_device *csiphy_dev) +{ + int rc = 0; + if (csiphy_dev == NULL) { + pr_err("%s: csiphy_dev NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); +// rc = -EINVAL; +// return rc; + msm_csiphy_recovery(csiphy_dev); + } + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + csiphy_dev->base = ioremap(csiphy_dev->mem->start, + resource_size(csiphy_dev->mem)); + if (!csiphy_dev->base) { + pr_err("%s: csiphy_dev->base NULL\n", __func__); + csiphy_dev->ref_count--; + rc = -ENOMEM; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->hw_dts_version < CSIPHY_VERSION_V30) { + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { + pr_err("%s clk mux mem %p io %p\n", __func__, + csiphy_dev->clk_mux_mem, + csiphy_dev->clk_mux_io); + rc = -ENOMEM; + return rc; + } + csiphy_dev->clk_mux_base = ioremap( + csiphy_dev->clk_mux_mem->start, + resource_size(csiphy_dev->clk_mux_mem)); + if (!csiphy_dev->clk_mux_base) { + pr_err("%s: ERROR %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else { + pr_err("%s: ERROR Invalid CSIPHY Version %d", + __func__, __LINE__); + rc = -EINVAL; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (rc < 0) { + pr_err("%s: csiphy clk enable failed\n", __func__); + csiphy_dev->ref_count--; + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + enable_irq(csiphy_dev->irq->start); + + msm_csiphy_reset(csiphy_dev); + + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) + csiphy_dev->hw_version = + msm_camera_io_r(csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_hw_version_addr); + else + csiphy_dev->hw_version = csiphy_dev->hw_dts_version; + + CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, + csiphy_dev->hw_version); + csiphy_dev->csiphy_state = CSIPHY_POWER_UP; + return 0; +} +#else +static int msm_csiphy_init(struct csiphy_device *csiphy_dev) +{ + int rc = 0; + if (csiphy_dev == NULL) { + pr_err("%s: csiphy_dev NULL\n", __func__); + rc = -ENOMEM; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); +// rc = -EINVAL; +// return rc; + msm_csiphy_recovery(csiphy_dev); + } + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->ref_count++) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + csiphy_dev->base = ioremap(csiphy_dev->mem->start, + resource_size(csiphy_dev->mem)); + if (!csiphy_dev->base) { + pr_err("%s: csiphy_dev->base NULL\n", __func__); + csiphy_dev->ref_count--; + rc = -ENOMEM; + return rc; + } + if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) { + pr_err("%s clk mux mem %p io %p\n", __func__, + csiphy_dev->clk_mux_mem, + csiphy_dev->clk_mux_io); + rc = -ENOMEM; + return rc; + } + csiphy_dev->clk_mux_base = ioremap( + csiphy_dev->clk_mux_mem->start, + resource_size(csiphy_dev->clk_mux_mem)); + if (!csiphy_dev->clk_mux_base) { + pr_err("%s: ERROR %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 1); + } else { + pr_err("%s: ERROR Invalid CSIPHY Version %d", + __func__, __LINE__); + rc = -EINVAL; + return rc; + } + + CDBG("%s:%d called\n", __func__, __LINE__); + if (rc < 0) { + pr_err("%s: csiphy clk enable failed\n", __func__); + csiphy_dev->ref_count--; + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + return rc; + } + CDBG("%s:%d called\n", __func__, __LINE__); + + msm_csiphy_reset(csiphy_dev); + + CDBG("%s:%d called\n", __func__, __LINE__); + + if (csiphy_dev->hw_dts_version == CSIPHY_VERSION_V30) + csiphy_dev->hw_version = + msm_camera_io_r(csiphy_dev->base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_hw_version_addr); + else + csiphy_dev->hw_version = csiphy_dev->hw_dts_version; + + CDBG("%s:%d called csiphy_dev->hw_version 0x%x\n", __func__, __LINE__, + csiphy_dev->hw_version); + csiphy_dev->csiphy_state = CSIPHY_POWER_UP; + return 0; +} +#endif + +#if DBG_CSIPHY +static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) +{ + int i = 0; + struct msm_camera_csi_lane_params *csi_lane_params; + uint16_t csi_lane_mask; + csi_lane_params = (struct msm_camera_csi_lane_params *)arg; + + if (!csiphy_dev || !csiphy_dev->ref_count) { + pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); + return 0; + } + + if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); + return -EINVAL; + } + + if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { + csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; + for (i = 0; i < 4; i++) + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } else { + if (!csi_lane_params) { + pr_err("%s:%d failed: csi_lane_params %p\n", __func__, + __LINE__, csi_lane_params); + return -EINVAL; + } + csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); + + CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", + __func__, + csi_lane_params->csi_lane_assign, + csi_lane_params->csi_lane_mask); + + if (!csi_lane_mask) + csi_lane_mask = 0x1f; + + csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= + ~(csi_lane_mask); + i = 0; + while (csi_lane_mask) { + if (csi_lane_mask & 0x1) { + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } + csi_lane_mask >>= 1; + i++; + } + } + + if (--csiphy_dev->ref_count) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return 0; + } + + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_lnck_cfg2_addr); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + + disable_irq(csiphy_dev->irq->start); + + if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + iounmap(csiphy_dev->clk_mux_base); + } + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; + return 0; +} +#else +static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg) +{ + int i = 0; + struct msm_camera_csi_lane_params *csi_lane_params; + uint16_t csi_lane_mask; + csi_lane_params = (struct msm_camera_csi_lane_params *)arg; + + if (!csiphy_dev || !csiphy_dev->ref_count) { + pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__); + return 0; + } + + if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) { + pr_err("%s: csiphy invalid state %d\n", __func__, + csiphy_dev->csiphy_state); + return -EINVAL; + } + + if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) { + csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0; + for (i = 0; i < 4; i++) + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } else { + if (!csi_lane_params) { + pr_err("%s:%d failed: csi_lane_params %p\n", __func__, + __LINE__, csi_lane_params); + return -EINVAL; + } + csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F); + + CDBG("%s csiphy_params, lane assign 0x%x mask = 0x%x\n", + __func__, + csi_lane_params->csi_lane_assign, + csi_lane_params->csi_lane_mask); + + if (!csi_lane_mask) + csi_lane_mask = 0x1f; + + csiphy_dev->lane_mask[csiphy_dev->pdev->id] &= + ~(csi_lane_mask); + i = 0; + while (csi_lane_mask) { + if (csi_lane_mask & 0x1) { + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_lnn_cfg2_addr + 0x40*i); + } + csi_lane_mask >>= 1; + i++; + } + } + + if (--csiphy_dev->ref_count) { + CDBG("%s csiphy refcount = %d\n", __func__, + csiphy_dev->ref_count); + return 0; + } + + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_lnck_cfg2_addr); + msm_camera_io_w(0x0, csiphy_dev->base + + csiphy_dev->ctrl_reg->csiphy_reg.mipi_csiphy_glbl_pwr_cfg_addr); + + if (csiphy_dev->hw_dts_version <= CSIPHY_VERSION_V22) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + } else if (csiphy_dev->hw_dts_version >= CSIPHY_VERSION_V30) { + msm_cam_clk_enable(&csiphy_dev->pdev->dev, + csiphy_clk_info, csiphy_dev->csiphy_clk, + csiphy_dev->num_clk, 0); + iounmap(csiphy_dev->clk_mux_base); + } + + iounmap(csiphy_dev->base); + csiphy_dev->base = NULL; + csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; + return 0; +} + +#endif + +static int32_t msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg) +{ + int rc = 0; + struct csiphy_cfg_data *cdata = (struct csiphy_cfg_data *)arg; + struct msm_camera_csiphy_params csiphy_params; + struct msm_camera_csi_lane_params csi_lane_params; + if (!csiphy_dev || !cdata) { + pr_err("%s: csiphy_dev NULL\n", __func__); + return -EINVAL; + } + switch (cdata->cfgtype) { + case CSIPHY_INIT: + rc = msm_csiphy_init(csiphy_dev); + break; + case CSIPHY_CFG: + if (copy_from_user(&csiphy_params, + (void *)cdata->cfg.csiphy_params, + sizeof(struct msm_camera_csiphy_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_csiphy_lane_config(csiphy_dev, &csiphy_params); + break; + case CSIPHY_RELEASE: + if (copy_from_user(&csi_lane_params, + (void *)cdata->cfg.csi_lane_params, + sizeof(struct msm_camera_csi_lane_params))) { + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + rc = msm_csiphy_release(csiphy_dev, &csi_lane_params); + break; + default: + pr_err("%s: %d failed\n", __func__, __LINE__); + rc = -ENOIOCTLCMD; + break; + } + return rc; +} + +static int32_t msm_csiphy_get_subdev_id(struct csiphy_device *csiphy_dev, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EINVAL; + } + *subdev_id = csiphy_dev->pdev->id; + pr_debug("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); + return 0; +} + +static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = -ENOIOCTLCMD; + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + CDBG("%s:%d id %d\n", __func__, __LINE__, csiphy_dev->pdev->id); + mutex_lock(&csiphy_dev->mutex); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + rc = msm_csiphy_get_subdev_id(csiphy_dev, arg); + break; + case VIDIOC_MSM_CSIPHY_IO_CFG: + rc = msm_csiphy_cmd(csiphy_dev, arg); + break; + case VIDIOC_MSM_CSIPHY_RELEASE: + case MSM_SD_SHUTDOWN: + rc = msm_csiphy_release(csiphy_dev, arg); + break; + default: + pr_err_ratelimited("%s: command not found\n", __func__); + } + mutex_unlock(&csiphy_dev->mutex); + CDBG("%s:%d\n", __func__, __LINE__); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_csiphy_internal_ops; + +static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = { + .g_chip_ident = &msm_csiphy_subdev_g_chip_ident, + .ioctl = &msm_csiphy_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = { + .core = &msm_csiphy_subdev_core_ops, +}; + +static int msm_csiphy_get_clk_info(struct csiphy_device *csiphy_dev, + struct platform_device *pdev) +{ + uint32_t count; + int i, rc; + uint32_t rates[CSIPHY_NUM_CLK_MAX]; + + struct device_node *of_node; + of_node = pdev->dev.of_node; + + count = of_property_count_strings(of_node, "clock-names"); + csiphy_dev->num_clk = count; + + CDBG("%s: count = %d\n", __func__, count); + if (count == 0) { + pr_err("%s: no clocks found in device tree, count=%d", + __func__, count); + return 0; + } + + if (count > CSIPHY_NUM_CLK_MAX) { + pr_err("%s: invalid count=%d, max is %d\n", __func__, + count, CSIPHY_NUM_CLK_MAX); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(csiphy_clk_info[i].clk_name)); + CDBG("%s: clock-names[%d] = %s\n", __func__, + i, csiphy_clk_info[i].clk_name); + if (rc < 0) { + pr_err("%s:%d, failed\n", __func__, __LINE__); + return rc; + } + } + rc = of_property_read_u32_array(of_node, "qcom,clock-rates", + rates, count); + if (rc < 0) { + pr_err("%s:%d, failed", __func__, __LINE__); + return rc; + } + for (i = 0; i < count; i++) { + csiphy_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i]; + CDBG("%s: clk_rate[%d] = %ld\n", __func__, i, + csiphy_clk_info[i].clk_rate); + } + return 0; +} + +static int csiphy_probe(struct platform_device *pdev) +{ + struct csiphy_device *new_csiphy_dev; + int rc = 0; + + new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL); + if (!new_csiphy_dev) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + new_csiphy_dev->ctrl_reg = NULL; + new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t), + GFP_KERNEL); + if (!new_csiphy_dev->ctrl_reg) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + kfree(new_csiphy_dev); + return -ENOMEM; + } + v4l2_subdev_init(&new_csiphy_dev->msm_sd.sd, &msm_csiphy_subdev_ops); + v4l2_set_subdevdata(&new_csiphy_dev->msm_sd.sd, new_csiphy_dev); + platform_set_drvdata(pdev, &new_csiphy_dev->msm_sd.sd); + + mutex_init(&new_csiphy_dev->mutex); + + if (pdev->dev.of_node) { + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + CDBG("%s: device id = %d\n", __func__, pdev->id); + } + + rc = msm_csiphy_get_clk_info(new_csiphy_dev, pdev); + if (rc < 0) { + pr_err("%s: msm_csiphy_get_clk_info() failed", __func__); + rc = -EFAULT; + goto csiphy_no_resource; + } + + new_csiphy_dev->mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csiphy"); + if (!new_csiphy_dev->mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto csiphy_no_resource; + } + new_csiphy_dev->irq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "csiphy"); + if (!new_csiphy_dev->irq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto csiphy_no_resource; + } + new_csiphy_dev->io = request_mem_region(new_csiphy_dev->mem->start, + resource_size(new_csiphy_dev->mem), pdev->name); + if (!new_csiphy_dev->io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto csiphy_no_resource; + } + + rc = request_irq(new_csiphy_dev->irq->start, msm_csiphy_irq, + IRQF_TRIGGER_RISING, "csiphy", new_csiphy_dev); + if (rc < 0) { + release_mem_region(new_csiphy_dev->mem->start, + resource_size(new_csiphy_dev->mem)); + pr_err("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto csiphy_no_resource; + } + disable_irq(new_csiphy_dev->irq->start); + + new_csiphy_dev->clk_mux_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "csiphy_clk_mux"); + if (new_csiphy_dev->clk_mux_mem) { + new_csiphy_dev->clk_mux_io = request_mem_region( + new_csiphy_dev->clk_mux_mem->start, + resource_size(new_csiphy_dev->clk_mux_mem), + new_csiphy_dev->clk_mux_mem->name); + if (!new_csiphy_dev->clk_mux_io) + pr_err("%s: ERROR %d\n", __func__, __LINE__); + } + + new_csiphy_dev->pdev = pdev; + new_csiphy_dev->msm_sd.sd.internal_ops = &msm_csiphy_internal_ops; + new_csiphy_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(new_csiphy_dev->msm_sd.sd.name, + ARRAY_SIZE(new_csiphy_dev->msm_sd.sd.name), "msm_csiphy"); + media_entity_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL, 0); + new_csiphy_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + new_csiphy_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSIPHY; + new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4; + msm_sd_register(&new_csiphy_dev->msm_sd); + + if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v2.0")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V20; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v2.2")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_2; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V22; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v3.0")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_0; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V30; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v3.1")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_1; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V31; + } else if (of_device_is_compatible(new_csiphy_dev->pdev->dev.of_node, + "qcom,csiphy-v3.2")) { + new_csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v3_2; + new_csiphy_dev->hw_dts_version = CSIPHY_VERSION_V32; + } else { + pr_err("%s:%d, invalid hw version : 0x%x", __func__, __LINE__, + new_csiphy_dev->hw_dts_version); + rc = -EINVAL; + goto csiphy_no_resource; + } + + new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN; + return 0; + +csiphy_no_resource: + mutex_destroy(&new_csiphy_dev->mutex); + kfree(new_csiphy_dev->ctrl_reg); + kfree(new_csiphy_dev); + return rc; +} + +static const struct of_device_id msm_csiphy_dt_match[] = { + {.compatible = "qcom,csiphy"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_csiphy_dt_match); + +static struct platform_driver csiphy_driver = { + .probe = csiphy_probe, + .driver = { + .name = MSM_CSIPHY_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_csiphy_dt_match, + }, +}; + +static int __init msm_csiphy_init_module(void) +{ + return platform_driver_register(&csiphy_driver); +} + +static void __exit msm_csiphy_exit_module(void) +{ + platform_driver_unregister(&csiphy_driver); +} + +module_init(msm_csiphy_init_module); +module_exit(msm_csiphy_exit_module); +MODULE_DESCRIPTION("MSM CSIPHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/msm_csiphy.h new file mode 100644 index 0000000000000000000000000000000000000000..8a363df67bc768503d8fd84f4cfe20b42ca77057 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/csiphy/msm_csiphy.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CSIPHY_H +#define MSM_CSIPHY_H + +#include +#include +#include +#include +#include "../../include/media/msm_cam_sensor.h" +#include "msm_sd.h" + +#define MAX_CSIPHY 3 + +struct csiphy_reg_parms_t { +/*MIPI CSI PHY registers*/ + uint32_t mipi_csiphy_lnn_cfg1_addr; + uint32_t mipi_csiphy_lnn_cfg2_addr; + uint32_t mipi_csiphy_lnn_cfg3_addr; + uint32_t mipi_csiphy_lnn_cfg4_addr; + uint32_t mipi_csiphy_lnn_cfg5_addr; + uint32_t mipi_csiphy_lnck_cfg1_addr; + uint32_t mipi_csiphy_lnck_cfg2_addr; + uint32_t mipi_csiphy_lnck_cfg3_addr; + uint32_t mipi_csiphy_lnck_cfg4_addr; + uint32_t mipi_csiphy_lnck_cfg5_addr; + uint32_t mipi_csiphy_lnck_misc1_addr; + uint32_t mipi_csiphy_glbl_reset_addr; + uint32_t mipi_csiphy_glbl_pwr_cfg_addr; + uint32_t mipi_csiphy_glbl_irq_cmd_addr; + uint32_t mipi_csiphy_hw_version_addr; + uint32_t mipi_csiphy_interrupt_status0_addr; + uint32_t mipi_csiphy_interrupt_mask0_addr; + uint32_t mipi_csiphy_interrupt_mask_val; + uint32_t mipi_csiphy_interrupt_mask_addr; + uint32_t mipi_csiphy_interrupt_clear0_addr; + uint32_t mipi_csiphy_interrupt_clear_addr; + uint32_t mipi_csiphy_mode_config_shift; + uint32_t mipi_csiphy_glbl_t_init_cfg0_addr; + uint32_t mipi_csiphy_t_wakeup_cfg0_addr; + uint32_t csiphy_version; +}; + +struct csiphy_ctrl_t { + struct csiphy_reg_parms_t csiphy_reg; +}; + +enum msm_csiphy_state_t { + CSIPHY_POWER_UP, + CSIPHY_POWER_DOWN, +}; + +struct csiphy_device { + struct platform_device *pdev; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev subdev; + struct resource *mem; + struct resource *clk_mux_mem; + struct resource *irq; + struct resource *io; + struct resource *clk_mux_io; + void __iomem *base; + void __iomem *clk_mux_base; + struct mutex mutex; + uint32_t hw_version; + uint32_t hw_dts_version; + enum msm_csiphy_state_t csiphy_state; + struct csiphy_ctrl_t *ctrl_reg; + uint32_t num_clk; + + struct clk *csiphy_clk[8]; + + int32_t ref_count; + uint16_t lane_mask[MAX_CSIPHY]; +}; + +#define VIDIOC_MSM_CSIPHY_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *) +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d5aa00d163f42a5b676faea0003a3f0dc3fec023 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/Makefile @@ -0,0 +1,5 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/cci +obj-$(CONFIG_MSM_EEPROM) += msm_eeprom.o +obj-$(CONFIG_MSM_OTP) += msm_otp.o \ No newline at end of file diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_eeprom.c new file mode 100644 index 0000000000000000000000000000000000000000..52bd44669c83623fd785fd7fe1a529cdc2b1499e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_eeprom.c @@ -0,0 +1,1568 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include "msm_sd.h" +#include "msm_cci.h" +#include "msm_eeprom.h" + +//#define MSM_EEPROM_DEBUG +#undef CDBG +#ifdef MSM_EEPROM_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +DEFINE_MSM_MUTEX(msm_eeprom_mutex); + +/** + * msm_eeprom_parse_memory_map() - parse memory map in device node + * @of: device node + * @str: id string + * @data: memory block for output + * + * This functions parses @of to fill @data. It allocates map itself, parses + * the @of node, calculate total data length, and allocates required buffer. + * It only fills the map, but does not perform actual reading. + */ +static int msm_eeprom_parse_memory_map(struct device_node *of, const char *str, + struct msm_eeprom_memory_block_t *data) +{ + int i, rc = 0; + char property[PROPERTY_MAXSIZE]; + uint32_t count = 6; + struct msm_eeprom_memory_map_t *map; + + snprintf(property, PROPERTY_MAXSIZE, "qcom,%s-num-blocks", str); + rc = of_property_read_u32(of, property, &data->num_map); + CDBG("%s: %s %d\n", __func__, property, data->num_map); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + return rc; + } + + map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + if (!map) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return -ENOMEM; + } + data->map = map; + + for (i = 0; i < data->num_map; i++) { + snprintf(property, PROPERTY_MAXSIZE, "qcom,%s-page%d", str, i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].page, count); + if (rc < 0) { + pr_err("%s: failed %d\n", __func__, __LINE__); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "qcom,%s-poll%d", str, i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].poll, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "qcom,%s-mem%d", str, i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].mem, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + data->num_data += map[i].mem.valid_size; + } + + CDBG("%s num_bytes %d\n", __func__, data->num_data); + + data->mapdata = kzalloc(data->num_data, GFP_KERNEL); + if (!data->mapdata) { + pr_err("%s failed line %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + return rc; + +ERROR: + kfree(data->map); + memset(data, 0, sizeof(*data)); + return rc; +} + +/** + * read_eeprom_memory() - read map data into buffer + * @e_ctrl: eeprom control struct + * @block: block to be read + * + * This function iterates through blocks stored in block->map, reads each + * region and concatenate them into the pre-allocated block->mapdata + */ +static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_memory_block_t *block) +{ + int rc = 0; + int j; + struct msm_eeprom_memory_map_t *emap = block->map; + uint8_t *memptr = block->mapdata; + + pr_err("%s Enter \n", __func__); + + if (!e_ctrl) { + pr_err("%s e_ctrl is NULL", __func__); + return -EINVAL; + } + + for (j = 0; j < block->num_map; j++) { + if (emap[j].page.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].page.addr_t; + pr_err("%s %d \n", __func__, __LINE__); + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), emap[j].page.addr, + emap[j].page.data, emap[j].page.data_t); + pr_err("%s %d \n", __func__, __LINE__); + msleep(emap[j].page.delay); + pr_err("%s %d delay = %d \n", __func__, __LINE__, emap[j].page.delay); + if (rc < 0) { + pr_err("%s: page write failed\n", __func__); + return rc; + } + } + + if (emap[j].poll.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].poll.addr_t; + pr_err("%s %d \n", __func__, __LINE__); + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll( + &(e_ctrl->i2c_client), emap[j].poll.addr, + emap[j].poll.data, emap[j].poll.data_t); + pr_err("%s %d \n", __func__, __LINE__); + msleep(emap[j].poll.delay); + pr_err("%s %d delay = %d \n", __func__, __LINE__, emap[j].poll.delay); + if (rc < 0) { + pr_err("%s: poll failed\n", __func__); + return rc; + } + } + + if (emap[j].mem.valid_size) { + e_ctrl->i2c_client.addr_type = emap[j].mem.addr_t; + pr_err("%s %d \n", __func__, __LINE__); + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq( + &(e_ctrl->i2c_client), emap[j].mem.addr, + memptr, emap[j].mem.valid_size); + pr_err("%s %d \n", __func__, __LINE__); + if (rc < 0) { + pr_err("%s: read failed\n", __func__); + return rc; + } + memptr += emap[j].mem.valid_size; + } + } + + pr_err("%s Exit \n", __func__); + return rc; +} + +/** + * msm_eeprom_verify_sum - verify crc32 checksum + * @mem: data buffer + * @size: size of data buffer + * @sum: expected checksum + * + * Returns 0 if checksum match, -EINVAL otherwise. + */ +static int msm_eeprom_verify_sum(const char *mem, uint32_t size, uint32_t sum) +{ + uint32_t crc = ~0UL; + + /* check overflow */ + if (size > crc - sizeof(uint32_t)) + return -EINVAL; + + crc = crc32_le(crc, mem, size); + if (~crc != sum) { + pr_err("%s: expect 0x%x, result 0x%x\n", __func__, sum, ~crc); + pr_err("Check eeprom or interface"); + return -EINVAL; + } + CDBG("%s: checksum pass 0x%x\n", __func__, sum); + return 0; +} + +/** + * msm_eeprom_match_crc - verify multiple regions using crc + * @data: data block to be verified + * + * Iterates through all regions stored in @data. Regions with odd index + * are treated as data, and its next region is treated as checksum. Thus + * regions of even index must have valid_size of 4 or 0 (skip verification). + * Returns a bitmask of verified regions, starting from LSB. 1 indicates + * a checksum match, while 0 indicates checksum mismatch or not verified. + */ +static uint32_t msm_eeprom_match_crc(struct msm_eeprom_memory_block_t *data) +{ + int j, rc; + uint32_t *sum; + uint32_t ret = 0; + uint8_t *memptr; + struct msm_eeprom_memory_map_t *map; + + if (!data) { + pr_err("%s data is NULL", __func__); + return -EINVAL; + } + map = data->map; + memptr = data->mapdata; + + for (j = 0; j + 1 < data->num_map; j += 2) { + /* empty table or no checksum */ + if (!map[j].mem.valid_size || !map[j+1].mem.valid_size) { + memptr += map[j].mem.valid_size + + map[j+1].mem.valid_size; + continue; + } + if (map[j+1].mem.valid_size != sizeof(uint32_t)) { + pr_err("%s: malformatted data mapping\n", __func__); + return -EINVAL; + } + sum = (uint32_t *) (memptr + map[j].mem.valid_size); + rc = msm_eeprom_verify_sum(memptr, map[j].mem.valid_size, + *sum); + if (!rc) + ret |= 1 << (j/2); + memptr += map[j].mem.valid_size + map[j+1].mem.valid_size; + } + return ret; +} + +static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc; + struct msm_camera_i2c_client *client = &e_ctrl->i2c_client; + uint8_t id[2]; + rc = msm_camera_spi_query_id(client, 0, &id[0], 2); + if (rc < 0) + return rc; + + pr_info("%s: read 0x%02X%02X, check Fidelix 16M:0x%02X%02X, Winbond 8M:0x%02X%02X, Winbond 16M:0x%02X%02X\n", __func__, + id[0], id[1], client->spi_client->mfr_id0, client->spi_client->device_id0, + client->spi_client->mfr_id1, client->spi_client->device_id1, + client->spi_client->mfr_id2, client->spi_client->device_id2); + + if ((id[0] == client->spi_client->mfr_id0 && id[1] == client->spi_client->device_id0) + || (id[0] == client->spi_client->mfr_id1 && id[1] == client->spi_client->device_id1) + || (id[0] == client->spi_client->mfr_id2 && id[1] == client->spi_client->device_id2)) + return 0; + + return -ENODEV; +} + +/** + * msm_eeprom_power_up() - power up eeprom if it's not on + * @e_ctrl: control struct + * @down: output to indicate whether power down is needed later + * + * This function powers up EEPROM only if it's not already on. If power + * up is performed here, @down will be set to true. Caller should power + * down EEPROM after transaction if @down is true. + */ +static int msm_eeprom_power_up(struct msm_eeprom_ctrl_t *e_ctrl, bool *down) +{ + int rc = 0; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) + rc = msm_eeprom_match_id(e_ctrl); + pr_warn("%s : E", __func__); + + if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE || rc < 0) { + if (down) *down = true; + rc = msm_camera_power_up(&e_ctrl->eboard_info->power_info, + e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); + } else { + if (down) *down = false; + } + return rc; +} + +/** + * msm_eeprom_power_down() - power down eeprom + * @e_ctrl: control struct + * @down: indicate whether kernel powered up eeprom before + * + * This function powers down EEPROM only if it's powered on by calling + * msm_eeprom_power_up() before. If @down is false, no action will be + * taken. Otherwise, eeprom will be powered down. + */ +static int msm_eeprom_power_down(struct msm_eeprom_ctrl_t *e_ctrl, bool down) +{ + pr_warn("%s : E", __func__); + if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE || down) + return msm_camera_power_down(&e_ctrl->eboard_info->power_info, + e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); + else + return 0; +} + +static int eeprom_config_read_cal_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc; + + /* check range */ + if (cdata->cfg.read_data.num_bytes > e_ctrl->cal_data.num_data) { + pr_err("%s: Invalid size. exp %u, req %u\n", __func__, + e_ctrl->cal_data.num_data, + cdata->cfg.read_data.num_bytes); + return -EINVAL; + } + if (!e_ctrl->cal_data.mapdata) { + pr_err("%s : is NULL", __func__); + return -EFAULT; + } + CDBG("%s:%d: subdevid: %d",__func__,__LINE__,e_ctrl->subdev_id); + rc = copy_to_user(cdata->cfg.read_data.dbuffer, + e_ctrl->cal_data.mapdata, + cdata->cfg.read_data.num_bytes); + + return rc; +} + +static int eeprom_config_read_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + char *buf; + int rc = 0; + bool down; + buf = kmalloc(cdata->cfg.read_data.num_bytes, GFP_KERNEL); + if (!buf) { + pr_err("%s : buf is NULL", __func__); + return -ENOMEM; + } + rc = msm_eeprom_power_up(e_ctrl, &down); + if (rc < 0) { + pr_err("%s: failed to power on eeprom\n", __func__); + goto FREE; + } + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq( + &(e_ctrl->i2c_client), cdata->cfg.read_data.addr, + buf, cdata->cfg.read_data.num_bytes); + CDBG("%s: read data, rc addr = 0x%p %d %d\n", __func__, (void*)cdata->cfg.read_data.addr, cdata->cfg.read_data.num_bytes, rc); + if (rc < 0) { + pr_err("%s: failed to read data, rc %d\n", __func__, rc); + goto POWER_DOWN; + } + rc = copy_to_user(cdata->cfg.read_data.dbuffer, buf, + cdata->cfg.read_data.num_bytes); +POWER_DOWN: + msm_eeprom_power_down(e_ctrl, down); +FREE: + kfree(buf); + return rc; +} + +static int eeprom_config_read_compressed_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc = 0; +#if 0 // just once to power up when load lib + bool down; +#endif + + uint8_t *buf_comp = NULL; + uint8_t *buf_decomp = NULL; + uint32_t decomp_size; + + pr_err("%s: address (0x%x) comp_size (%d) after decomp (%d)", __func__, + cdata->cfg.read_data.addr, + cdata->cfg.read_data.comp_size, cdata->cfg.read_data.num_bytes); + + buf_comp = kmalloc(cdata->cfg.read_data.comp_size, GFP_KERNEL); + buf_decomp = kmalloc(cdata->cfg.read_data.num_bytes, GFP_KERNEL); + if (!buf_decomp || !buf_comp) { + pr_err("%s: kmalloc fail", __func__); + rc = -ENOMEM; + goto FREE; + } + +#if 0 // just once to power up when load lib + rc = msm_eeprom_power_up(e_ctrl, &down); + if (rc < 0) { + pr_err("%s: failed to power on eeprom\n", __func__); + goto FREE; + } +#endif + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq( + &(e_ctrl->i2c_client), cdata->cfg.read_data.addr, + buf_comp, cdata->cfg.read_data.comp_size); + + if (rc < 0) { + pr_err("%s: failed to read data, rc %d\n", __func__, rc); + goto POWER_DOWN; + } + + pr_err("%s: crc = 0x%08X\n", __func__, *(uint32_t*)&buf_comp[cdata->cfg.read_data.comp_size-4]); + // compressed data(buf_comp) contains uncompressed crc32 value. + rc = msm_eeprom_verify_sum(buf_comp, cdata->cfg.read_data.comp_size-4, + *(uint32_t*)&buf_comp[cdata->cfg.read_data.comp_size-4]); + + if (rc < 0) { + pr_err("%s: crc check error, rc %d\n", __func__, rc); + goto POWER_DOWN; + } + + decomp_size = cdata->cfg.read_data.num_bytes; + rc = lzo1x_decompress_safe(buf_comp, cdata->cfg.read_data.comp_size-4, + buf_decomp, &decomp_size); + if (rc != LZO_E_OK) { + pr_err("%s: decompression failed %d", __func__, rc); + goto POWER_DOWN; + } + rc = copy_to_user(cdata->cfg.read_data.dbuffer, buf_decomp, decomp_size); + + if (rc < 0) { + pr_err("%s: failed to copy to user\n", __func__); + goto POWER_DOWN; + } + + pr_info("%s: done", __func__); + +POWER_DOWN: +#if 0 // just once to power up when load lib + msm_eeprom_power_down(e_ctrl, down); +#endif + + FREE: + if (buf_comp) kfree(buf_comp); + if (buf_decomp) kfree(buf_decomp); + + return rc; +} + +static int eeprom_config_write_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc = 0; + + char *buf = NULL; + bool down; + void *work_mem = NULL; + uint8_t *compressed_buf = NULL; + uint32_t compressed_size = 0; + uint32_t crc = ~0UL; + + pr_warn("%s: compress ? %d size %d", __func__, + cdata->cfg.write_data.compress, cdata->cfg.write_data.num_bytes); + buf = kmalloc(cdata->cfg.write_data.num_bytes, GFP_KERNEL); + if (!buf) { + pr_err("%s: allocation failed 1", __func__); + return -ENOMEM; + } + rc = copy_from_user(buf, cdata->cfg.write_data.dbuffer, + cdata->cfg.write_data.num_bytes); + if (rc < 0) { + pr_err("%s: failed to copy write data\n", __func__); + goto FREE; + } + /* compress */ + if (cdata->cfg.write_data.compress) { + compressed_buf = kmalloc(cdata->cfg.write_data.num_bytes + + cdata->cfg.write_data.num_bytes / 16 + 64 + 3, GFP_KERNEL); + if (!compressed_buf) { + pr_err("%s: allocation failed 2", __func__); + rc = -ENOMEM; + goto FREE; + } + work_mem = kmalloc(LZO1X_1_MEM_COMPRESS, GFP_KERNEL); + if (!work_mem) { + pr_err("%s: allocation failed 3", __func__); + rc = -ENOMEM; + goto FREE; + } + if (lzo1x_1_compress(buf, cdata->cfg.write_data.num_bytes, + compressed_buf, &compressed_size, work_mem) != LZO_E_OK) { + pr_err("%s: compression failed", __func__); + goto FREE; + } + + crc = crc32_le(crc, compressed_buf, compressed_size); + crc = ~crc; + + pr_err("%s: compressed size %d, crc=0x%0X", __func__, compressed_size, crc); + *cdata->cfg.write_data.write_size = compressed_size + 4; // include CRC size + } + rc = msm_eeprom_power_up(e_ctrl, &down); + if (rc < 0) { + pr_err("%s: failed to power on eeprom\n", __func__); + goto FREE; + } + if (cdata->cfg.write_data.compress) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq( + &(e_ctrl->i2c_client), cdata->cfg.write_data.addr, + compressed_buf, compressed_size); + + // write CRC32 for compressed data + rc |= e_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq( + &(e_ctrl->i2c_client), cdata->cfg.write_data.addr+compressed_size, + (uint8_t *)&crc, 4); + } else { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq( + &(e_ctrl->i2c_client), cdata->cfg.write_data.addr, + buf, cdata->cfg.write_data.num_bytes); + } + + if (rc < 0) { + pr_err("%s: failed to write data, rc %d\n", __func__, rc); + goto POWER_DOWN; + } + CDBG("%s: done", __func__); +POWER_DOWN: + msm_eeprom_power_down(e_ctrl, down); +FREE: + if (buf) kfree(buf); + if (compressed_buf) kfree(compressed_buf); + if (work_mem) kfree(work_mem); + return rc; +} +static int eeprom_config_erase(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc; + bool down; + pr_warn("%s: erasing addr 0x%x, size %u\n", __func__, + cdata->cfg.erase_data.addr, cdata->cfg.erase_data.num_bytes); + rc = msm_eeprom_power_up(e_ctrl, &down); + if (rc < 0) { + pr_err("%s: failed to power on eeprom\n", __func__); + return rc; + } + rc = msm_camera_spi_erase(&e_ctrl->i2c_client, + cdata->cfg.erase_data.addr, cdata->cfg.erase_data.num_bytes); + if (rc < 0) + pr_err("%s: failed to erase eeprom\n", __func__); + msm_eeprom_power_down(e_ctrl, down); + return rc; +} + +static int32_t msm_eeprom_read_eeprom_data(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int32_t rc = 0; + + CDBG("%s:%d Enter\n", __func__, __LINE__); + /* check eeprom id */ + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) { + rc = msm_eeprom_match_id(e_ctrl); + if (rc < 0) { + CDBG("%s: eeprom not matching %d\n", __func__, rc); + return rc; + } + } + /* read eeprom */ + if (e_ctrl->cal_data.map) { + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s: read cal data failed\n", __func__); + return rc; + } + e_ctrl->is_supported |= msm_eeprom_match_crc( + &e_ctrl->cal_data); + } + + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + CDBG("%s:%d Exit\n", __func__, __LINE__); + return rc; +} + +static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl, + void __user *argp) +{ + struct msm_eeprom_cfg_data *cdata = + (struct msm_eeprom_cfg_data *)argp; + int rc = 0; + + CDBG("%s:%d: subdevid: %d",__func__,__LINE__,e_ctrl->subdev_id); + switch (cdata->cfgtype) { + case CFG_EEPROM_GET_INFO: + CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); + cdata->is_supported = e_ctrl->is_supported; + memcpy(cdata->cfg.eeprom_name, + e_ctrl->eboard_info->eeprom_name, + sizeof(cdata->cfg.eeprom_name)); + break; + case CFG_EEPROM_GET_CAL_DATA: + CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); + cdata->cfg.get_data.num_bytes = + e_ctrl->cal_data.num_data; + break; + case CFG_EEPROM_READ_CAL_DATA: + CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__); + rc = eeprom_config_read_cal_data(e_ctrl, cdata); + break; + case CFG_EEPROM_READ_DATA: + case CFG_EEPROM_GET_FW_VERSION_INFO: + CDBG("%s E CFG_EEPROM_READ_DATA\n", __func__); + rc = eeprom_config_read_data(e_ctrl, cdata); + break; + case CFG_EEPROM_READ_COMPRESSED_DATA: + rc = eeprom_config_read_compressed_data(e_ctrl, cdata); + if (rc < 0) + pr_err("%s : eeprom_config_read_compressed_data failed", __func__); + break; + case CFG_EEPROM_WRITE_DATA: + pr_warn("%s E CFG_EEPROM_WRITE_DATA\n", __func__); + rc = eeprom_config_write_data(e_ctrl, cdata); + break; + case CFG_EEPROM_READ_DATA_FROM_HW: + e_ctrl->is_supported = 0x01; + pr_err ("kernel is supported before%X\n",e_ctrl->is_supported); + rc = msm_eeprom_read_eeprom_data(e_ctrl); + pr_err ("kernel is supported after%X\n",e_ctrl->is_supported); + cdata->is_supported = e_ctrl->is_supported; + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + break; + } + rc = copy_to_user(cdata->cfg.read_data.dbuffer, + e_ctrl->cal_data.mapdata, + cdata->cfg.read_data.num_bytes); + break; + case CFG_EEPROM_GET_ERASESIZE: + CDBG("%s E CFG_EEPROM_GET_ERASESIZE\n", __func__); + cdata->cfg.get_data.num_bytes = + e_ctrl->i2c_client.spi_client->erase_size; + break; + case CFG_EEPROM_ERASE: + pr_warn("%s E CFG_EEPROM_ERASE\n", __func__); + rc = eeprom_config_erase(e_ctrl, cdata); + break; + case CFG_EEPROM_POWER_ON: + rc = msm_eeprom_power_up(e_ctrl, NULL); + if (rc < 0) + pr_err("%s : msm_eeprom_power_up failed", __func__); + break; + case CFG_EEPROM_POWER_OFF: + rc = msm_eeprom_power_down(e_ctrl, true); + if (rc < 0) + pr_err("%s : msm_eeprom_power_down failed", __func__); + break; + default: + break; + } + + CDBG("%s X rc: %d\n", __func__, rc); + return rc; +} + +static int msm_eeprom_get_subdev_id(struct msm_eeprom_ctrl_t *e_ctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + CDBG("%s E\n", __func__); + if (!subdev_id) { + pr_err("%s failed\n", __func__); + return -EINVAL; + } + *subdev_id = e_ctrl->subdev_id; + CDBG("subdev_id %d\n", *subdev_id); + CDBG("%s X\n", __func__); + return 0; +} + +static long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + void __user *argp = (void __user *)arg; + CDBG("%s E\n", __func__); + CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, e_ctrl, argp); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return msm_eeprom_get_subdev_id(e_ctrl, argp); + case VIDIOC_MSM_EEPROM_CFG: + return msm_eeprom_config(e_ctrl, argp); + default: + return -ENOIOCTLCMD; + } + + CDBG("%s X\n", __func__); +} + +static struct msm_camera_i2c_fn_t msm_eeprom_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_seq = msm_camera_cci_i2c_write_seq, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; + +static struct msm_camera_i2c_fn_t msm_eeprom_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, +}; + +static struct msm_camera_i2c_fn_t msm_eeprom_spi_func_tbl = { + .i2c_read = msm_camera_spi_read, + .i2c_read_seq = msm_camera_spi_read_seq, +}; + +static int msm_eeprom_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + CDBG("%s E\n", __func__); + if (!e_ctrl) { + pr_err("%s failed e_ctrl is NULL\n", __func__); + return -EINVAL; + } + CDBG("%s X\n", __func__); + return rc; +} + +static int msm_eeprom_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + CDBG("%s E\n", __func__); + if (!e_ctrl) { + pr_err("%s failed e_ctrl is NULL\n", __func__); + return -EINVAL; + } + CDBG("%s X\n", __func__); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_eeprom_internal_ops = { + .open = msm_eeprom_open, + .close = msm_eeprom_close, +}; + +static struct msm_cam_clk_info cam_8960_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_clk", 24000000}, +}; + +static struct msm_cam_clk_info cam_8974_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, + [SENSOR_CAM_CLK] = {"cam_clk", 0}, +}; + +static struct v4l2_subdev_core_ops msm_eeprom_subdev_core_ops = { + .ioctl = msm_eeprom_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_eeprom_subdev_ops = { + .core = &msm_eeprom_subdev_core_ops, +}; + +static int msm_eeprom_i2c_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +#define msm_eeprom_spi_parse_cmd(spic, str, name, out, size) \ + { \ + rc = of_property_read_u32_array( \ + spic->spi_master->dev.of_node, \ + str, out, size); \ + if (rc < 0) \ + return rc; \ + spic->cmd_tbl.name.opcode = out[0]; \ + spic->cmd_tbl.name.addr_len = out[1]; \ + spic->cmd_tbl.name.dummy_len = out[2]; \ + spic->cmd_tbl.name.delay_intv = out[3]; \ + spic->cmd_tbl.name.delay_count = out[4]; \ + } + +static int msm_eeprom_spi_parse_of(struct msm_camera_spi_client *spic) +{ + int rc = -EFAULT; + uint32_t tmp[5]; + struct device_node *of = spic->spi_master->dev.of_node; + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop-read", read, tmp, 5); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop-readseq", read_seq, tmp, 5); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop-queryid", query_id, tmp, 5); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop-pprog", + page_program, tmp, 5); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop-wenable", + write_enable, tmp, 5); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop-readst", + read_status, tmp, 5); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop-erase", erase, tmp, 5); + + rc = of_property_read_u32(of, "qcom,spi-busy-mask", tmp); + if (rc < 0) { + pr_err("%s: Failed to get busy mask\n", __func__); + return rc; + } + spic->busy_mask = tmp[0]; + rc = of_property_read_u32(of, "qcom,spi-page-size", tmp); + if (rc < 0) { + pr_err("%s: Failed to get page size\n", __func__); + return rc; + } + spic->page_size = tmp[0]; + rc = of_property_read_u32(of, "qcom,spi-erase-size", tmp); + if (rc < 0) { + pr_err("%s: Failed to get erase size\n", __func__); + return rc; + } + spic->erase_size = tmp[0]; + + rc = of_property_read_u32_array(of, "qcom,eeprom-id0", tmp, 2); + if (rc < 0) { + pr_err("%s: Failed to get eeprom id 0\n", __func__); + return rc; + } + spic->mfr_id0 = tmp[0]; + spic->device_id0 = tmp[1]; + + rc = of_property_read_u32_array(of, "qcom,eeprom-id1", tmp, 2); + if (rc < 0) { + pr_err("%s: Failed to get eeprom id 1\n", __func__); + return rc; + } + spic->mfr_id1 = tmp[0]; + spic->device_id1 = tmp[1]; + + rc = of_property_read_u32_array(of, "qcom,eeprom-id2", tmp, 2); + if (rc < 0) { + pr_err("%s: Failed to get eeprom id 2\n", __func__); + return rc; + } + spic->mfr_id2 = tmp[0]; + spic->device_id2 = tmp[1]; + + return 0; +} + +static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0, i = 0; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = + &e_ctrl->eboard_info->power_info; + struct device_node *of_node = NULL; + struct msm_camera_gpio_conf *gconf = NULL; + int16_t gpio_array_size = 0; + uint16_t *gpio_array = NULL; + + eb_info = e_ctrl->eboard_info; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) + of_node = e_ctrl->i2c_client. + spi_client->spi_master->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) + of_node = e_ctrl->pdev->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE) + of_node = e_ctrl->i2c_client.client->dev.of_node; + + rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, + &power_info->num_vreg); + if (rc < 0) { + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + return rc; + } + + rc = msm_camera_get_dt_power_setting_data(of_node, + power_info->cam_vreg, power_info->num_vreg, + power_info); + if (rc < 0) { + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + goto ERROR1; + } + + power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!power_info->gpio_conf) { + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + rc = -ENOMEM; + goto ERROR2; + } + gconf = power_info->gpio_conf; + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size > 0) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR3; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(gpio_array); + } + + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + return rc; +ERROR4: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(gpio_array); +ERROR3: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(power_info->gpio_conf); +ERROR2: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(power_info->cam_vreg); +ERROR1: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(power_info->power_setting); + return rc; +} + +static int msm_eeprom_spi_setup(struct spi_device *spi) +{ + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_camera_i2c_client *client = NULL; + struct msm_camera_spi_client *spi_client; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = NULL; + int rc = 0; + uint32_t temp = 0; + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + client = &e_ctrl->i2c_client; + e_ctrl->is_supported = 0; + + spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL); + if (!spi_client) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + kfree(e_ctrl); + return -ENOMEM; + } + + rc = of_property_read_u32(spi->dev.of_node, "cell-index", + &e_ctrl->subdev_id); + CDBG("cell-index/subdev_id %d, rc %d\n", e_ctrl->subdev_id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto spi_free; + } + + e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE; + client->spi_client = spi_client; + spi_client->spi_master = spi; + client->i2c_func_tbl = &msm_eeprom_spi_func_tbl; + client->addr_type = MSM_CAMERA_I2C_3B_ADDR; + + eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL); + if (!eb_info) { + pr_err("%s : eb_info is NULL", __func__); + goto spi_free; + } + e_ctrl->eboard_info = eb_info; + rc = of_property_read_string(spi->dev.of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto board_free; + } + power_info = &eb_info->power_info; + + power_info->clk_info = cam_8974_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); + power_info->dev = &spi->dev; + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc < 0) { + pr_err("%s : msm_eeprom_get_dt_data", __func__); + goto board_free; + } + + /* set spi instruction info */ + spi_client->retry_delay = 1; + spi_client->retries = 0; + + rc = msm_eeprom_spi_parse_of(spi_client); + if (rc < 0) { + dev_err(&spi->dev, + "%s: Error parsing device properties\n", __func__); + goto board_free; + } + + /* prepare memory buffer */ + rc = msm_eeprom_parse_memory_map(spi->dev.of_node, "cal", + &e_ctrl->cal_data); + if (rc < 0) + CDBG("%s: no cal memory map\n", __func__); + + /* power up eeprom for reading */ + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto caldata_free; + } + + /* check eeprom id */ + rc = msm_eeprom_match_id(e_ctrl); + if (rc < 0) { + CDBG("%s: eeprom not matching %d\n", __func__, rc); + goto power_down; + } + /* read eeprom */ + if (e_ctrl->cal_data.map) { + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s: read cal data failed\n", __func__); + goto power_down; + } + e_ctrl->is_supported |= msm_eeprom_match_crc( + &e_ctrl->cal_data); + } + + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto caldata_free; + } + + if (0 > of_property_read_u32(spi->dev.of_node, "qcom,sensor-position", &temp)) { + pr_err("%s:%d Fail position, Default sensor position\n", __func__, __LINE__); + temp = 0; + } + + /* initiazlie subdev */ + v4l2_spi_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->i2c_client.spi_client->spi_master, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.flags = temp; + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + CDBG("%s success result=%d supported=%x X\n", __func__, rc, + e_ctrl->is_supported); + + return 0; + +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +caldata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); +spi_free: + kfree(spi_client); + kfree(e_ctrl); + return rc; +} + +static int msm_eeprom_spi_probe(struct spi_device *spi) +{ + int irq, cs, cpha, cpol, cs_high; + + CDBG("%s\n", __func__); + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + spi_setup(spi); + + irq = spi->irq; + cs = spi->chip_select; + cpha = (spi->mode & SPI_CPHA) ? 1 : 0; + cpol = (spi->mode & SPI_CPOL) ? 1 : 0; + cs_high = (spi->mode & SPI_CS_HIGH) ? 1 : 0; + CDBG("%s: irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n", + __func__, irq, cs, cpha, cpol, cs_high); + CDBG("%s: max_speed[%u]\n", __func__, spi->max_speed_hz); + + return msm_eeprom_spi_setup(spi); +} + +static int msm_eeprom_spi_remove(struct spi_device *sdev) +{ + struct v4l2_subdev *sd = spi_get_drvdata(sdev); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->i2c_client.spi_client); + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} +static int msm_eeprom_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + uint32_t temp = 0; + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + struct device_node *of_node = client->dev.of_node; + pr_err("%s E\n", __func__); + + if (!of_node) { + pr_err("%s of_node NULL\n", __func__); + rc = -EINVAL; + goto probe_failure; + } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s i2c_check_functionality failed\n", __func__); + rc = -EINVAL; + goto probe_failure; + } + e_ctrl = kzalloc(sizeof(struct msm_eeprom_ctrl_t), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + rc = -ENOMEM; + goto probe_failure; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + CDBG("%s client = %x\n", __func__, (unsigned int)client); + e_ctrl->eboard_info = kzalloc(sizeof( + struct msm_eeprom_board_info), GFP_KERNEL); + if (!e_ctrl->eboard_info) { + pr_err("%s:%d board info NULL\n", __func__, __LINE__); + rc = -ENOMEM; + goto board_free; + } + rc = of_property_read_u32(of_node, "qcom,slave-addr", &temp); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + goto memdata_free; + } + rc = of_property_read_u32(of_node, "cell-index", &e_ctrl->subdev_id); + pr_err("cell-index/subdev_id %d, rc %d\n", e_ctrl->subdev_id, rc); + if (rc < 0) { + pr_err("failed read, rc %d\n", rc); + goto memdata_free; + } + + power_info = &e_ctrl->eboard_info->power_info; + e_ctrl->eboard_info->i2c_slaveaddr = temp; + e_ctrl->i2c_client.client = client; + e_ctrl->is_supported = 0; + e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; + e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl; + if (e_ctrl->eboard_info->i2c_slaveaddr != 0) + e_ctrl->i2c_client.client->addr = + e_ctrl->eboard_info->i2c_slaveaddr; + power_info->clk_info = cam_8960_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info); + power_info->dev = &client->dev; + rc = of_property_read_string(of_node, "qcom,eeprom-name", + &e_ctrl->eboard_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + e_ctrl->eboard_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto memdata_free; + } + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc) + goto memdata_free; + rc = msm_eeprom_parse_memory_map(of_node, "cal", + &e_ctrl->cal_data); + if (rc < 0) + pr_warn("%s: no cal memory map\n", __func__); + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("%s failed power up %d\n", __func__, __LINE__); + goto memdata_free; + } + if (e_ctrl->cal_data.map) { + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s: read cal data failed\n", __func__); + goto power_down; + } + e_ctrl->is_supported |= msm_eeprom_match_crc( + &e_ctrl->cal_data); + } + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto power_down; + } + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", &temp)) { + pr_err("%s:%d Fail position, Default sensor position\n", __func__, __LINE__); + temp = 0; + } + pr_err("%s qcom,sensor-position %d\n", __func__,temp); + + v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->i2c_client.client, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(e_ctrl->msm_sd.sd.name, + ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom"); + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.flags = temp; + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + e_ctrl->is_supported = 1; + pr_err("%s success result=%d X\n", __func__, rc); + return rc; +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +memdata_free: + if (e_ctrl->eboard_info) + kfree(e_ctrl->eboard_info); +board_free: + if (e_ctrl) + kfree(e_ctrl); +probe_failure: + pr_err("%s failed! rc = %d\n", __func__, rc); + return rc; +} +static int msm_eeprom_platform_probe(struct platform_device *pdev) +{ + int rc = 0; + int j = 0; + uint32_t temp; + + struct msm_camera_cci_client *cci_client = NULL; + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_eeprom_board_info *eb_info = NULL; + struct device_node *of_node = pdev->dev.of_node; + struct msm_camera_power_ctrl_t *power_info = NULL; + + CDBG("%s E\n", __func__); + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + + e_ctrl->is_supported = 0; + if (!of_node) { + pr_err("%s dev.of_node NULL\n", __func__); + kfree(e_ctrl); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, "cell-index", + &pdev->id); + CDBG("cell-index %d, rc %d\n", pdev->id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + kfree(e_ctrl); + return rc; + } + e_ctrl->subdev_id = pdev->id; + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &e_ctrl->cci_master); + CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + kfree(e_ctrl); + return rc; + } + rc = of_property_read_u32(of_node, "qcom,slave-addr", + &temp); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + kfree(e_ctrl); + return rc; + } + + /* Set platform device handle */ + e_ctrl->pdev = pdev; + /* Set device type as platform device */ + e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE; + e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_cci_func_tbl; + e_ctrl->i2c_client.cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!e_ctrl->i2c_client.cci_client) { + pr_err("%s failed no memory\n", __func__); + rc = -ENOMEM; + kfree(e_ctrl); + return rc; + } + + e_ctrl->eboard_info = kzalloc(sizeof( + struct msm_eeprom_board_info), GFP_KERNEL); + if (!e_ctrl->eboard_info) { + pr_err("%s failed line %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto cciclient_free; + } + eb_info = e_ctrl->eboard_info; + power_info = &eb_info->power_info; + eb_info->i2c_slaveaddr = temp; + + power_info->clk_info = cam_8974_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); + power_info->dev = &pdev->dev; + + CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr); + cci_client = e_ctrl->i2c_client.cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = e_ctrl->cci_master; + cci_client->sid = eb_info->i2c_slaveaddr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + + rc = of_property_read_string(of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto board_free; + } + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc) + goto board_free; + + rc = msm_eeprom_parse_memory_map(of_node, "cal", &e_ctrl->cal_data); + if (rc < 0) + goto board_free; + + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s read_eeprom_memory failed\n", __func__); + goto power_down; + } + for (j = 0; j < e_ctrl->cal_data.num_data; j++) + CDBG("memory_data[%d] = 0x%X\n", j, + e_ctrl->cal_data.mapdata[j]); + + e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); + + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", &temp)) { + pr_err("%s:%d Fail position, Default sensor position\n", __func__, __LINE__); + temp = 0; + } + + v4l2_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + platform_set_drvdata(pdev, &e_ctrl->msm_sd.sd); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(e_ctrl->msm_sd.sd.name, + ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom"); + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.flags = temp; + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + CDBG("%s X\n", __func__); + return rc; + +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +memdata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); +cciclient_free: + kfree(e_ctrl->i2c_client.cci_client); + kfree(e_ctrl); + return rc; +} + +static int msm_eeprom_platform_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->i2c_client.cci_client); + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +static const struct of_device_id msm_eeprom_dt_match[] = { + { .compatible = "qcom,eeprom" }, + { } +}; + +MODULE_DEVICE_TABLE(of, msm_eeprom_dt_match); + +static struct platform_driver msm_eeprom_platform_driver = { + .driver = { + .name = "qcom,eeprom", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_dt_match, + }, + .remove = msm_eeprom_platform_remove, +}; + +static const struct i2c_device_id msm_eeprom_i2c_id[] = { + { "qcom,eeprom", (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver msm_eeprom_i2c_driver = { + .id_table = msm_eeprom_i2c_id, + .probe = msm_eeprom_i2c_probe, + .remove = msm_eeprom_i2c_remove, + .driver = { + .name = "qcom,eeprom", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_dt_match, + }, +}; + +static struct spi_driver msm_eeprom_spi_driver = { + .driver = { + .name = "qcom_eeprom", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_dt_match, + }, + .probe = msm_eeprom_spi_probe, + .remove = msm_eeprom_spi_remove, +}; + +static int __init msm_eeprom_init_module(void) +{ + int rc = 0; + pr_err("%s E\n", __func__); + rc = platform_driver_probe(&msm_eeprom_platform_driver, + msm_eeprom_platform_probe); + CDBG("%s:%d platform rc %d\n", __func__, __LINE__, rc); +// rc = spi_register_driver(&msm_eeprom_spi_driver); +// CDBG("%s:%d spi rc %d\n", __func__, __LINE__, rc); + rc = i2c_add_driver(&msm_eeprom_i2c_driver); + if (rc < 0 /*&& spi_rc < 0*/) + pr_err("%s:%d probe failed\n", __func__, __LINE__); + + return rc; +} + +static void __exit msm_eeprom_exit_module(void) +{ + platform_driver_unregister(&msm_eeprom_platform_driver); + spi_unregister_driver(&msm_eeprom_spi_driver); + i2c_del_driver(&msm_eeprom_i2c_driver); +} + +module_init(msm_eeprom_init_module); +module_exit(msm_eeprom_exit_module); +MODULE_DESCRIPTION("MSM EEPROM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_eeprom.h b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_eeprom.h new file mode 100644 index 0000000000000000000000000000000000000000..d1a371d357504e167bff27b595da99d2e27ed6f8 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_eeprom.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ +#ifndef MSM_EEPROM_H +#define MSM_EEPROM_H + +#include +#include +#include "../../include/soc/qcom/camera2.h" +#include +#include "../../include/media/msmb_camera.h" +#include "msm_camera_i2c.h" +#include "msm_camera_spi.h" +#include "msm_camera_io_util.h" +#include "msm_camera_dt_util.h" + +struct msm_eeprom_ctrl_t; + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define PROPERTY_MAXSIZE 32 +#define EEPROM_FW_VERSION_OFFSET 48 + +struct msm_eeprom_ctrl_t { + struct platform_device *pdev; + struct mutex *eeprom_mutex; + + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops; + enum msm_camera_device_type_t eeprom_device_type; + struct msm_sd_subdev msm_sd; + enum cci_i2c_master_t cci_master; + + struct msm_camera_i2c_client i2c_client; + struct msm_eeprom_memory_block_t cal_data; + uint8_t is_supported; + struct msm_eeprom_board_info *eboard_info; + uint32_t subdev_id; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp.c b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp.c new file mode 100755 index 0000000000000000000000000000000000000000..84518801b5de36fe8251f5115f8ef0dbcb00d334 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp.c @@ -0,0 +1,2099 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include +#include +#include "msm_sd.h" +#include "msm_cci.h" +#if defined(CONFIG_SR544) +#include "msm_otp_sr544.h" +#else +#include "msm_otp_s5k5e3yx.h" +#endif +#include "../../include/media/msm_cam_sensor.h" + +//#define MSM_EEPROM_DEBUG 1 + +#undef CDBG +#ifdef MSM_EEPROM_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#undef EEPROM_MMAP_DEBUG + +uint8_t *map_data = NULL; + +DEFINE_MSM_MUTEX(msm_eeprom_mutex); + +static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl); +static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_memory_block_t *block); + + +static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl); +/** + * msm_eeprom_verify_sum - verify crc32 checksum + * @mem: data buffer + * @size: size of data buffer + * @sum: expected checksum + * + * Returns 0 if checksum match, -EINVAL otherwise. + */ +static int msm_eeprom_verify_sum(const char *mem, uint32_t size, uint32_t sum) +{ + uint32_t crc = ~0UL; + + /* check overflow */ + if (size > crc - sizeof(uint32_t)) + return -EINVAL; + + crc = crc32_le(crc, mem, size); + if (~crc != sum) { + pr_err("%s: expect 0x%x, result 0x%x\n", __func__, sum, ~crc); + pr_err("Check eeprom or interface"); + return -EINVAL; + } + pr_err("%s: checksum pass 0x%x\n", __func__, sum); + return 0; +} + +/** + * msm_eeprom_match_crc - verify multiple regions using crc + * @data: data block to be verified + * + * Iterates through all regions stored in @data. Regions with odd index + * are treated as data, and its next region is treated as checksum. Thus + * regions of even index must have valid_size of 4 or 0 (skip verification). + * Returns a bitmask of verified regions, starting from LSB. 1 indicates + * a checksum match, while 0 indicates checksum mismatch or not verified. + */ +static uint32_t msm_eeprom_match_crc(struct msm_eeprom_memory_block_t *data) +{ + int j, rc; + uint32_t *sum; + uint32_t ret = 0; + uint8_t *memptr, *memptr_crc; + struct msm_eeprom_memory_map_t *map; + + if (!data) { + pr_err("%s data is NULL", __func__); + return -EINVAL; + } + map = data->map; + + for (j = 0; j + 1 < data->num_map; j += 2) { + memptr = data->mapdata + map[j].mem.addr; + memptr_crc = data->mapdata + map[j+1].mem.addr; + + /* empty table or no checksum */ + if (!map[j].mem.valid_size || !map[j+1].mem.valid_size) { + continue; + } + if (map[j+1].mem.valid_size != sizeof(uint32_t)) { + pr_err("%s: malformatted data mapping\n", __func__); + return -EINVAL; + } + sum = (uint32_t *) (memptr_crc); + rc = msm_eeprom_verify_sum(memptr, map[j].mem.valid_size, *sum); + if (!rc) + { + ret |= 1 << (j/2); + } + } + return ret; +} + +static int msm_eeprom_get_cmm_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc = 0; + struct msm_eeprom_cmm_t *cmm_data = &e_ctrl->eboard_info->cmm_data; + cdata->cfg.get_cmm_data.cmm_support = cmm_data->cmm_support; + cdata->cfg.get_cmm_data.cmm_compression = cmm_data->cmm_compression; + cdata->cfg.get_cmm_data.cmm_size = cmm_data->cmm_size; + return rc; +} + +/** + * msm_eeprom_power_up() - power up eeprom if it's not on + * @e_ctrl: control struct + * @down: output to indicate whether power down is needed later + * + * This function powers up EEPROM only if it's not already on. If power + * up is performed here, @down will be set to true. Caller should power + * down EEPROM after transaction if @down is true. + */ +static int msm_eeprom_power_up(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0; + pr_warn("%s : E", __func__); + + rc = msm_camera_power_up(&e_ctrl->eboard_info->power_info, + e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); + + return rc; +} +/** + * msm_eeprom_power_down() - power down eeprom + * @e_ctrl: control struct + * @down: indicate whether kernel powered up eeprom before + * + * This function powers down EEPROM only if it's powered on by calling + * msm_eeprom_power_up() before. If @down is false, no action will be + * taken. Otherwise, eeprom will be powered down. + */ +static int msm_eeprom_power_down(struct msm_eeprom_ctrl_t *e_ctrl) +{ + pr_warn("%s : E", __func__); + return msm_camera_power_down(&e_ctrl->eboard_info->power_info, + e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); +} + +#if defined(CONFIG_SR544) +static int prepare_read_write_data(struct msm_eeprom_ctrl_t *e_ctrl, uint8_t addr_h, uint8_t addr_l, enum msm_camera_i2c_data_type data_type, int isWrite) +{ + int rc=0; + + isWrite = !(!isWrite)+1; + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_otp); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_addr_h, + addr_h, data_type); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_addr_l, + addr_l, data_type); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_cmd, + isWrite, data_type); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + return rc; +} +#endif + +static int eeprom_config_read_cal_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc; + + /* check range */ + if (cdata->cfg.read_data.num_bytes > e_ctrl->cal_data.num_data) { + pr_err("%s: Invalid size. exp %u, req %u\n", __func__, + e_ctrl->cal_data.num_data, + cdata->cfg.read_data.num_bytes); + return -EINVAL; + } + if (!e_ctrl->cal_data.mapdata) { + pr_err("%s : is NULL", __func__); + return -EFAULT; + } + CDBG("%s:%d: subdevid: %d",__func__,__LINE__,e_ctrl->subdev_id); + rc = copy_to_user(cdata->cfg.read_data.dbuffer, + e_ctrl->cal_data.mapdata, + cdata->cfg.read_data.num_bytes); + /* this below code is giving probelm in device -> encrypt -> came launch + Ideally we should not free this data until dtor. so commentiong out */ + + return rc; +} + +static int eeprom_config_read_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + char *buf; + int rc = 0; + uint16_t data; + int i; +#if defined(CONFIG_SR544) + uint8_t addr_h, addr_l; +#endif + +#if defined(CONFIG_SR544) + return rc; +#endif + + buf = kmalloc(cdata->cfg.read_data.num_bytes+1, GFP_KERNEL); + if (!buf) { + pr_err("%s : buf is NULL", __func__); + return -ENOMEM; + } + + rc = msm_eeprom_power_up(e_ctrl); + if (rc < 0) { + pr_err("%s: failed to power on otp\n", __func__); + goto FREE; + } + +#if defined(CONFIG_SR544) + addr_h = ((cdata->cfg.read_data.addr)>>8)&0xFF; + addr_l = cdata->cfg.read_data.addr&0xFF; + + rc = prepare_read_write_data(e_ctrl, addr_h, addr_l, MSM_CAMERA_I2C_BYTE_DATA, 0); + if (rc < 0) { + pr_err("%s: failed to prepare read/write on otp\n", __func__); + goto POWER_DOWN; + } +#else + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_read_otp); + if (rc < 0) { + pr_err("%s:(%d) init_read_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } +#endif + + for(i=0; icfg.read_data.num_bytes; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(e_ctrl->i2c_client), +#if defined(CONFIG_SR544) + r_otp_rdata, +#else + cdata->cfg.read_data.addr+i, +#endif + &data, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) read failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + buf[i]=data; + } + +#if !defined(CONFIG_SR544) + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &finish_read_otp); + if (rc < 0) { + pr_err("%s:(%d) finish_read_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } +#endif + buf[cdata->cfg.read_data.num_bytes] = '\0'; + pr_err("[sjlee] %s : buf[%s]\n", __func__, buf); + + rc = copy_to_user(cdata->cfg.read_data.dbuffer, buf, + cdata->cfg.read_data.num_bytes); +POWER_DOWN: + msm_eeprom_power_down(e_ctrl); +FREE: + kfree(buf); + return rc; +} + +static int eeprom_config_read_fw_version(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + char *buf; + int rc = 0; + + buf = kmalloc(cdata->cfg.read_data.num_bytes, GFP_KERNEL); + if (!buf) { + pr_err("%s : buf is NULL", __func__); + return -ENOMEM; + } + memset(buf, 0, cdata->cfg.read_data.num_bytes); + if(e_ctrl->cal_data.num_data < (cdata->cfg.read_data.addr + cdata->cfg.read_data.num_bytes)) { + pr_err("%s : requested data size was mismatched! addr:size[0x%x:%d]\n", __func__, cdata->cfg.read_data.addr, cdata->cfg.read_data.num_bytes); + rc = -ENOMEM; + goto FREE; + } + + memcpy(buf, &map_data[cdata->cfg.read_data.addr], cdata->cfg.read_data.num_bytes); + + rc = copy_to_user(cdata->cfg.read_data.dbuffer, buf, + cdata->cfg.read_data.num_bytes); + +FREE: + + kfree(buf); + return rc; +} + +static int eeprom_config_read_compressed_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc = 0; + uint8_t *buf_comp = NULL; + uint8_t *buf_decomp = NULL; + uint32_t decomp_size; + uint16_t data; + int i; +#if defined(CONFIG_SR544) + uint8_t addr_h, addr_l; +#endif + + pr_err("%s: address (0x%x) comp_size (%d) after decomp (%d)", __func__, + cdata->cfg.read_data.addr, + cdata->cfg.read_data.comp_size, cdata->cfg.read_data.num_bytes); + + buf_comp = kmalloc(cdata->cfg.read_data.comp_size, GFP_KERNEL); + buf_decomp = kmalloc(cdata->cfg.read_data.num_bytes, GFP_KERNEL); + if (!buf_decomp || !buf_comp) { + pr_err("%s: kmalloc fail", __func__); + rc = -ENOMEM; + goto FREE; + } + +#if defined(CONFIG_SR544) + addr_h = ((cdata->cfg.read_data.addr)>>8)&0xFF; + addr_l = cdata->cfg.read_data.addr&0xFF; + + rc = prepare_read_write_data(e_ctrl, addr_h, addr_l, MSM_CAMERA_I2C_BYTE_DATA, 0); + if (rc < 0) { + pr_err("%s: failed to prepare read/write on otp\n", __func__); + goto POWER_DOWN; + } +#else + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_read_otp); + if (rc < 0) { + pr_err("%s:(%d) init_read_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } +#endif + + for(i=0; icfg.read_data.comp_size; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(e_ctrl->i2c_client), +#if defined(CONFIG_SR544) + r_otp_rdata, +#else + cdata->cfg.read_data.addr+i, +#endif + &data, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) read failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + buf_comp[i]=data; + } + +#if !defined(CONFIG_SR544) + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &finish_read_otp); + if (rc < 0) { + pr_err("%s:(%d) finish_read_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } +#endif + + pr_err("%s: crc = 0x%08X\n", __func__, *(uint32_t*)&buf_comp[cdata->cfg.read_data.comp_size-4]); + // compressed data(buf_comp) contains uncompressed crc32 value. + rc = msm_eeprom_verify_sum(buf_comp, cdata->cfg.read_data.comp_size-4, + *(uint32_t*)&buf_comp[cdata->cfg.read_data.comp_size-4]); + + if (rc < 0) { + pr_err("%s: crc check error, rc %d\n", __func__, rc); + goto POWER_DOWN; + } + + decomp_size = cdata->cfg.read_data.num_bytes; + rc = lzo1x_decompress_safe(buf_comp, cdata->cfg.read_data.comp_size-4, + buf_decomp, &decomp_size); + if (rc != LZO_E_OK) { + pr_err("%s: decompression failed %d", __func__, rc); + goto POWER_DOWN; + } + rc = copy_to_user(cdata->cfg.read_data.dbuffer, buf_decomp, decomp_size); + + if (rc < 0) { + pr_err("%s: failed to copy to user\n", __func__); + goto POWER_DOWN; + } + + pr_info("%s: done", __func__); + +POWER_DOWN: +#if 0 // just once to power up when load lib + msm_eeprom_power_down(e_ctrl); +#endif + + FREE: + if (buf_comp) kfree(buf_comp); + if (buf_decomp) kfree(buf_decomp); + + return rc; +} + +static int eeprom_config_write_data(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + int rc = 0; + + char *buf = NULL; + void *work_mem = NULL; + uint8_t *compressed_buf = NULL; + uint32_t compressed_size = 0; + uint32_t crc = ~0UL; + int i; +#if defined(CONFIG_SR544) + uint8_t addr_h, addr_l; +#endif + + pr_warn("%s: compress ? %d size %d", __func__, + cdata->cfg.write_data.compress, cdata->cfg.write_data.num_bytes); + buf = kmalloc(cdata->cfg.write_data.num_bytes, GFP_KERNEL); + if (!buf) { + pr_err("%s: allocation failed 1", __func__); + return -ENOMEM; + } + rc = copy_from_user(buf, cdata->cfg.write_data.dbuffer, + cdata->cfg.write_data.num_bytes); + if (rc < 0) { + pr_err("%s: failed to copy write data\n", __func__); + goto FREE; + } + /* compress */ + if (cdata->cfg.write_data.compress) { + compressed_buf = kmalloc(cdata->cfg.write_data.num_bytes + + cdata->cfg.write_data.num_bytes / 16 + 64 + 3, GFP_KERNEL); + if (!compressed_buf) { + pr_err("%s: allocation failed 2", __func__); + rc = -ENOMEM; + goto FREE; + } + work_mem = kmalloc(LZO1X_1_MEM_COMPRESS, GFP_KERNEL); + if (!work_mem) { + pr_err("%s: allocation failed 3", __func__); + rc = -ENOMEM; + goto FREE; + } + if (lzo1x_1_compress(buf, cdata->cfg.write_data.num_bytes, + compressed_buf, &compressed_size, work_mem) != LZO_E_OK) { + pr_err("%s: compression failed", __func__); + goto FREE; + } + + crc = crc32_le(crc, compressed_buf, compressed_size); + crc = ~crc; + + pr_err("%s: compressed size %d, crc=0x%0X", __func__, compressed_size, crc); + *cdata->cfg.write_data.write_size = compressed_size + 4; // include CRC size + } + rc = msm_eeprom_power_up(e_ctrl); + if (rc < 0) { + pr_err("%s: failed to power on eeprom\n", __func__); + goto FREE; + } + +#if defined(CONFIG_SR544) + if (cdata->cfg.write_data.compress) { + + addr_h = ((cdata->cfg.write_data.addr)>>8)&0xFF; + addr_l = cdata->cfg.write_data.addr&0xFF; + + rc = prepare_read_write_data(e_ctrl, addr_h, addr_l, MSM_CAMERA_I2C_BYTE_DATA, 1); + if (rc < 0) { + pr_err("%s: failed to prepare read/write on otp\n", __func__); + goto POWER_DOWN; + } + + for(i=0; ii2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_wdata, + compressed_buf[i], MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } + + addr_h = ((cdata->cfg.write_data.addr+compressed_size)>>8)&0xFF; + addr_l = (cdata->cfg.write_data.addr+compressed_size)&0xFF; + + rc = prepare_read_write_data(e_ctrl, addr_h, addr_l, MSM_CAMERA_I2C_BYTE_DATA, 1); + if (rc < 0) { + pr_err("%s: failed to prepare read/write on otp\n", __func__); + goto POWER_DOWN; + } + + // write CRC32 for compressed data + for(i=0; i<4; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_wdata, + ((uint8_t *)crc)[i], MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } + } else { + addr_h = ((cdata->cfg.write_data.addr)>>8)&0xFF; + addr_l = cdata->cfg.write_data.addr&0xFF; + + rc = prepare_read_write_data(e_ctrl, addr_h, addr_l, MSM_CAMERA_I2C_BYTE_DATA, 1); + if (rc < 0) { + pr_err("%s: failed to prepare read/write on otp\n", __func__); + goto POWER_DOWN; + } + + for(i=0; icfg.write_data.num_bytes; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_wdata, + buf[i], MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } + } +#else + if (cdata->cfg.write_data.compress) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_write_otp); + if (rc < 0) { + pr_err("%s:(%d) init_write_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + + for(i=0; ii2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), cdata->cfg.write_data.addr+i, + compressed_buf[i], MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_write_otp); + if (rc < 0) { + pr_err("%s:(%d) init_write_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + + // write CRC32 for compressed data + for(i=0; i<4; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), cdata->cfg.write_data.addr+compressed_size+i, + ((uint8_t *)crc)[i], MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &finish_write_otp); + if (rc < 0) { + pr_err("%s:(%d) finish_write_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } else { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_write_otp); + if (rc < 0) { + pr_err("%s:(%d) init_write_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + + for(i=0; icfg.write_data.num_bytes; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), cdata->cfg.write_data.addr+i, + buf[i], MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &finish_write_otp); + if (rc < 0) { + pr_err("%s:(%d) finish_write_otp failed\n", __func__, __LINE__); + goto POWER_DOWN; + } + } +#endif + + if (rc < 0) { + pr_err("%s: failed to write data, rc %d\n", __func__, rc); + goto POWER_DOWN; + } + CDBG("%s: done", __func__); +POWER_DOWN: + msm_eeprom_power_down(e_ctrl); +FREE: + if (buf) kfree(buf); + if (compressed_buf) kfree(compressed_buf); + if (work_mem) kfree(work_mem); + return rc; +} +static int eeprom_config_erase(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_cfg_data *cdata) +{ + + int rc = 0; +#if 0 + pr_warn("%s: erasing addr 0x%x, size %u\n", __func__, + cdata->cfg.erase_data.addr, cdata->cfg.erase_data.num_bytes); + rc = msm_eeprom_power_up(e_ctrl); + if (rc < 0) { + pr_err("%s: failed to power on eeprom\n", __func__); + return rc; + } + rc = msm_camera_spi_erase(&e_ctrl->i2c_client, + cdata->cfg.erase_data.addr, cdata->cfg.erase_data.num_bytes); + if (rc < 0) + pr_err("%s: failed to erase eeprom\n", __func__); + msm_eeprom_power_down(e_ctrl); +#endif + return rc; +} + +static int32_t msm_eeprom_read_eeprom_data(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int32_t rc = 0; + + /* power up */ + rc = msm_camera_power_up(&e_ctrl->eboard_info->power_info, + e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + return rc; + } + + /* read cal data */ + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s read_eeprom_memory failed\n", __func__); + goto POWER_DOWN; + } + + /* update support info */ + e_ctrl->is_supported = (msm_eeprom_match_crc(&e_ctrl->cal_data) << 1) | 1; + pr_err("%s:%d is_supported = 0x%X\n", __func__, __LINE__, e_ctrl->is_supported); + +POWER_DOWN: + /* power down */ + if (msm_camera_power_down(&e_ctrl->eboard_info->power_info, + e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client) < 0) + pr_err("%s:%d pwoer down failed\n", __func__, __LINE__); + pr_err("%s:%d Exit\n", __func__, __LINE__); + + return rc; +} + +static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl, + void __user *argp) +{ + struct msm_eeprom_cfg_data *cdata = + (struct msm_eeprom_cfg_data *)argp; + int rc = 0; + + CDBG("%s:%d: subdevid: %d, cfgtype: %d\n",__func__,__LINE__,e_ctrl->subdev_id, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_EEPROM_GET_INFO: + CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__); + cdata->is_supported = e_ctrl->is_supported; + memcpy(cdata->cfg.eeprom_name, + e_ctrl->eboard_info->eeprom_name, + sizeof(cdata->cfg.eeprom_name)); + break; + case CFG_EEPROM_GET_CAL_DATA: + CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__); + cdata->cfg.get_data.num_bytes = + e_ctrl->cal_data.num_data; + break; + case CFG_EEPROM_READ_CAL_DATA: + CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__); + rc = eeprom_config_read_cal_data(e_ctrl, cdata); + break; + case CFG_EEPROM_READ_DATA: + CDBG("%s E CFG_EEPROM_READ_DATA\n", __func__); + rc = eeprom_config_read_data(e_ctrl, cdata); + break; + case CFG_EEPROM_READ_COMPRESSED_DATA: + rc = eeprom_config_read_compressed_data(e_ctrl, cdata); + if (rc < 0) + pr_err("%s : eeprom_config_read_compressed_data failed", __func__); + break; + case CFG_EEPROM_WRITE_DATA: + pr_warn("%s E CFG_EEPROM_WRITE_DATA\n", __func__); + rc = eeprom_config_write_data(e_ctrl, cdata); + break; + case CFG_EEPROM_READ_DATA_FROM_HW: + e_ctrl->is_supported = 0x01; + pr_err ("kernel is supported before : %X\n",e_ctrl->is_supported); + rc = msm_eeprom_read_eeprom_data(e_ctrl); + pr_err ("kernel is supported after : %X\n",e_ctrl->is_supported); + cdata->is_supported = e_ctrl->is_supported; + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + break; + } + rc = copy_to_user(cdata->cfg.read_data.dbuffer, + e_ctrl->cal_data.mapdata, + cdata->cfg.read_data.num_bytes); + break; + case CFG_EEPROM_GET_MM_INFO: + CDBG("%s E CFG_EEPROM_GET_MM_INFO\n", __func__); + rc = msm_eeprom_get_cmm_data(e_ctrl, cdata); + break; + + case CFG_EEPROM_ERASE: + pr_warn("%s E CFG_EEPROM_ERASE\n", __func__); + rc = eeprom_config_erase(e_ctrl, cdata); + break; + case CFG_EEPROM_POWER_ON: + rc = msm_eeprom_power_up(e_ctrl); + if (rc < 0) + pr_err("%s : msm_eeprom_power_up failed", __func__); + break; + case CFG_EEPROM_POWER_OFF: + rc = msm_eeprom_power_down(e_ctrl); + if (rc < 0) + pr_err("%s : msm_eeprom_power_down failed", __func__); + break; + case CFG_EEPROM_GET_FW_VERSION_INFO: + CDBG("%s E CFG_EEPROM_GET_FW_VERSION_INFO\n", __func__); + rc = eeprom_config_read_fw_version(e_ctrl, cdata); + break; + default: + break; + } + + pr_err("%s X rc: %d\n", __func__, rc); + return rc; +} + +static int msm_eeprom_get_subdev_id(struct msm_eeprom_ctrl_t *e_ctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + CDBG("%s E\n", __func__); + if (!subdev_id) { + pr_err("%s failed\n", __func__); + return -EINVAL; + } + *subdev_id = e_ctrl->subdev_id; + CDBG("subdev_id %d\n", *subdev_id); + CDBG("%s X\n", __func__); + return 0; +} + +static long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + void __user *argp = (void __user *)arg; + CDBG("%s E\n", __func__); + CDBG("%s:%d a_ctrl %p argp %p\n", __func__, __LINE__, e_ctrl, argp); + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return msm_eeprom_get_subdev_id(e_ctrl, argp); + case VIDIOC_MSM_EEPROM_CFG: + return msm_eeprom_config(e_ctrl, argp); + default: + return -ENOIOCTLCMD; + } + + pr_err("%s X\n", __func__); +} + +static struct msm_camera_i2c_fn_t msm_eeprom_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_seq = msm_camera_cci_i2c_write_seq, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; + +static struct msm_camera_i2c_fn_t msm_eeprom_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, +}; + +static struct msm_camera_i2c_fn_t msm_eeprom_spi_func_tbl = { + .i2c_read = msm_camera_spi_read, + .i2c_read_seq = msm_camera_spi_read_seq, +}; + +static int msm_eeprom_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + CDBG("%s E\n", __func__); + if (!e_ctrl) { + pr_err("%s failed e_ctrl is NULL\n", __func__); + return -EINVAL; + } + CDBG("%s X\n", __func__); + return rc; +} + +static int msm_eeprom_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) { + int rc = 0; + struct msm_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + CDBG("%s E\n", __func__); + if (!e_ctrl) { + pr_err("%s failed e_ctrl is NULL\n", __func__); + return -EINVAL; + } + CDBG("%s X\n", __func__); + return rc; +} + +static const struct v4l2_subdev_internal_ops msm_eeprom_internal_ops = { + .open = msm_eeprom_open, + .close = msm_eeprom_close, +}; + +uint8_t* get_eeprom_data_addr() +{ + return map_data; +} + +/** + * read_eeprom_memory() - read map data into buffer + * @e_ctrl: eeprom control struct + * @block: block to be read + * + * This function iterates through blocks stored in block->map, reads each + * region and concatenate them into the pre-allocated block->mapdata + */ +#if defined(CONFIG_SR544) +// compare dtsi file to GTA when L-OS upgrade for rossa/core-prime. +static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_memory_block_t *block) +{ + int rc = 0; + struct msm_eeprom_memory_map_t *emap = block->map; + struct msm_eeprom_board_info *eb_info; + uint8_t *memptr = block->mapdata; + enum msm_camera_i2c_data_type data_type = MSM_CAMERA_I2C_BYTE_DATA; + uint16_t OTP_Bank=0, OTP_Data=0; + int i, j; + uint16_t start_addr; + uint16_t version; + + if (!e_ctrl) { + pr_err("%s e_ctrl is NULL", __func__); + return -EINVAL; + } + + eb_info = e_ctrl->eboard_info; + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &sr544_init); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + rc = prepare_read_write_data(e_ctrl, 0x00, 0x20, MSM_CAMERA_I2C_BYTE_DATA, 0); + if (rc < 0) { + pr_err("%s: failed to prepare read/write on otp\n", __func__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(e_ctrl->i2c_client), r_otp_rdata, + &version, data_type); + if (rc < 0) { + pr_err("%s:(%d) read failed\n", __func__, __LINE__); + return rc; + } + pr_err("%s:(%d) cra_version(0x%02X)",__func__,__LINE__,version); + + rc = prepare_read_write_data(e_ctrl, 0x06, 0x80, MSM_CAMERA_I2C_BYTE_DATA, 0); + if (rc < 0) { + pr_err("%s: failed to prepare read/write on otp\n", __func__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(e_ctrl->i2c_client), r_otp_rdata, + &OTP_Bank, data_type); + if (rc < 0) { + pr_err("%s:(%d) read failed\n", __func__, __LINE__); + return rc; + } + + pr_err("%s: read OTP_Bank: %d\n", __func__, OTP_Bank); + + switch(OTP_Bank) { + case 0: + case 1: + start_addr = 0x0690; + break; + case 3: + start_addr = 0x0EE0; + break; + case 7: + start_addr = 0x1730; + break; + default: + pr_err("%s: Bank error : Bank(%d)\n", __func__, OTP_Bank); + return -EINVAL; + } + + for (j = 0; j < block->num_map; j++) { + if (emap[j].saddr.addr) { + eb_info->i2c_slaveaddr = emap[j].saddr.addr; + e_ctrl->i2c_client.cci_client->sid = + eb_info->i2c_slaveaddr >> 1; + pr_err("qcom,slave-addr = 0x%X\n", + eb_info->i2c_slaveaddr); + } + } + + pr_err("%s:(%d) e_ctrl->cal_data.num_data : %x\n", __func__, __LINE__, e_ctrl->cal_data.num_data); + + if (e_ctrl->cal_data.num_data) + { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_addr_h, + ((start_addr & 0xFF00) >> 8), data_type); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_addr_l, + (start_addr & 0x00FF), data_type); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write( + &(e_ctrl->i2c_client), r_otp_cmd, + 0x01, data_type); + if (rc < 0) { + pr_err("%s:(%d) write failed\n", __func__, __LINE__); + return rc; + } + + for (i=0; ical_data.num_data; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(e_ctrl->i2c_client), r_otp_rdata, + &OTP_Data, data_type); + if (rc < 0) { + pr_err("%s:(%d) read failed\n", __func__, __LINE__); + return rc; + } + memptr[i] = OTP_Data; + } +#ifdef EEPROM_MMAP_DEBUG + printk("OTP data : "); + for (i=0; ical_data.num_data; i++) { + printk("[%d:%x], ", i, memptr[i]); + if(i%16 == 15) + printk("\n"); + } + printk("\n"); +#endif + + // copy CRA information which is read from OTP 0x20 to cal data [0x50] address. + memptr[0x50] = version & 0xFF; + pr_err("%s: %d version = 0x%02X, memptr[0x50] = 0x%02X\n", __func__, __LINE__ , version, memptr[0x50]); + + memptr += e_ctrl->cal_data.num_data; + pr_err("%s: %d memptr after addition = %p\n", __func__, __LINE__ , memptr); + } + return rc; +} +#else +static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl, + struct msm_eeprom_memory_block_t *block) +{ + int rc = 0; + struct msm_eeprom_memory_map_t *emap = block->map; + struct msm_eeprom_board_info *eb_info; + uint8_t *memptr = block->mapdata; + enum msm_camera_i2c_data_type data_type = MSM_CAMERA_I2C_BYTE_DATA; + uint16_t OTP_Bank=0, OTP_Data=0; + int i, j; + uint8_t page; + + if (!e_ctrl) { + pr_err("%s e_ctrl is NULL", __func__); + return -EINVAL; + } + + eb_info = e_ctrl->eboard_info; + + for (j = 0; j < block->num_map; j++) { + if (emap[j].saddr.addr) { + eb_info->i2c_slaveaddr = emap[j].saddr.addr; + e_ctrl->i2c_client.cci_client->sid = + eb_info->i2c_slaveaddr >> 1; + pr_err("qcom,slave-addr = 0x%X\n", + eb_info->i2c_slaveaddr); + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_read_otp); + if (rc < 0) { + pr_err("%s:(%d) init_read_otp failed\n", __func__, __LINE__); + return rc; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(e_ctrl->i2c_client), 0x0A04, + &OTP_Bank, data_type); + if (rc < 0) { + pr_err("%s:(%d) read failed\n", __func__, __LINE__); + return rc; + } + + pr_err("%s: read OTP_Bank: %d\n", __func__, OTP_Bank); + + switch(OTP_Bank) { + case 0: + case 1: + page = 2; + break; + case 3: + page = 3; + break; + case 7: + page = 4; + break; + case 0xF: + page = 5; + break; + default: + pr_err("%s: Bank error : Bank(%d)\n", __func__, OTP_Bank); + return -EINVAL; + } + init_read_otp.reg_setting[1].reg_data = page; + init_write_otp.reg_setting[7].reg_data = page; + + if (emap[j].mem.valid_size) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &init_read_otp); + if (rc < 0) { + pr_err("%s:(%d) init_read_otp failed\n", __func__, __LINE__); + return rc; + } + + for (i=0x0A08; i<=0x0A41; i++) { + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read( + &(e_ctrl->i2c_client), i, + &OTP_Data, data_type); + if (rc < 0) { + pr_err("%s:(%d) read failed\n", __func__, __LINE__); + return rc; + } + memptr[i-0x0A08] = OTP_Data; + } + + rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write_table( + &(e_ctrl->i2c_client), &finish_read_otp); + if (rc < 0) { + pr_err("%s:(%d) finish_read_otp failed\n", __func__, __LINE__); + return rc; + } +#ifdef EEPROM_MMAP_DEBUG + for (i=0; inum_map); + pr_err("%s::%d %s %d\n", __func__, __LINE__, property, data->num_map); + if (rc < 0) { + pr_err("%s::%d failed rc %d\n", __func__,__LINE__,rc); + return rc; + } + + map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + if (!map) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return -ENOMEM; + } + data->map = map; + + for (i = 0; i < data->num_map; i++) { + pr_err("%s, %d: i = %d\n", __func__, __LINE__, i); + + snprintf(property, PROPERTY_MAXSIZE, "qcom,page%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].page, count); + if (rc < 0) { + pr_err("%s: failed %d\n", __func__, __LINE__); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "qcom,poll%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].poll, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "qcom,mem%d", i); + rc = of_property_read_u32_array(of, property, + (uint32_t *) &map[i].mem, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + data->num_data += map[i].mem.valid_size; + } + pr_err("%s::%d valid size = %d\n", __func__,__LINE__, data->num_data); + + total_size = 0; + +#if defined(CONFIG_SR544) + // if total-size is defined at dtsi file. + // set num_data as total-size (refer dtsi file of GTA) + snprintf(property, PROPERTY_MAXSIZE, "qcom,total-size"); + rc = of_property_read_u32(of, property, &total_size); + pr_err("%s::%d %s %d\n", __func__,__LINE__,property, total_size); + + // if "qcom,total-size" propoerty exists. + if (rc >= 0) { + pr_err("%s::%d set num_data as total-size in order to use same address at cal map(total : %d, valid : %d)\n", + __func__,__LINE__, total_size, data->num_data); + data->num_data = total_size; + } +#endif + + data->mapdata = kzalloc(data->num_data, GFP_KERNEL); + if (!data->mapdata) { + pr_err("%s failed line %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + return rc; + +ERROR: + kfree(data->map); + memset(data, 0, sizeof(*data)); + return rc; +} + +static struct msm_cam_clk_info cam_8960_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_clk", 24000000}, +}; + +static struct msm_cam_clk_info cam_8974_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, + [SENSOR_CAM_CLK] = {"cam_clk", 0}, +}; + +static struct v4l2_subdev_core_ops msm_eeprom_subdev_core_ops = { + .ioctl = msm_eeprom_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_eeprom_subdev_ops = { + .core = &msm_eeprom_subdev_core_ops, +}; + +static int msm_eeprom_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + uint32_t temp = 0; + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + struct device_node *of_node = client->dev.of_node; + int j; + + pr_err("%s E\n", __func__); + + if (!of_node) { + pr_err("%s of_node NULL\n", __func__); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s i2c_check_functionality failed\n", __func__); + goto probe_failure; + } + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + rc = -ENOMEM; + goto probe_failure; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + pr_err("%s client = 0x%p\n", __func__, client); + + //e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data); + e_ctrl->eboard_info = kzalloc(sizeof( + struct msm_eeprom_board_info), GFP_KERNEL); + if (!e_ctrl->eboard_info) { + pr_err("%s:%d board info NULL\n", __func__, __LINE__); + rc = -EINVAL; + goto memdata_free; + } + + rc = of_property_read_u32(of_node, "qcom,slave-addr", &temp); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + goto board_free; + } + + rc = of_property_read_u32(of_node, "cell-index", + &e_ctrl->subdev_id); + pr_err("cell-index/subdev_id %d, rc %d\n", e_ctrl->subdev_id, rc); + if (rc < 0) { + pr_err("failed read, rc %d\n", rc); + goto board_free; + } + + power_info = &e_ctrl->eboard_info->power_info; + e_ctrl->eboard_info->i2c_slaveaddr = temp; + e_ctrl->i2c_client.client = client; + e_ctrl->is_supported = 0; + + pr_err("%s:%d e_ctrl->eboard_info->i2c_slaveaddr = %d\n", __func__, __LINE__ , e_ctrl->eboard_info->i2c_slaveaddr); + + /* Set device type as I2C */ + e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; + e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl; + e_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_WORD_ADDR; + + if (e_ctrl->eboard_info->i2c_slaveaddr != 0) + e_ctrl->i2c_client.client->addr = + e_ctrl->eboard_info->i2c_slaveaddr; + power_info->clk_info = cam_8960_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info); + power_info->dev = &client->dev; + + + rc = of_property_read_string(of_node, "qcom,eeprom-name", + &e_ctrl->eboard_info->eeprom_name); + pr_err("%s qcom,eeprom-name %s, rc %d\n", __func__, + e_ctrl->eboard_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto board_free; + } + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc) + goto board_free; + rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data); + if (rc < 0) + pr_err("%s: no cal memory map\n", __func__); + if (e_ctrl->cal_data.mapdata) + map_data = e_ctrl->cal_data.mapdata; + + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto board_free; + } + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s read_eeprom_memory failed\n", __func__); + goto power_down; + } + for (j = 0; j < e_ctrl->cal_data.num_data; j++) + CDBG("memory_data[%d] = 0x%X\n", j, + e_ctrl->cal_data.mapdata[j]); + +// e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); + + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto power_down; + } + + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", &temp)) { + pr_err("%s:%d Fail position, Default sensor position\n", __func__, __LINE__); + temp = 0; + } + pr_err("%s qcom,sensor-position %d\n", __func__,temp); + + /* Initialize sub device */ + v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->i2c_client.client, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.flags = temp; + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + e_ctrl->is_supported = 1; + pr_err("%s success result=%d X\n", __func__, rc); + return rc; + +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +board_free: + if (e_ctrl->eboard_info) + kfree(e_ctrl->eboard_info); +memdata_free: + if (e_ctrl) + kfree(e_ctrl); +probe_failure: + pr_err("%s failed! rc = %d\n", __func__, rc); + return rc; +} + +static int msm_eeprom_i2c_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +#define msm_eeprom_spi_parse_cmd(spic, str, name, out, size) \ + { \ + if (of_property_read_u32_array( \ + spic->spi_master->dev.of_node, \ + str, out, size)) { \ + return -EFAULT; \ + } else { \ + spic->cmd_tbl.name.opcode = out[0]; \ + spic->cmd_tbl.name.addr_len = out[1]; \ + spic->cmd_tbl.name.dummy_len = out[2]; \ + } \ + } + +static int msm_eeprom_spi_parse_of(struct msm_camera_spi_client *spic) +{ + int rc = -EFAULT; + uint32_t tmp[3]; + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,read", read, tmp, 3); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,readseq", read_seq, tmp, 3); + msm_eeprom_spi_parse_cmd(spic, "qcom,spiop,queryid", query_id, tmp, 3); + + rc = of_property_read_u32_array(spic->spi_master->dev.of_node, + "qcom,eeprom-id", tmp, 2); + if (rc) { + pr_err("%s: Failed to get eeprom id\n", __func__); + return rc; + } + spic->mfr_id = tmp[0]; + spic->device_id = tmp[1]; + + return 0; +} + +static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc; + struct msm_camera_i2c_client *client = &e_ctrl->i2c_client; + uint8_t id[2]; + + rc = msm_camera_spi_query_id(client, 0, &id[0], 2); + if (rc < 0) + return rc; + pr_err("%s: read 0x%x 0x%x, check 0x%x 0x%x\n", __func__, id[0], + id[1], client->spi_client->mfr_id, client->spi_client->device_id); + if (id[0] != client->spi_client->mfr_id + || id[1] != client->spi_client->device_id) + return -ENODEV; + + return 0; +} + +static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0, i = 0; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = + &e_ctrl->eboard_info->power_info; + struct device_node *of_node = NULL; + struct msm_camera_gpio_conf *gconf = NULL; + uint16_t gpio_array_size = 0; + uint16_t *gpio_array = NULL; + + eb_info = e_ctrl->eboard_info; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) + of_node = e_ctrl->i2c_client. + spi_client->spi_master->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) + of_node = e_ctrl->pdev->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE) + of_node = e_ctrl->i2c_client.client->dev.of_node; + rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, + &power_info->num_vreg); + if (rc < 0) { + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + return rc; + } + + pr_err("msm_camera_get_dt_power_setting_data : %d\n", __LINE__); + rc = msm_camera_get_dt_power_setting_data(of_node, + power_info->cam_vreg, power_info->num_vreg, + power_info); + if (rc < 0) { + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + goto ERROR1; + } + + power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!power_info->gpio_conf) { + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + rc = -ENOMEM; + goto ERROR2; + } + gconf = power_info->gpio_conf; + gpio_array_size = of_gpio_count(of_node); + pr_err("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR3; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + pr_err("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(gpio_array); + } + + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + return rc; +ERROR4: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(gpio_array); +ERROR3: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(power_info->gpio_conf); +ERROR2: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(power_info->cam_vreg); +ERROR1: + pr_err("msm_eeprom_get_dt_data: %d\n", __LINE__); + kfree(power_info->power_setting); + return rc; +} + + +static int msm_eeprom_cmm_dts(struct msm_eeprom_board_info *eb_info, + struct device_node *of_node) +{ + int rc = 0; + struct msm_eeprom_cmm_t *cmm_data = &eb_info->cmm_data; + + cmm_data->cmm_support = + of_property_read_bool(of_node, "qcom,cmm-data-support"); + if (!cmm_data->cmm_support){ + pr_err("%s::%d qcom,cmm-data-support failed ",__func__,__LINE__); + return -EINVAL; + } + cmm_data->cmm_compression = + of_property_read_bool(of_node, "qcom,cmm-data-compressed"); + if (!cmm_data->cmm_compression) + CDBG("No MM compression data\n"); + + rc = of_property_read_u32(of_node, "qcom,cmm-data-offset", + &cmm_data->cmm_offset); + if (rc < 0) + CDBG("No MM offset data\n"); + + rc = of_property_read_u32(of_node, "qcom,cmm-data-size", + &cmm_data->cmm_size); + if (rc < 0) + CDBG("No MM size data\n"); + + CDBG("cmm_support: cmm_compr %d, cmm_offset %d, cmm_size %d\n", + cmm_data->cmm_compression, + cmm_data->cmm_offset, + cmm_data->cmm_size); + return 0; +} + +static int msm_eeprom_spi_setup(struct spi_device *spi) +{ + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_camera_i2c_client *client = NULL; + struct msm_camera_spi_client *spi_client; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = NULL; + int rc = 0; + uint32_t temp = 0; + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + client = &e_ctrl->i2c_client; + e_ctrl->is_supported = 0; + + spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL); + if (!spi_client) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + kfree(e_ctrl); + return -ENOMEM; + } + + rc = of_property_read_u32(spi->dev.of_node, "cell-index", + &e_ctrl->subdev_id); + CDBG("cell-index/subdev_id %d, rc %d\n", e_ctrl->subdev_id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto spi_free; + } + + e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE; + client->spi_client = spi_client; + spi_client->spi_master = spi; + client->i2c_func_tbl = &msm_eeprom_spi_func_tbl; + client->addr_type = MSM_CAMERA_I2C_3B_ADDR; + + eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL); + if (!eb_info) + goto spi_free; + e_ctrl->eboard_info = eb_info; + rc = of_property_read_string(spi->dev.of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto board_free; + } + + rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, spi->dev.of_node); + if (rc < 0) + CDBG("%s MM data miss:%d\n", __func__, __LINE__); + + power_info = &eb_info->power_info; + + power_info->clk_info = cam_8974_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); + power_info->dev = &spi->dev; + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc < 0) + goto board_free; + + /* set spi instruction info */ + spi_client->retry_delay = 1; + spi_client->retries = 0; + + rc = msm_eeprom_spi_parse_of(spi_client); + if (rc < 0) { + dev_err(&spi->dev, + "%s: Error parsing device properties\n", __func__); + goto board_free; + } + + /* prepare memory buffer */ + rc = msm_eeprom_parse_memory_map(spi->dev.of_node, + &e_ctrl->cal_data); + if (rc < 0) + CDBG("%s: no cal memory map\n", __func__); + + /* power up eeprom for reading */ + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto caldata_free; + } + + /* check eeprom id */ + rc = msm_eeprom_match_id(e_ctrl); + if (rc < 0) { + CDBG("%s: eeprom not matching %d\n", __func__, rc); + goto power_down; + } + /* read eeprom */ + if (e_ctrl->cal_data.map) { + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s: read cal data failed\n", __func__); + goto power_down; + } + e_ctrl->is_supported |= msm_eeprom_match_crc( + &e_ctrl->cal_data); + } + + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto caldata_free; + } + + if (0 > of_property_read_u32(spi->dev.of_node, "qcom,sensor-position", &temp)) { + pr_err("%s:%d Fail position, Default sensor position\n", __func__, __LINE__); + temp = 0; + } + + /* initiazlie subdev */ + v4l2_spi_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->i2c_client.spi_client->spi_master, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.flags = temp; + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + CDBG("%s success result=%d supported=%x X\n", __func__, rc, + e_ctrl->is_supported); + + return 0; + +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +caldata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); +spi_free: + kfree(spi_client); + kfree(e_ctrl); + return rc; +} + +static int msm_eeprom_spi_probe(struct spi_device *spi) +{ + int irq, cs, cpha, cpol, cs_high; + + pr_err("%s\n", __func__); + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + spi_setup(spi); + + irq = spi->irq; + cs = spi->chip_select; + cpha = (spi->mode & SPI_CPHA) ? 1 : 0; + cpol = (spi->mode & SPI_CPOL) ? 1 : 0; + cs_high = (spi->mode & SPI_CS_HIGH) ? 1 : 0; + pr_err("%s: irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n", + __func__, irq, cs, cpha, cpol, cs_high); + pr_err("%s: max_speed[%u]\n", __func__, spi->max_speed_hz); + + return msm_eeprom_spi_setup(spi); +} + +static int msm_eeprom_spi_remove(struct spi_device *sdev) +{ + struct v4l2_subdev *sd = spi_get_drvdata(sdev); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->i2c_client.spi_client); + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +static int msm_eeprom_platform_probe(struct platform_device *pdev) +{ + int rc = 0; + int j = 0; + uint32_t temp; + + struct msm_camera_cci_client *cci_client = NULL; + struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_eeprom_board_info *eb_info = NULL; + struct device_node *of_node = pdev->dev.of_node; + struct msm_camera_power_ctrl_t *power_info = NULL; + + pr_err("%s E\n", __func__); + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + pr_err("%s:%d kzalloc failed\n", __func__, __LINE__); + return -ENOMEM; + } + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; + e_ctrl->eeprom_mutex = &msm_eeprom_mutex; + + e_ctrl->is_supported = 0; + if (!of_node) { + pr_err("%s dev.of_node NULL\n", __func__); + kfree(e_ctrl); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, "cell-index", + &pdev->id); + CDBG("cell-index %d, rc %d\n", pdev->id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + kfree(e_ctrl); + return rc; + } + e_ctrl->subdev_id = pdev->id; + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &e_ctrl->cci_master); + CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + kfree(e_ctrl); + return rc; + } + rc = of_property_read_u32(of_node, "qcom,slave-addr", + &temp); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + kfree(e_ctrl); + return rc; + } + + /* Set platform device handle */ + e_ctrl->pdev = pdev; + /* Set device type as platform device */ + e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE; + e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_cci_func_tbl; + e_ctrl->i2c_client.addr_type = MSM_CAMERA_I2C_WORD_ADDR; + e_ctrl->i2c_client.cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!e_ctrl->i2c_client.cci_client) { + pr_err("%s failed no memory\n", __func__); + kfree(e_ctrl); + return -ENOMEM; + } + + e_ctrl->eboard_info = kzalloc(sizeof( + struct msm_eeprom_board_info), GFP_KERNEL); + if (!e_ctrl->eboard_info) { + pr_err("%s failed line %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto cciclient_free; + } + eb_info = e_ctrl->eboard_info; + power_info = &eb_info->power_info; + eb_info->i2c_slaveaddr = temp; + + power_info->clk_info = cam_8974_clk_info; + power_info->clk_info_size = ARRAY_SIZE(cam_8974_clk_info); + power_info->dev = &pdev->dev; + + CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr); + cci_client = e_ctrl->i2c_client.cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = e_ctrl->cci_master; + cci_client->sid = eb_info->i2c_slaveaddr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + + rc = of_property_read_string(of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto board_free; + } + + rc = msm_eeprom_cmm_dts(e_ctrl->eboard_info, of_node); + if (rc < 0){ + pr_err("%s MM data miss:%d\n", __func__, __LINE__); + } + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc) + goto board_free; + + rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data); + if (rc < 0) + goto board_free; + + if (e_ctrl->cal_data.mapdata) + map_data = e_ctrl->cal_data.mapdata; + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s read_eeprom_memory failed\n", __func__); + goto power_down; + } + for (j = 0; j < e_ctrl->cal_data.num_data; j++) + CDBG("memory_data[%d] = 0x%X\n", j, + e_ctrl->cal_data.mapdata[j]); + + e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); + + rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", &temp)) { + pr_err("%s:%d Fail position, Default sensor position\n", __func__, __LINE__); + temp = 0; + } + pr_err("%s qcom,sensor-position %d\n", __func__,temp); + + v4l2_subdev_init(&e_ctrl->msm_sd.sd, + e_ctrl->eeprom_v4l2_subdev_ops); + v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); + platform_set_drvdata(pdev, &e_ctrl->msm_sd.sd); + e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; + e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(e_ctrl->msm_sd.sd.name, + ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_otp"); + media_entity_init(&e_ctrl->msm_sd.sd.entity, 0, NULL, 0); + e_ctrl->msm_sd.sd.entity.flags = temp; + e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM; + msm_sd_register(&e_ctrl->msm_sd); + + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + pr_err("%s X\n", __func__); + return rc; + +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +memdata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); +cciclient_free: + kfree(e_ctrl->i2c_client.cci_client); + kfree(e_ctrl); + return rc; +} + +static int msm_eeprom_platform_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct msm_eeprom_ctrl_t *e_ctrl; + if (!sd) { + pr_err("%s: Subdevice is NULL\n", __func__); + return 0; + } + + e_ctrl = (struct msm_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + pr_err("%s: eeprom device is NULL\n", __func__); + return 0; + } + + kfree(e_ctrl->i2c_client.cci_client); + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + if (e_ctrl->eboard_info) { + kfree(e_ctrl->eboard_info->power_info.gpio_conf); + kfree(e_ctrl->eboard_info); + } + kfree(e_ctrl); + return 0; +} + +static const struct of_device_id msm_eeprom_dt_match[] = { + { .compatible = "qcom,otp" }, + { } +}; + +MODULE_DEVICE_TABLE(of, msm_eeprom_dt_match); + +static struct platform_driver msm_eeprom_platform_driver = { + .driver = { + .name = "qcom,otp", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_dt_match, + }, + .remove = msm_eeprom_platform_remove, +}; + +static const struct of_device_id msm_eeprom_i2c_dt_match[] = { + { .compatible = "qcom,otp"}, + { } +}; + +MODULE_DEVICE_TABLE(of, msm_eeprom_i2c_dt_match); + +static const struct i2c_device_id msm_eeprom_i2c_id[] = { + { "qcom,otp", (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver msm_eeprom_i2c_driver = { + .id_table = msm_eeprom_i2c_id, + .probe = msm_eeprom_i2c_probe, + .remove = msm_eeprom_i2c_remove, + .driver = { + .name = "qcom,otp", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_i2c_dt_match, + }, +}; + +static struct spi_driver msm_eeprom_spi_driver = { + .driver = { + .name = "qcom_otp", + .owner = THIS_MODULE, + .of_match_table = msm_eeprom_dt_match, + }, + .probe = msm_eeprom_spi_probe, + .remove = msm_eeprom_spi_remove, +}; + +static int __init msm_eeprom_init_module(void) +{ + int rc = 0 /*, spi_rc = 0*/; + pr_err("%s E\n", __func__); + rc = platform_driver_probe(&msm_eeprom_platform_driver, + msm_eeprom_platform_probe); + if(rc<0){ + pr_err("%s:%d platform rc %d\n", __func__, __LINE__, rc); + return rc; + } + rc = i2c_add_driver(&msm_eeprom_i2c_driver); + if (rc < 0) + pr_err("%s:%d probe failed\n", __func__, __LINE__); + return rc; +} + +static void __exit msm_eeprom_exit_module(void) +{ + platform_driver_unregister(&msm_eeprom_platform_driver); + spi_unregister_driver(&msm_eeprom_spi_driver); + i2c_del_driver(&msm_eeprom_i2c_driver); +} + +module_init(msm_eeprom_init_module); +module_exit(msm_eeprom_exit_module); +MODULE_DESCRIPTION("MSM EEPROM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp_s5k5e3yx.h b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp_s5k5e3yx.h new file mode 100755 index 0000000000000000000000000000000000000000..215ed6baf643c5fa6b20d1e2765c3b088bca883f --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp_s5k5e3yx.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ +#ifndef MSM_EEPROM_H +#define MSM_EEPROM_H + +#include +#include +#include "../../include/soc/qcom/camera2.h" +#include +#include "../../include/media/msmb_camera.h" +#include "msm_camera_i2c.h" +#include "msm_camera_spi.h" +#include "msm_camera_io_util.h" +#include "msm_camera_dt_util.h" + +struct msm_eeprom_ctrl_t; + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define PROPERTY_MAXSIZE 32 +#define EEPROM_FW_VERSION_OFFSET 17 + +struct msm_eeprom_ctrl_t { + struct platform_device *pdev; + struct mutex *eeprom_mutex; + + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops; + enum msm_camera_device_type_t eeprom_device_type; + struct msm_sd_subdev msm_sd; + enum cci_i2c_master_t cci_master; + + struct msm_camera_i2c_client i2c_client; + struct msm_eeprom_memory_block_t cal_data; + uint8_t is_supported; + struct msm_eeprom_board_info *eboard_info; + uint32_t subdev_id; +}; + +static struct msm_camera_i2c_reg_array init_read_s5k5e3yx_otp_reg[] = { + {0x0A00, 0x04, NULL, 0}, + {0x0A02, 0x02, NULL, 0}, + {0x0A00, 0x01, NULL, 10}, +}; + +struct msm_camera_i2c_reg_setting init_read_otp = { + init_read_s5k5e3yx_otp_reg, sizeof(init_read_s5k5e3yx_otp_reg)/sizeof(struct msm_camera_i2c_reg_array), MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_BYTE_DATA, 10 +}; + +static struct msm_camera_i2c_reg_array finish_read_s5k5e3yx_otp_reg[] = { + {0x0A00, 0x04, NULL, 0}, + {0x0A00, 0x00, NULL, 0}, +}; + +struct msm_camera_i2c_reg_setting finish_read_otp = { + finish_read_s5k5e3yx_otp_reg, sizeof(finish_read_s5k5e3yx_otp_reg)/sizeof(struct msm_camera_i2c_reg_array), MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_BYTE_DATA, 10 +}; + +static struct msm_camera_i2c_reg_array init_write_s5k5e3yx_otp_reg[] = { + {0x3b42, 0x68, NULL, 0}, + {0x3b41, 0x01, NULL, 0}, + {0x3b40, 0x00, NULL, 0}, + {0x3b45, 0x02, NULL, 0}, + {0x0A00, 0x04, NULL, 0}, + {0x0A00, 0x03, NULL, 0}, + {0x3b42, 0x00, NULL, 0}, + {0x0A02, 0x02, NULL, 0}, + {0x0A00, 0x03, NULL, 10}, +}; + +struct msm_camera_i2c_reg_setting init_write_otp = { + init_write_s5k5e3yx_otp_reg, sizeof(init_write_s5k5e3yx_otp_reg)/sizeof(struct msm_camera_i2c_reg_array), MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_BYTE_DATA, 10 +}; + +static struct msm_camera_i2c_reg_array finish_write_s5k5e3yx_otp_reg[] = { + {0x0A00, 0x04, NULL, 0}, + {0x0A00, 0x00, NULL, 0}, + {0x3b40, 0x01, NULL, 10}, +}; + +struct msm_camera_i2c_reg_setting finish_write_otp = { + finish_write_s5k5e3yx_otp_reg, sizeof(finish_write_s5k5e3yx_otp_reg)/sizeof(struct msm_camera_i2c_reg_array), MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_BYTE_DATA, 10 +}; + +extern uint8_t* get_eeprom_data_addr(void); +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp_sr544.h b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp_sr544.h new file mode 100755 index 0000000000000000000000000000000000000000..c4eeffe62a52f59a65ae6cf9ef147dc5757ba55e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/eeprom/msm_otp_sr544.h @@ -0,0 +1,2102 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ +#ifndef MSM_EEPROM_H +#define MSM_EEPROM_H + +#include +#include +#include "../../include/soc/qcom/camera2.h" +#include +#include "../../include/media/msmb_camera.h" +#include "msm_camera_i2c.h" +#include "msm_camera_spi.h" +#include "msm_camera_io_util.h" +#include "msm_camera_dt_util.h" + +struct msm_eeprom_ctrl_t; + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define PROPERTY_MAXSIZE 32 +#define EEPROM_FW_VERSION_OFFSET 48 +#define r_otp_addr_h 0x010A +#define r_otp_addr_l 0x010B +#define r_otp_cmd 0x0102 +#define r_otp_wdata 0x0106 +#define r_otp_rdata 0x0108 + +struct msm_eeprom_ctrl_t { + struct platform_device *pdev; + struct mutex *eeprom_mutex; + + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops; + enum msm_camera_device_type_t eeprom_device_type; + struct msm_sd_subdev msm_sd; + enum cci_i2c_master_t cci_master; + + struct msm_camera_i2c_client i2c_client; + struct msm_eeprom_memory_block_t cal_data; + uint8_t is_supported; + struct msm_eeprom_board_info *eboard_info; + uint32_t subdev_id; +}; + +static struct msm_camera_i2c_reg_array sr544_init_reg[] = { +{0x0118, 0x0000}, //sleep On + +//--- SRAM timing control---// +{0x0E00, 0x0101}, +{0x0E02, 0x0101}, +{0x0E04, 0x0101}, +{0x0E06, 0x0101}, +{0x0E08, 0x0101}, +{0x0E0A, 0x0101}, +{0x0E0C, 0x0101}, +{0x0E0E, 0x0101}, + +//Firmware 2Lane v0.39, LB OTP Burst On + double luma under dark. FW 20140804 +{0x2000, 0x4031}, +{0x2002, 0x83F8}, +{0x2004, 0x4104}, +{0x2006, 0x4307}, +{0x2008, 0x4382}, +{0x200a, 0x80D0}, +{0x200c, 0x4382}, +{0x200e, 0x8070}, +{0x2010, 0x43A2}, +{0x2012, 0x0B80}, +{0x2014, 0x0C0A}, +{0x2016, 0x4382}, +{0x2018, 0x0B90}, +{0x201a, 0x0C0A}, +{0x201c, 0x4382}, +{0x201e, 0x0B9C}, +{0x2020, 0x0C0A}, +{0x2022, 0x93D2}, +{0x2024, 0x003D}, +{0x2026, 0x2002}, +{0x2028, 0x4030}, +{0x202a, 0xF6C0}, +{0x202c, 0x43C2}, +{0x202e, 0x0F82}, +{0x2030, 0x425F}, +{0x2032, 0x0118}, +{0x2034, 0xF37F}, +{0x2036, 0x930F}, +{0x2038, 0x2002}, +{0x203a, 0x0CC8}, +{0x203c, 0x3FF9}, +{0x203e, 0x4F82}, +{0x2040, 0x809A}, +{0x2042, 0x43D2}, +{0x2044, 0x0A80}, +{0x2046, 0x43D2}, +{0x2048, 0x0180}, +{0x204a, 0x43D2}, +{0x204c, 0x019A}, +{0x204e, 0x40F2}, +{0x2050, 0x0009}, +{0x2052, 0x019B}, +{0x2054, 0x12B0}, +{0x2056, 0xFE26}, +{0x2058, 0x4382}, +{0x205a, 0x8094}, +{0x205c, 0x93D2}, +{0x205e, 0x003E}, +{0x2060, 0x2002}, +{0x2062, 0x4030}, +{0x2064, 0xF5A0}, +{0x2066, 0x4308}, +{0x2068, 0x5038}, +{0x206a, 0x0030}, +{0x206c, 0x480F}, +{0x206e, 0x12B0}, +{0x2070, 0xFE38}, +{0x2072, 0x403B}, +{0x2074, 0x7606}, +{0x2076, 0x4B29}, +{0x2078, 0x5318}, +{0x207a, 0x480F}, +{0x207c, 0x12B0}, +{0x207e, 0xFE38}, +{0x2080, 0x4B2A}, +{0x2082, 0x5318}, +{0x2084, 0x480F}, +{0x2086, 0x12B0}, +{0x2088, 0xFE38}, +{0x208a, 0x4A0D}, +{0x208c, 0xF03D}, +{0x208e, 0x000F}, +{0x2090, 0x108D}, +{0x2092, 0x4B2E}, +{0x2094, 0x5E0E}, +{0x2096, 0x5E0E}, +{0x2098, 0x5E0E}, +{0x209a, 0x5E0E}, +{0x209c, 0x4A0F}, +{0x209e, 0xC312}, +{0x20a0, 0x100F}, +{0x20a2, 0x110F}, +{0x20a4, 0x110F}, +{0x20a6, 0x110F}, +{0x20a8, 0x590D}, +{0x20aa, 0x4D87}, +{0x20ac, 0x5000}, +{0x20ae, 0x5F0E}, +{0x20b0, 0x4E87}, +{0x20b2, 0x6000}, +{0x20b4, 0x5327}, +{0x20b6, 0x5038}, +{0x20b8, 0xFFD1}, +{0x20ba, 0x9038}, +{0x20bc, 0x0300}, +{0x20be, 0x2BD4}, +{0x20c0, 0x0261}, +{0x20c2, 0x0000}, +{0x20c4, 0x43A2}, +{0x20c6, 0x0384}, +{0x20c8, 0x42B2}, +{0x20ca, 0x0386}, +{0x20cc, 0x43C2}, +{0x20ce, 0x0180}, +{0x20d0, 0x43D2}, +{0x20d2, 0x003D}, +{0x20d4, 0x40B2}, +{0x20d6, 0x808B}, +{0x20d8, 0x0B88}, +{0x20da, 0x0C0A}, +{0x20dc, 0x40B2}, +{0x20de, 0x1009}, +{0x20e0, 0x0B8A}, +{0x20e2, 0x0C0A}, +{0x20e4, 0x40B2}, +{0x20e6, 0xC40C}, +{0x20e8, 0x0B8C}, +{0x20ea, 0x0C0A}, +{0x20ec, 0x40B2}, +{0x20ee, 0xC9E1}, +{0x20f0, 0x0B8E}, +{0x20f2, 0x0C0A}, +{0x20f4, 0x40B2}, +{0x20f6, 0x0C1E}, +{0x20f8, 0x0B92}, +{0x20fa, 0x0C0A}, +{0x20fc, 0x43D2}, +{0x20fe, 0x0F82}, +{0x2100, 0x0C3C}, +{0x2102, 0x0C3C}, +{0x2104, 0x0C3C}, +{0x2106, 0x0C3C}, +{0x2108, 0x421F}, +{0x210a, 0x00A6}, +{0x210c, 0x503F}, +{0x210e, 0x07D0}, +{0x2110, 0x3811}, +{0x2112, 0x4F82}, +{0x2114, 0x7100}, +{0x2116, 0x0004}, +{0x2118, 0x0C0D}, +{0x211a, 0x0005}, +{0x211c, 0x0C04}, +{0x211e, 0x000D}, +{0x2120, 0x0C09}, +{0x2122, 0x003D}, +{0x2124, 0x0C1D}, +{0x2126, 0x003C}, +{0x2128, 0x0C13}, +{0x212a, 0x0004}, +{0x212c, 0x0C09}, +{0x212e, 0x0004}, +{0x2130, 0x533F}, +{0x2132, 0x37EF}, +{0x2134, 0x4392}, +{0x2136, 0x8096}, +{0x2138, 0x4382}, +{0x213a, 0x809E}, +{0x213c, 0x4382}, +{0x213e, 0x80B6}, +{0x2140, 0x4382}, +{0x2142, 0x80BE}, +{0x2144, 0x4382}, +{0x2146, 0x80A2}, +{0x2148, 0x40B2}, +{0x214a, 0x0028}, +{0x214c, 0x7000}, +{0x214e, 0x43A2}, +{0x2150, 0x80A0}, +{0x2152, 0xB3E2}, +{0x2154, 0x00B4}, +{0x2156, 0x2402}, +{0x2158, 0x4392}, +{0x215a, 0x80A0}, +{0x215c, 0x4326}, +{0x215e, 0xB3D2}, +{0x2160, 0x00B4}, +{0x2162, 0x2002}, +{0x2164, 0x4030}, +{0x2166, 0xF590}, +{0x2168, 0x4306}, +{0x216a, 0x4384}, +{0x216c, 0x0002}, +{0x216e, 0x4384}, +{0x2170, 0x0006}, +{0x2172, 0x4382}, +{0x2174, 0x809C}, +{0x2176, 0x4382}, +{0x2178, 0x8098}, +{0x217a, 0x40B2}, +{0x217c, 0x0005}, +{0x217e, 0x7320}, +{0x2180, 0x4392}, +{0x2182, 0x7326}, +{0x2184, 0x12B0}, +{0x2186, 0xF952}, +{0x2188, 0x4392}, +{0x218a, 0x731C}, +{0x218c, 0x9382}, +{0x218e, 0x8096}, +{0x2190, 0x200A}, +{0x2192, 0x0B00}, +{0x2194, 0x7302}, +{0x2196, 0x02BC}, +{0x2198, 0x4382}, +{0x219a, 0x7004}, +{0x219c, 0x430F}, +{0x219e, 0x12B0}, +{0x21a0, 0xF752}, +{0x21a2, 0x12B0}, +{0x21a4, 0xF952}, +{0x21a6, 0x4392}, +{0x21a8, 0x80BC}, +{0x21aa, 0x4382}, +{0x21ac, 0x740E}, +{0x21ae, 0xB3E2}, +{0x21b0, 0x0080}, +{0x21b2, 0x2402}, +{0x21b4, 0x4392}, +{0x21b6, 0x740E}, +{0x21b8, 0x431F}, +{0x21ba, 0x12B0}, +{0x21bc, 0xF752}, +{0x21be, 0x4392}, +{0x21c0, 0x7004}, +{0x21c2, 0x4682}, +{0x21c4, 0x7110}, +{0x21c6, 0x9382}, +{0x21c8, 0x8092}, +{0x21ca, 0x2005}, +{0x21cc, 0x9392}, +{0x21ce, 0x7110}, +{0x21d0, 0x2402}, +{0x21d2, 0x4030}, +{0x21d4, 0xF494}, +{0x21d6, 0x9392}, +{0x21d8, 0x7110}, +{0x21da, 0x20A4}, +{0x21dc, 0x0B00}, +{0x21de, 0x7302}, +{0x21e0, 0x0032}, +{0x21e2, 0x4382}, +{0x21e4, 0x7004}, +{0x21e6, 0x0B00}, +{0x21e8, 0x7302}, +{0x21ea, 0x03E8}, +{0x21ec, 0x0800}, +{0x21ee, 0x7114}, +{0x21f0, 0x425F}, +{0x21f2, 0x0C9C}, +{0x21f4, 0x4F4E}, +{0x21f6, 0x430F}, +{0x21f8, 0x4E0D}, +{0x21fa, 0x430C}, +{0x21fc, 0x421F}, +{0x21fe, 0x0C9A}, +{0x2200, 0xDF0C}, +{0x2202, 0x1204}, +{0x2204, 0x440F}, +{0x2206, 0x532F}, +{0x2208, 0x120F}, +{0x220a, 0x1212}, +{0x220c, 0x0CA2}, +{0x220e, 0x403E}, +{0x2210, 0x80C0}, +{0x2212, 0x403F}, +{0x2214, 0x8072}, +{0x2216, 0x12B0}, +{0x2218, 0xF7BA}, +{0x221a, 0x4F07}, +{0x221c, 0x425F}, +{0x221e, 0x0CA0}, +{0x2220, 0x4F4E}, +{0x2222, 0x430F}, +{0x2224, 0x4E0D}, +{0x2226, 0x430C}, +{0x2228, 0x421F}, +{0x222a, 0x0C9E}, +{0x222c, 0xDF0C}, +{0x222e, 0x440F}, +{0x2230, 0x522F}, +{0x2232, 0x120F}, +{0x2234, 0x532F}, +{0x2236, 0x120F}, +{0x2238, 0x1212}, +{0x223a, 0x0CA4}, +{0x223c, 0x403E}, +{0x223e, 0x80A4}, +{0x2240, 0x403F}, +{0x2242, 0x8050}, +{0x2244, 0x12B0}, +{0x2246, 0xF7BA}, +{0x2248, 0x4F08}, +{0x224a, 0x430D}, +{0x224c, 0x441E}, +{0x224e, 0x0004}, +{0x2250, 0x442F}, +{0x2252, 0x5031}, +{0x2254, 0x000C}, +{0x2256, 0x9E0F}, +{0x2258, 0x2C01}, +{0x225a, 0x431D}, +{0x225c, 0x8E0F}, +{0x225e, 0x930F}, +{0x2260, 0x3402}, +{0x2262, 0xE33F}, +{0x2264, 0x531F}, +{0x2266, 0x421E}, +{0x2268, 0x0CA2}, +{0x226a, 0xC312}, +{0x226c, 0x100E}, +{0x226e, 0x9E0F}, +{0x2270, 0x2804}, +{0x2272, 0x930D}, +{0x2274, 0x2001}, +{0x2276, 0x5317}, +{0x2278, 0x5D08}, +{0x227a, 0x403B}, +{0x227c, 0x0196}, +{0x227e, 0x403D}, +{0x2280, 0x0040}, +{0x2282, 0x4D0F}, +{0x2284, 0x8B2F}, +{0x2286, 0x470A}, +{0x2288, 0x4F0C}, +{0x228a, 0x12B0}, +{0x228c, 0xFE58}, +{0x228e, 0x4E09}, +{0x2290, 0xC312}, +{0x2292, 0x1009}, +{0x2294, 0x1109}, +{0x2296, 0x1109}, +{0x2298, 0x1109}, +{0x229a, 0x1109}, +{0x229c, 0x1109}, +{0x229e, 0x4D0F}, +{0x22a0, 0x8B2F}, +{0x22a2, 0x480A}, +{0x22a4, 0x4F0C}, +{0x22a6, 0x12B0}, +{0x22a8, 0xFE58}, +{0x22aa, 0x4E0F}, +{0x22ac, 0xC312}, +{0x22ae, 0x100F}, +{0x22b0, 0x110F}, +{0x22b2, 0x110F}, +{0x22b4, 0x110F}, +{0x22b6, 0x110F}, +{0x22b8, 0x110F}, +{0x22ba, 0x5F09}, +{0x22bc, 0xC312}, +{0x22be, 0x1009}, +{0x22c0, 0x92B2}, +{0x22c2, 0x80BE}, +{0x22c4, 0x280C}, +{0x22c6, 0x90B2}, +{0x22c8, 0x0096}, +{0x22ca, 0x80B6}, +{0x22cc, 0x2408}, +{0x22ce, 0x0900}, +{0x22d0, 0x710E}, +{0x22d2, 0x0B00}, +{0x22d4, 0x7302}, +{0x22d6, 0x0320}, +{0x22d8, 0x12B0}, +{0x22da, 0xF6F2}, +{0x22dc, 0x3F74}, +{0x22de, 0x470A}, +{0x22e0, 0x580A}, +{0x22e2, 0xC312}, +{0x22e4, 0x100A}, +{0x22e6, 0x890A}, +{0x22e8, 0xB3E2}, +{0x22ea, 0x0C81}, +{0x22ec, 0x2418}, +{0x22ee, 0x425F}, +{0x22f0, 0x0C92}, +{0x22f2, 0xF37F}, +{0x22f4, 0x9F0A}, +{0x22f6, 0x280E}, +{0x22f8, 0x425F}, +{0x22fa, 0x0C92}, +{0x22fc, 0xF37F}, +{0x22fe, 0x4A0E}, +{0x2300, 0x8F0E}, +{0x2302, 0x4E82}, +{0x2304, 0x0CAC}, +{0x2306, 0x425F}, +{0x2308, 0x0C92}, +{0x230a, 0xF37F}, +{0x230c, 0x8F0A}, +{0x230e, 0x4A82}, +{0x2310, 0x0CAE}, +{0x2312, 0x3FDD}, +{0x2314, 0x4382}, +{0x2316, 0x0CAC}, +{0x2318, 0x4382}, +{0x231a, 0x0CAE}, +{0x231c, 0x3FD8}, +{0x231e, 0x4A82}, +{0x2320, 0x0CAC}, +{0x2322, 0x3FF5}, +{0x2324, 0x0B00}, +{0x2326, 0x7302}, +{0x2328, 0x0002}, +{0x232a, 0x069A}, +{0x232c, 0x0C1F}, +{0x232e, 0x0403}, +{0x2330, 0x0C05}, +{0x2332, 0x0001}, +{0x2334, 0x0C01}, +{0x2336, 0x0003}, +{0x2338, 0x0C03}, +{0x233a, 0x000B}, +{0x233c, 0x0C33}, +{0x233e, 0x0003}, +{0x2340, 0x0C03}, +{0x2342, 0x0653}, +{0x2344, 0x0C03}, +{0x2346, 0x065B}, +{0x2348, 0x0C13}, +{0x234a, 0x065F}, +{0x234c, 0x0C43}, +{0x234e, 0x0657}, +{0x2350, 0x0C03}, +{0x2352, 0x0653}, +{0x2354, 0x0C03}, +{0x2356, 0x0643}, +{0x2358, 0x0C0F}, +{0x235a, 0x067D}, +{0x235c, 0x0C01}, +{0x235e, 0x077F}, +{0x2360, 0x0C01}, +{0x2362, 0x0677}, +{0x2364, 0x0C01}, +{0x2366, 0x0673}, +{0x2368, 0x0C67}, +{0x236a, 0x0677}, +{0x236c, 0x0C03}, +{0x236e, 0x077D}, +{0x2370, 0x0C19}, +{0x2372, 0x0013}, +{0x2374, 0x0C27}, +{0x2376, 0x0003}, +{0x2378, 0x0C45}, +{0x237a, 0x0675}, +{0x237c, 0x0C01}, +{0x237e, 0x0671}, +{0x2380, 0x4392}, +{0x2382, 0x7004}, +{0x2384, 0x430F}, +{0x2386, 0x9382}, +{0x2388, 0x80BC}, +{0x238a, 0x2001}, +{0x238c, 0x431F}, +{0x238e, 0x4F82}, +{0x2390, 0x80BC}, +{0x2392, 0x930F}, +{0x2394, 0x2473}, +{0x2396, 0x0B00}, +{0x2398, 0x7302}, +{0x239a, 0x033A}, +{0x239c, 0x0675}, +{0x239e, 0x0C02}, +{0x23a0, 0x0339}, +{0x23a2, 0xAE0C}, +{0x23a4, 0x0C01}, +{0x23a6, 0x003C}, +{0x23a8, 0x0C01}, +{0x23aa, 0x0004}, +{0x23ac, 0x0C01}, +{0x23ae, 0x0642}, +{0x23b0, 0x0B00}, +{0x23b2, 0x7302}, +{0x23b4, 0x0386}, +{0x23b6, 0x0643}, +{0x23b8, 0x0C05}, +{0x23ba, 0x0001}, +{0x23bc, 0x0C01}, +{0x23be, 0x0003}, +{0x23c0, 0x0C03}, +{0x23c2, 0x000B}, +{0x23c4, 0x0C33}, +{0x23c6, 0x0003}, +{0x23c8, 0x0C03}, +{0x23ca, 0x0653}, +{0x23cc, 0x0C03}, +{0x23ce, 0x065B}, +{0x23d0, 0x0C13}, +{0x23d2, 0x065F}, +{0x23d4, 0x0C43}, +{0x23d6, 0x0657}, +{0x23d8, 0x0C03}, +{0x23da, 0x0653}, +{0x23dc, 0x0C03}, +{0x23de, 0x0643}, +{0x23e0, 0x0C0F}, +{0x23e2, 0x067D}, +{0x23e4, 0x0C01}, +{0x23e6, 0x077F}, +{0x23e8, 0x0C01}, +{0x23ea, 0x0677}, +{0x23ec, 0x0C01}, +{0x23ee, 0x0673}, +{0x23f0, 0x0C67}, +{0x23f2, 0x0677}, +{0x23f4, 0x0C03}, +{0x23f6, 0x077D}, +{0x23f8, 0x0C19}, +{0x23fa, 0x0013}, +{0x23fc, 0x0C27}, +{0x23fe, 0x0003}, +{0x2400, 0x0C45}, +{0x2402, 0x0675}, +{0x2404, 0x0C01}, +{0x2406, 0x0671}, +{0x2408, 0x12B0}, +{0x240a, 0xF6F2}, +{0x240c, 0x930F}, +{0x240e, 0x2405}, +{0x2410, 0x4292}, +{0x2412, 0x8096}, +{0x2414, 0x809E}, +{0x2416, 0x4382}, +{0x2418, 0x8096}, +{0x241a, 0x9382}, +{0x241c, 0x80BC}, +{0x241e, 0x241E}, +{0x2420, 0x0B00}, +{0x2422, 0x7302}, +{0x2424, 0x069E}, +{0x2426, 0x0675}, +{0x2428, 0x0C02}, +{0x242a, 0x0339}, +{0x242c, 0xAE0C}, +{0x242e, 0x0C01}, +{0x2430, 0x003C}, +{0x2432, 0x0C01}, +{0x2434, 0x0004}, +{0x2436, 0x0C01}, +{0x2438, 0x0642}, +{0x243a, 0x0C01}, +{0x243c, 0x06A1}, +{0x243e, 0x0C03}, +{0x2440, 0x06A0}, +{0x2442, 0x9382}, +{0x2444, 0x80D0}, +{0x2446, 0x2004}, +{0x2448, 0x930F}, +{0x244a, 0x26BD}, +{0x244c, 0x4030}, +{0x244e, 0xF18C}, +{0x2450, 0x43C2}, +{0x2452, 0x0A80}, +{0x2454, 0x0B00}, +{0x2456, 0x7302}, +{0x2458, 0xFFF0}, +{0x245a, 0x3EB5}, +{0x245c, 0x0B00}, +{0x245e, 0x7302}, +{0x2460, 0x069E}, +{0x2462, 0x0675}, +{0x2464, 0x0C02}, +{0x2466, 0x0301}, +{0x2468, 0xAE0C}, +{0x246a, 0x0C01}, +{0x246c, 0x0004}, +{0x246e, 0x0C03}, +{0x2470, 0x0642}, +{0x2472, 0x0C01}, +{0x2474, 0x06A1}, +{0x2476, 0x0C03}, +{0x2478, 0x06A0}, +{0x247a, 0x3FE3}, +{0x247c, 0x0B00}, +{0x247e, 0x7302}, +{0x2480, 0x033A}, +{0x2482, 0x0675}, +{0x2484, 0x0C02}, +{0x2486, 0x0301}, +{0x2488, 0xAE0C}, +{0x248a, 0x0C01}, +{0x248c, 0x0004}, +{0x248e, 0x0C03}, +{0x2490, 0x0642}, +{0x2492, 0x3F8E}, +{0x2494, 0x0B00}, +{0x2496, 0x7302}, +{0x2498, 0x0002}, +{0x249a, 0x069A}, +{0x249c, 0x0C1F}, +{0x249e, 0x0402}, +{0x24a0, 0x0C05}, +{0x24a2, 0x0001}, +{0x24a4, 0x0C01}, +{0x24a6, 0x0003}, +{0x24a8, 0x0C03}, +{0x24aa, 0x000B}, +{0x24ac, 0x0C33}, +{0x24ae, 0x0003}, +{0x24b0, 0x0C03}, +{0x24b2, 0x0653}, +{0x24b4, 0x0C03}, +{0x24b6, 0x065B}, +{0x24b8, 0x0C13}, +{0x24ba, 0x065F}, +{0x24bc, 0x0C43}, +{0x24be, 0x0657}, +{0x24c0, 0x0C03}, +{0x24c2, 0x0653}, +{0x24c4, 0x0C03}, +{0x24c6, 0x0643}, +{0x24c8, 0x0C0F}, +{0x24ca, 0x077D}, +{0x24cc, 0x0C01}, +{0x24ce, 0x067F}, +{0x24d0, 0x0C01}, +{0x24d2, 0x0677}, +{0x24d4, 0x0C01}, +{0x24d6, 0x0673}, +{0x24d8, 0x0C5F}, +{0x24da, 0x0663}, +{0x24dc, 0x0C6F}, +{0x24de, 0x0667}, +{0x24e0, 0x0C01}, +{0x24e2, 0x0677}, +{0x24e4, 0x0C01}, +{0x24e6, 0x077D}, +{0x24e8, 0x0C33}, +{0x24ea, 0x0013}, +{0x24ec, 0x0C27}, +{0x24ee, 0x0003}, +{0x24f0, 0x0C4F}, +{0x24f2, 0x0675}, +{0x24f4, 0x0C01}, +{0x24f6, 0x0671}, +{0x24f8, 0x0CFF}, +{0x24fa, 0x0C78}, +{0x24fc, 0x0661}, +{0x24fe, 0x4392}, +{0x2500, 0x7004}, +{0x2502, 0x430F}, +{0x2504, 0x9382}, +{0x2506, 0x80BC}, +{0x2508, 0x2001}, +{0x250a, 0x431F}, +{0x250c, 0x4F82}, +{0x250e, 0x80BC}, +{0x2510, 0x12B0}, +{0x2512, 0xF6F2}, +{0x2514, 0x930F}, +{0x2516, 0x2405}, +{0x2518, 0x4292}, +{0x251a, 0x8096}, +{0x251c, 0x809E}, +{0x251e, 0x4382}, +{0x2520, 0x8096}, +{0x2522, 0x9382}, +{0x2524, 0x80BC}, +{0x2526, 0x2019}, +{0x2528, 0x0B00}, +{0x252a, 0x7302}, +{0x252c, 0x0562}, +{0x252e, 0x0665}, +{0x2530, 0x0C02}, +{0x2532, 0x0301}, +{0x2534, 0xA60C}, +{0x2536, 0x0204}, +{0x2538, 0xAE0C}, +{0x253a, 0x0C03}, +{0x253c, 0x0642}, +{0x253e, 0x0C13}, +{0x2540, 0x06A1}, +{0x2542, 0x0C03}, +{0x2544, 0x06A0}, +{0x2546, 0x9382}, +{0x2548, 0x80D0}, +{0x254a, 0x277E}, +{0x254c, 0x43C2}, +{0x254e, 0x0A80}, +{0x2550, 0x0B00}, +{0x2552, 0x7302}, +{0x2554, 0xFFF0}, +{0x2556, 0x4030}, +{0x2558, 0xF1C6}, +{0x255a, 0x0B00}, +{0x255c, 0x7302}, +{0x255e, 0x0562}, +{0x2560, 0x0665}, +{0x2562, 0x0C02}, +{0x2564, 0x0339}, +{0x2566, 0xA60C}, +{0x2568, 0x023C}, +{0x256a, 0xAE0C}, +{0x256c, 0x0C01}, +{0x256e, 0x0004}, +{0x2570, 0x0C01}, +{0x2572, 0x0642}, +{0x2574, 0x0C13}, +{0x2576, 0x06A1}, +{0x2578, 0x0C03}, +{0x257a, 0x06A0}, +{0x257c, 0x9382}, +{0x257e, 0x80D0}, +{0x2580, 0x2763}, +{0x2582, 0x43C2}, +{0x2584, 0x0A80}, +{0x2586, 0x0B00}, +{0x2588, 0x7302}, +{0x258a, 0xFFF0}, +{0x258c, 0x4030}, +{0x258e, 0xF1C6}, +{0x2590, 0xB3E2}, +{0x2592, 0x00B4}, +{0x2594, 0x2002}, +{0x2596, 0x4030}, +{0x2598, 0xF16A}, +{0x259a, 0x4316}, +{0x259c, 0x4030}, +{0x259e, 0xF16A}, +{0x25a0, 0x4392}, +{0x25a2, 0x760E}, +{0x25a4, 0x425F}, +{0x25a6, 0x0118}, +{0x25a8, 0xF37F}, +{0x25aa, 0x930F}, +{0x25ac, 0x2005}, +{0x25ae, 0x43C2}, +{0x25b0, 0x0A80}, +{0x25b2, 0x0B00}, +{0x25b4, 0x7302}, +{0x25b6, 0xFFF0}, +{0x25b8, 0x9382}, +{0x25ba, 0x760C}, +{0x25bc, 0x2002}, +{0x25be, 0x0C64}, +{0x25c0, 0x3FF1}, +{0x25c2, 0x4F82}, +{0x25c4, 0x809A}, +{0x25c6, 0x421F}, +{0x25c8, 0x760A}, +{0x25ca, 0x932F}, +{0x25cc, 0x2013}, +{0x25ce, 0x4292}, +{0x25d0, 0x018A}, +{0x25d2, 0x80B8}, +{0x25d4, 0x12B0}, +{0x25d6, 0xFE26}, +{0x25d8, 0x40B2}, +{0x25da, 0x0005}, +{0x25dc, 0x7600}, +{0x25de, 0x4382}, +{0x25e0, 0x7602}, +{0x25e2, 0x0262}, +{0x25e4, 0x0000}, +{0x25e6, 0x0222}, +{0x25e8, 0x0000}, +{0x25ea, 0x0262}, +{0x25ec, 0x0000}, +{0x25ee, 0x0260}, +{0x25f0, 0x0000}, +{0x25f2, 0x3FD6}, +{0x25f4, 0x903F}, +{0x25f6, 0x0003}, +{0x25f8, 0x285B}, +{0x25fa, 0x903F}, +{0x25fc, 0x0102}, +{0x25fe, 0x204E}, +{0x2600, 0x425F}, +{0x2602, 0x0186}, +{0x2604, 0x4F4C}, +{0x2606, 0x93D2}, +{0x2608, 0x018F}, +{0x260a, 0x2446}, +{0x260c, 0x425F}, +{0x260e, 0x018F}, +{0x2610, 0x4F4D}, +{0x2612, 0x4308}, +{0x2614, 0x421B}, +{0x2616, 0x80B8}, +{0x2618, 0x431F}, +{0x261a, 0x480E}, +{0x261c, 0x930E}, +{0x261e, 0x2403}, +{0x2620, 0x5F0F}, +{0x2622, 0x831E}, +{0x2624, 0x23FD}, +{0x2626, 0xFC0F}, +{0x2628, 0x242F}, +{0x262a, 0x430F}, +{0x262c, 0x9D0F}, +{0x262e, 0x2C2C}, +{0x2630, 0x4B0E}, +{0x2632, 0x4E82}, +{0x2634, 0x7600}, +{0x2636, 0x4882}, +{0x2638, 0x7602}, +{0x263a, 0x4C82}, +{0x263c, 0x7604}, +{0x263e, 0x0264}, +{0x2640, 0x0000}, +{0x2642, 0x0224}, +{0x2644, 0x0000}, +{0x2646, 0x0264}, +{0x2648, 0x0000}, +{0x264a, 0x0260}, +{0x264c, 0x0000}, +{0x264e, 0x0268}, +{0x2650, 0x0000}, +{0x2652, 0x0C18}, +{0x2654, 0x02E8}, +{0x2656, 0x0000}, +{0x2658, 0x0C30}, +{0x265a, 0x02A8}, +{0x265c, 0x0000}, +{0x265e, 0x0C30}, +{0x2660, 0x0C30}, +{0x2662, 0x0C30}, +{0x2664, 0x0C30}, +{0x2666, 0x0C30}, +{0x2668, 0x0C30}, +{0x266a, 0x0C30}, +{0x266c, 0x0C30}, +{0x266e, 0x0C00}, +{0x2670, 0x02E8}, +{0x2672, 0x0000}, +{0x2674, 0x0C30}, +{0x2676, 0x0268}, +{0x2678, 0x0000}, +{0x267a, 0x0C18}, +{0x267c, 0x0260}, +{0x267e, 0x0000}, +{0x2680, 0x0C18}, +{0x2682, 0x531F}, +{0x2684, 0x9D0F}, +{0x2686, 0x2BD5}, +{0x2688, 0x5318}, +{0x268a, 0x9238}, +{0x268c, 0x2BC5}, +{0x268e, 0x0260}, +{0x2690, 0x0000}, +{0x2692, 0x5392}, +{0x2694, 0x80B8}, +{0x2696, 0x3F84}, +{0x2698, 0x432D}, +{0x269a, 0x3FBB}, +{0x269c, 0x903F}, +{0x269e, 0x0201}, +{0x26a0, 0x237F}, +{0x26a2, 0x5392}, +{0x26a4, 0x80B8}, +{0x26a6, 0x421F}, +{0x26a8, 0x80B8}, +{0x26aa, 0x12B0}, +{0x26ac, 0xFE38}, +{0x26ae, 0x3F78}, +{0x26b0, 0x931F}, +{0x26b2, 0x2376}, +{0x26b4, 0x12B0}, +{0x26b6, 0xFE26}, +{0x26b8, 0x4292}, +{0x26ba, 0x018A}, +{0x26bc, 0x80B8}, +{0x26be, 0x3FF3}, +{0x26c0, 0x4382}, +{0x26c2, 0x0B88}, +{0x26c4, 0x0C0A}, +{0x26c6, 0x4382}, +{0x26c8, 0x0B8A}, +{0x26ca, 0x0C0A}, +{0x26cc, 0x40B2}, +{0x26ce, 0x000C}, +{0x26d0, 0x0B8C}, +{0x26d2, 0x0C0A}, +{0x26d4, 0x40B2}, +{0x26d6, 0xB5E1}, +{0x26d8, 0x0B8E}, +{0x26da, 0x0C0A}, +{0x26dc, 0x40B2}, +{0x26de, 0x641C}, +{0x26e0, 0x0B92}, +{0x26e2, 0x0C0A}, +{0x26e4, 0x43C2}, +{0x26e6, 0x003D}, +{0x26e8, 0x4030}, +{0x26ea, 0xF02C}, +{0x26ec, 0x5231}, +{0x26ee, 0x4030}, +{0x26f0, 0xFE54}, +{0x26f2, 0xE3B2}, +{0x26f4, 0x740E}, +{0x26f6, 0x425F}, +{0x26f8, 0x0118}, +{0x26fa, 0xF37F}, +{0x26fc, 0x4F82}, +{0x26fe, 0x809A}, +{0x2700, 0x930F}, +{0x2702, 0x2005}, +{0x2704, 0x93C2}, +{0x2706, 0x0A82}, +{0x2708, 0x2402}, +{0x270a, 0x4392}, +{0x270c, 0x80D0}, +{0x270e, 0x9382}, +{0x2710, 0x809A}, +{0x2712, 0x2002}, +{0x2714, 0x4392}, +{0x2716, 0x8070}, +{0x2718, 0x421F}, +{0x271a, 0x710E}, +{0x271c, 0x93A2}, +{0x271e, 0x7110}, +{0x2720, 0x2411}, +{0x2722, 0x9382}, +{0x2724, 0x710E}, +{0x2726, 0x240C}, +{0x2728, 0x5292}, +{0x272a, 0x80A0}, +{0x272c, 0x7110}, +{0x272e, 0x4382}, +{0x2730, 0x740E}, +{0x2732, 0x9382}, +{0x2734, 0x80BA}, +{0x2736, 0x2402}, +{0x2738, 0x4392}, +{0x273a, 0x740E}, +{0x273c, 0x4392}, +{0x273e, 0x80BC}, +{0x2740, 0x430F}, +{0x2742, 0x4130}, +{0x2744, 0xF31F}, +{0x2746, 0x27ED}, +{0x2748, 0x40B2}, +{0x274a, 0x0003}, +{0x274c, 0x7110}, +{0x274e, 0x431F}, +{0x2750, 0x4130}, +{0x2752, 0x4F0E}, +{0x2754, 0x421D}, +{0x2756, 0x8070}, +{0x2758, 0x425F}, +{0x275a, 0x0118}, +{0x275c, 0xF37F}, +{0x275e, 0x903E}, +{0x2760, 0x0003}, +{0x2762, 0x2405}, +{0x2764, 0x931E}, +{0x2766, 0x2403}, +{0x2768, 0x0B00}, +{0x276a, 0x7302}, +{0x276c, 0x0384}, +{0x276e, 0x930F}, +{0x2770, 0x241A}, +{0x2772, 0x930D}, +{0x2774, 0x2018}, +{0x2776, 0x9382}, +{0x2778, 0x7308}, +{0x277a, 0x2402}, +{0x277c, 0x930E}, +{0x277e, 0x2419}, +{0x2780, 0x9382}, +{0x2782, 0x7328}, +{0x2784, 0x2402}, +{0x2786, 0x931E}, +{0x2788, 0x2414}, +{0x278a, 0x9382}, +{0x278c, 0x710E}, +{0x278e, 0x2402}, +{0x2790, 0x932E}, +{0x2792, 0x240F}, +{0x2794, 0x9382}, +{0x2796, 0x7114}, +{0x2798, 0x2402}, +{0x279a, 0x922E}, +{0x279c, 0x240A}, +{0x279e, 0x903E}, +{0x27a0, 0x0003}, +{0x27a2, 0x23DA}, +{0x27a4, 0x3C06}, +{0x27a6, 0x43C2}, +{0x27a8, 0x0A80}, +{0x27aa, 0x0B00}, +{0x27ac, 0x7302}, +{0x27ae, 0xFFF0}, +{0x27b0, 0x3FD3}, +{0x27b2, 0x4F82}, +{0x27b4, 0x809A}, +{0x27b6, 0x431F}, +{0x27b8, 0x4130}, +{0x27ba, 0x120B}, +{0x27bc, 0x120A}, +{0x27be, 0x1209}, +{0x27c0, 0x1208}, +{0x27c2, 0x1207}, +{0x27c4, 0x1206}, +{0x27c6, 0x1205}, +{0x27c8, 0x1204}, +{0x27ca, 0x8221}, +{0x27cc, 0x403B}, +{0x27ce, 0x0016}, +{0x27d0, 0x510B}, +{0x27d2, 0x4F08}, +{0x27d4, 0x4E09}, +{0x27d6, 0x4BA1}, +{0x27d8, 0x0000}, +{0x27da, 0x4B1A}, +{0x27dc, 0x0002}, +{0x27de, 0x4B91}, +{0x27e0, 0x0004}, +{0x27e2, 0x0002}, +{0x27e4, 0x4304}, +{0x27e6, 0x4305}, +{0x27e8, 0x4306}, +{0x27ea, 0x4307}, +{0x27ec, 0x9382}, +{0x27ee, 0x80B4}, +{0x27f0, 0x2425}, +{0x27f2, 0x438A}, +{0x27f4, 0x0000}, +{0x27f6, 0x430B}, +{0x27f8, 0x4B0F}, +{0x27fa, 0x5F0F}, +{0x27fc, 0x5F0F}, +{0x27fe, 0x580F}, +{0x2800, 0x4C8F}, +{0x2802, 0x0000}, +{0x2804, 0x4D8F}, +{0x2806, 0x0002}, +{0x2808, 0x4B0F}, +{0x280a, 0x5F0F}, +{0x280c, 0x590F}, +{0x280e, 0x41AF}, +{0x2810, 0x0000}, +{0x2812, 0x531B}, +{0x2814, 0x923B}, +{0x2816, 0x2BF0}, +{0x2818, 0x430B}, +{0x281a, 0x4B0F}, +{0x281c, 0x5F0F}, +{0x281e, 0x5F0F}, +{0x2820, 0x580F}, +{0x2822, 0x5F34}, +{0x2824, 0x6F35}, +{0x2826, 0x4B0F}, +{0x2828, 0x5F0F}, +{0x282a, 0x590F}, +{0x282c, 0x4F2E}, +{0x282e, 0x430F}, +{0x2830, 0x5E06}, +{0x2832, 0x6F07}, +{0x2834, 0x531B}, +{0x2836, 0x923B}, +{0x2838, 0x2BF0}, +{0x283a, 0x3C18}, +{0x283c, 0x4A2E}, +{0x283e, 0x4E0F}, +{0x2840, 0x5F0F}, +{0x2842, 0x5F0F}, +{0x2844, 0x580F}, +{0x2846, 0x4C8F}, +{0x2848, 0x0000}, +{0x284a, 0x4D8F}, +{0x284c, 0x0002}, +{0x284e, 0x5E0E}, +{0x2850, 0x590E}, +{0x2852, 0x41AE}, +{0x2854, 0x0000}, +{0x2856, 0x4A2F}, +{0x2858, 0x903F}, +{0x285a, 0x0007}, +{0x285c, 0x2404}, +{0x285e, 0x531F}, +{0x2860, 0x4F8A}, +{0x2862, 0x0000}, +{0x2864, 0x3FD9}, +{0x2866, 0x438A}, +{0x2868, 0x0000}, +{0x286a, 0x3FD6}, +{0x286c, 0x440C}, +{0x286e, 0x450D}, +{0x2870, 0x460A}, +{0x2872, 0x470B}, +{0x2874, 0x12B0}, +{0x2876, 0xFEAA}, +{0x2878, 0x4C08}, +{0x287a, 0x4D09}, +{0x287c, 0x4C0E}, +{0x287e, 0x430F}, +{0x2880, 0x4E0A}, +{0x2882, 0x4F0B}, +{0x2884, 0x460C}, +{0x2886, 0x470D}, +{0x2888, 0x12B0}, +{0x288a, 0xFE6E}, +{0x288c, 0x8E04}, +{0x288e, 0x7F05}, +{0x2890, 0x440E}, +{0x2892, 0x450F}, +{0x2894, 0xC312}, +{0x2896, 0x100F}, +{0x2898, 0x100E}, +{0x289a, 0x110F}, +{0x289c, 0x100E}, +{0x289e, 0x110F}, +{0x28a0, 0x100E}, +{0x28a2, 0x411D}, +{0x28a4, 0x0002}, +{0x28a6, 0x4E8D}, +{0x28a8, 0x0000}, +{0x28aa, 0x480F}, +{0x28ac, 0x5221}, +{0x28ae, 0x4134}, +{0x28b0, 0x4135}, +{0x28b2, 0x4136}, +{0x28b4, 0x4137}, +{0x28b6, 0x4138}, +{0x28b8, 0x4139}, +{0x28ba, 0x413A}, +{0x28bc, 0x413B}, +{0x28be, 0x4130}, +{0x28c0, 0x120A}, +{0x28c2, 0x4F0D}, +{0x28c4, 0x4E0C}, +{0x28c6, 0x425F}, +{0x28c8, 0x00BA}, +{0x28ca, 0x4F4A}, +{0x28cc, 0x503A}, +{0x28ce, 0x0010}, +{0x28d0, 0x931D}, +{0x28d2, 0x242B}, +{0x28d4, 0x932D}, +{0x28d6, 0x2421}, +{0x28d8, 0x903D}, +{0x28da, 0x0003}, +{0x28dc, 0x2418}, +{0x28de, 0x922D}, +{0x28e0, 0x2413}, +{0x28e2, 0x903D}, +{0x28e4, 0x0005}, +{0x28e6, 0x2407}, +{0x28e8, 0x903D}, +{0x28ea, 0x0006}, +{0x28ec, 0x2028}, +{0x28ee, 0xC312}, +{0x28f0, 0x100A}, +{0x28f2, 0x110A}, +{0x28f4, 0x3C24}, +{0x28f6, 0x4A0E}, +{0x28f8, 0xC312}, +{0x28fa, 0x100E}, +{0x28fc, 0x110E}, +{0x28fe, 0x4E0F}, +{0x2900, 0x110F}, +{0x2902, 0x4E0A}, +{0x2904, 0x5F0A}, +{0x2906, 0x3C1B}, +{0x2908, 0xC312}, +{0x290a, 0x100A}, +{0x290c, 0x3C18}, +{0x290e, 0x4A0E}, +{0x2910, 0xC312}, +{0x2912, 0x100E}, +{0x2914, 0x4E0F}, +{0x2916, 0x110F}, +{0x2918, 0x3FF3}, +{0x291a, 0x4A0F}, +{0x291c, 0xC312}, +{0x291e, 0x100F}, +{0x2920, 0x4F0E}, +{0x2922, 0x110E}, +{0x2924, 0x4F0A}, +{0x2926, 0x5E0A}, +{0x2928, 0x3C0A}, +{0x292a, 0x4A0F}, +{0x292c, 0xC312}, +{0x292e, 0x100F}, +{0x2930, 0x4F0E}, +{0x2932, 0x110E}, +{0x2934, 0x4F0A}, +{0x2936, 0x5E0A}, +{0x2938, 0x4E0F}, +{0x293a, 0x110F}, +{0x293c, 0x3FE3}, +{0x293e, 0x12B0}, +{0x2940, 0xFE58}, +{0x2942, 0x4E0F}, +{0x2944, 0xC312}, +{0x2946, 0x100F}, +{0x2948, 0x110F}, +{0x294a, 0x110F}, +{0x294c, 0x110F}, +{0x294e, 0x413A}, +{0x2950, 0x4130}, +{0x2952, 0x120B}, +{0x2954, 0x120A}, +{0x2956, 0x1209}, +{0x2958, 0x1208}, +{0x295a, 0x425F}, +{0x295c, 0x0080}, +{0x295e, 0xF36F}, +{0x2960, 0x4F0E}, +{0x2962, 0xF32E}, +{0x2964, 0x4E82}, +{0x2966, 0x80BA}, +{0x2968, 0xB3D2}, +{0x296a, 0x0786}, +{0x296c, 0x2402}, +{0x296e, 0x4392}, +{0x2970, 0x7002}, +{0x2972, 0x4392}, +{0x2974, 0x80BC}, +{0x2976, 0x4382}, +{0x2978, 0x740E}, +{0x297a, 0x9382}, +{0x297c, 0x80BA}, +{0x297e, 0x2402}, +{0x2980, 0x4392}, +{0x2982, 0x740E}, +{0x2984, 0x93C2}, +{0x2986, 0x00C6}, +{0x2988, 0x2406}, +{0x298a, 0xB392}, +{0x298c, 0x732A}, +{0x298e, 0x2403}, +{0x2990, 0xB3D2}, +{0x2992, 0x00C7}, +{0x2994, 0x2412}, +{0x2996, 0x4292}, +{0x2998, 0x01A8}, +{0x299a, 0x0688}, +{0x299c, 0x4292}, +{0x299e, 0x01AA}, +{0x29a0, 0x068A}, +{0x29a2, 0x4292}, +{0x29a4, 0x01AC}, +{0x29a6, 0x068C}, +{0x29a8, 0x4292}, +{0x29aa, 0x01AE}, +{0x29ac, 0x068E}, +{0x29ae, 0x4292}, +{0x29b0, 0x0190}, +{0x29b2, 0x0A92}, +{0x29b4, 0x4292}, +{0x29b6, 0x0192}, +{0x29b8, 0x0A94}, +{0x29ba, 0x430E}, +{0x29bc, 0x425F}, +{0x29be, 0x00C7}, +{0x29c0, 0xF35F}, +{0x29c2, 0xF37F}, +{0x29c4, 0xF21F}, +{0x29c6, 0x732A}, +{0x29c8, 0x200C}, +{0x29ca, 0xB3D2}, +{0x29cc, 0x00C7}, +{0x29ce, 0x2003}, +{0x29d0, 0xB392}, +{0x29d2, 0x80A2}, +{0x29d4, 0x2006}, +{0x29d6, 0xB3A2}, +{0x29d8, 0x732A}, +{0x29da, 0x2003}, +{0x29dc, 0x9382}, +{0x29de, 0x8096}, +{0x29e0, 0x2401}, +{0x29e2, 0x431E}, +{0x29e4, 0x4E82}, +{0x29e6, 0x80B4}, +{0x29e8, 0x930E}, +{0x29ea, 0x2002}, +{0x29ec, 0x4030}, +{0x29ee, 0xFDE4}, +{0x29f0, 0x4382}, +{0x29f2, 0x80BE}, +{0x29f4, 0x421F}, +{0x29f6, 0x732A}, +{0x29f8, 0xF31F}, +{0x29fa, 0x4F82}, +{0x29fc, 0x80A2}, +{0x29fe, 0x425F}, +{0x2a00, 0x008C}, +{0x2a02, 0x4FC2}, +{0x2a04, 0x8092}, +{0x2a06, 0x43C2}, +{0x2a08, 0x8093}, +{0x2a0a, 0x425F}, +{0x2a0c, 0x009E}, +{0x2a0e, 0x4F48}, +{0x2a10, 0x425F}, +{0x2a12, 0x009F}, +{0x2a14, 0xF37F}, +{0x2a16, 0x5F08}, +{0x2a18, 0x1108}, +{0x2a1a, 0x1108}, +{0x2a1c, 0x425F}, +{0x2a1e, 0x00B2}, +{0x2a20, 0x4F49}, +{0x2a22, 0x425F}, +{0x2a24, 0x00B3}, +{0x2a26, 0xF37F}, +{0x2a28, 0x5F09}, +{0x2a2a, 0x1109}, +{0x2a2c, 0x1109}, +{0x2a2e, 0x425F}, +{0x2a30, 0x00BA}, +{0x2a32, 0x4F4C}, +{0x2a34, 0x407A}, +{0x2a36, 0x001C}, +{0x2a38, 0x12B0}, +{0x2a3a, 0xFE8E}, +{0x2a3c, 0x934C}, +{0x2a3e, 0x25BE}, +{0x2a40, 0x403E}, +{0x2a42, 0x0080}, +{0x2a44, 0x4E0F}, +{0x2a46, 0xF37F}, +{0x2a48, 0x108F}, +{0x2a4a, 0xD03F}, +{0x2a4c, 0x008B}, +{0x2a4e, 0x4F82}, +{0x2a50, 0x0B88}, +{0x2a52, 0x0C0A}, +{0x2a54, 0x403C}, +{0x2a56, 0x0813}, +{0x2a58, 0x403D}, +{0x2a5a, 0x007F}, +{0x2a5c, 0x403F}, +{0x2a5e, 0x00BA}, +{0x2a60, 0x4F6E}, +{0x2a62, 0x90FF}, +{0x2a64, 0x0010}, +{0x2a66, 0x0000}, +{0x2a68, 0x2D13}, +{0x2a6a, 0x403C}, +{0x2a6c, 0x1005}, +{0x2a6e, 0x430D}, +{0x2a70, 0x425E}, +{0x2a72, 0x00BA}, +{0x2a74, 0x4E4F}, +{0x2a76, 0x108F}, +{0x2a78, 0xDD0F}, +{0x2a7a, 0x4F82}, +{0x2a7c, 0x0B90}, +{0x2a7e, 0x0C0A}, +{0x2a80, 0x4C82}, +{0x2a82, 0x0B8A}, +{0x2a84, 0x0C0A}, +{0x2a86, 0x425F}, +{0x2a88, 0x0C87}, +{0x2a8a, 0x4F4E}, +{0x2a8c, 0x425F}, +{0x2a8e, 0x0C88}, +{0x2a90, 0xF37F}, +{0x2a92, 0x12B0}, +{0x2a94, 0xF8C0}, +{0x2a96, 0x4F82}, +{0x2a98, 0x0C8C}, +{0x2a9a, 0x425F}, +{0x2a9c, 0x0C85}, +{0x2a9e, 0x4F4E}, +{0x2aa0, 0x425F}, +{0x2aa2, 0x0C89}, +{0x2aa4, 0xF37F}, +{0x2aa6, 0x12B0}, +{0x2aa8, 0xF8C0}, +{0x2aaa, 0x4F82}, +{0x2aac, 0x0C8A}, +{0x2aae, 0x425E}, +{0x2ab0, 0x00B7}, +{0x2ab2, 0x5E4E}, +{0x2ab4, 0x4EC2}, +{0x2ab6, 0x0CB0}, +{0x2ab8, 0x425F}, +{0x2aba, 0x00B8}, +{0x2abc, 0x5F4F}, +{0x2abe, 0x4FC2}, +{0x2ac0, 0x0CB1}, +{0x2ac2, 0x480E}, +{0x2ac4, 0x5E0E}, +{0x2ac6, 0x5E0E}, +{0x2ac8, 0x5E0E}, +{0x2aca, 0x5E0E}, +{0x2acc, 0x490F}, +{0x2ace, 0x5F0F}, +{0x2ad0, 0x5F0F}, +{0x2ad2, 0x5F0F}, +{0x2ad4, 0x5F0F}, +{0x2ad6, 0x5F0F}, +{0x2ad8, 0x5F0F}, +{0x2ada, 0x5F0F}, +{0x2adc, 0xDF0E}, +{0x2ade, 0x4E82}, +{0x2ae0, 0x0A8E}, +{0x2ae2, 0xB229}, +{0x2ae4, 0x2401}, +{0x2ae6, 0x5339}, +{0x2ae8, 0xB3E2}, +{0x2aea, 0x0080}, +{0x2aec, 0x2403}, +{0x2aee, 0x40F2}, +{0x2af0, 0x0003}, +{0x2af2, 0x00B5}, +{0x2af4, 0x40B2}, +{0x2af6, 0x1000}, +{0x2af8, 0x7500}, +{0x2afa, 0x40B2}, +{0x2afc, 0x1001}, +{0x2afe, 0x7502}, +{0x2b00, 0x40B2}, +{0x2b02, 0x0803}, +{0x2b04, 0x7504}, +{0x2b06, 0x40B2}, +{0x2b08, 0x080F}, +{0x2b0a, 0x7506}, +{0x2b0c, 0x40B2}, +{0x2b0e, 0x6003}, +{0x2b10, 0x7508}, +{0x2b12, 0x40B2}, +{0x2b14, 0x0801}, +{0x2b16, 0x750A}, +{0x2b18, 0x40B2}, +{0x2b1a, 0x0800}, +{0x2b1c, 0x750C}, +{0x2b1e, 0x40B2}, +{0x2b20, 0x1400}, +{0x2b22, 0x750E}, +{0x2b24, 0x403F}, +{0x2b26, 0x0003}, +{0x2b28, 0x12B0}, +{0x2b2a, 0xF752}, +{0x2b2c, 0x421F}, +{0x2b2e, 0x0098}, +{0x2b30, 0x821F}, +{0x2b32, 0x0092}, +{0x2b34, 0x531F}, +{0x2b36, 0xC312}, +{0x2b38, 0x100F}, +{0x2b3a, 0x4F82}, +{0x2b3c, 0x0A86}, +{0x2b3e, 0x421F}, +{0x2b40, 0x00AC}, +{0x2b42, 0x821F}, +{0x2b44, 0x00A6}, +{0x2b46, 0x531F}, +{0x2b48, 0x4F82}, +{0x2b4a, 0x0A88}, +{0x2b4c, 0xB0B2}, +{0x2b4e, 0x0010}, +{0x2b50, 0x0A84}, +{0x2b52, 0x248F}, +{0x2b54, 0x421E}, +{0x2b56, 0x068C}, +{0x2b58, 0xC312}, +{0x2b5a, 0x100E}, +{0x2b5c, 0x4E82}, +{0x2b5e, 0x0782}, +{0x2b60, 0x4292}, +{0x2b62, 0x068E}, +{0x2b64, 0x0784}, +{0x2b66, 0xB3D2}, +{0x2b68, 0x0CB6}, +{0x2b6a, 0x2418}, +{0x2b6c, 0x421A}, +{0x2b6e, 0x0CB8}, +{0x2b70, 0x430B}, +{0x2b72, 0x425F}, +{0x2b74, 0x0CBA}, +{0x2b76, 0x4F4E}, +{0x2b78, 0x430F}, +{0x2b7a, 0x4E0F}, +{0x2b7c, 0x430E}, +{0x2b7e, 0xDE0A}, +{0x2b80, 0xDF0B}, +{0x2b82, 0x421F}, +{0x2b84, 0x0CBC}, +{0x2b86, 0x4F0C}, +{0x2b88, 0x430D}, +{0x2b8a, 0x421F}, +{0x2b8c, 0x0CBE}, +{0x2b8e, 0x430E}, +{0x2b90, 0xDE0C}, +{0x2b92, 0xDF0D}, +{0x2b94, 0x12B0}, +{0x2b96, 0xFEAA}, +{0x2b98, 0x4C82}, +{0x2b9a, 0x0194}, +{0x2b9c, 0xB2A2}, +{0x2b9e, 0x0A84}, +{0x2ba0, 0x2412}, +{0x2ba2, 0x421E}, +{0x2ba4, 0x0A96}, +{0x2ba6, 0xC312}, +{0x2ba8, 0x100E}, +{0x2baa, 0x110E}, +{0x2bac, 0x110E}, +{0x2bae, 0x43C2}, +{0x2bb0, 0x0A98}, +{0x2bb2, 0x431D}, +{0x2bb4, 0x4E0F}, +{0x2bb6, 0x9F82}, +{0x2bb8, 0x0194}, +{0x2bba, 0x2850}, +{0x2bbc, 0x5E0F}, +{0x2bbe, 0x531D}, +{0x2bc0, 0x903D}, +{0x2bc2, 0x0009}, +{0x2bc4, 0x2BF8}, +{0x2bc6, 0x4292}, +{0x2bc8, 0x0084}, +{0x2bca, 0x7524}, +{0x2bcc, 0x4292}, +{0x2bce, 0x0088}, +{0x2bd0, 0x7316}, +{0x2bd2, 0x9382}, +{0x2bd4, 0x8092}, +{0x2bd6, 0x2403}, +{0x2bd8, 0x4292}, +{0x2bda, 0x008A}, +{0x2bdc, 0x7316}, +{0x2bde, 0x430E}, +{0x2be0, 0x421F}, +{0x2be2, 0x0086}, +{0x2be4, 0x822F}, +{0x2be6, 0x9F82}, +{0x2be8, 0x0084}, +{0x2bea, 0x2801}, +{0x2bec, 0x431E}, +{0x2bee, 0x4292}, +{0x2bf0, 0x0086}, +{0x2bf2, 0x7314}, +{0x2bf4, 0x93C2}, +{0x2bf6, 0x00BC}, +{0x2bf8, 0x2007}, +{0x2bfa, 0xB31E}, +{0x2bfc, 0x2405}, +{0x2bfe, 0x421F}, +{0x2c00, 0x0084}, +{0x2c02, 0x522F}, +{0x2c04, 0x4F82}, +{0x2c06, 0x7314}, +{0x2c08, 0x425F}, +{0x2c0a, 0x00BC}, +{0x2c0c, 0xF37F}, +{0x2c0e, 0xFE0F}, +{0x2c10, 0x2406}, +{0x2c12, 0x421E}, +{0x2c14, 0x0086}, +{0x2c16, 0x503E}, +{0x2c18, 0xFFFB}, +{0x2c1a, 0x4E82}, +{0x2c1c, 0x7524}, +{0x2c1e, 0x430E}, +{0x2c20, 0x421F}, +{0x2c22, 0x7524}, +{0x2c24, 0x9F82}, +{0x2c26, 0x809C}, +{0x2c28, 0x2C07}, +{0x2c2a, 0x9382}, +{0x2c2c, 0x8096}, +{0x2c2e, 0x2004}, +{0x2c30, 0x9382}, +{0x2c32, 0x8098}, +{0x2c34, 0x2001}, +{0x2c36, 0x431E}, +{0x2c38, 0x40B2}, +{0x2c3a, 0x0032}, +{0x2c3c, 0x7522}, +{0x2c3e, 0x4292}, +{0x2c40, 0x7524}, +{0x2c42, 0x809C}, +{0x2c44, 0x930E}, +{0x2c46, 0x24E6}, +{0x2c48, 0x421F}, +{0x2c4a, 0x7316}, +{0x2c4c, 0xC312}, +{0x2c4e, 0x100F}, +{0x2c50, 0x832F}, +{0x2c52, 0x4F82}, +{0x2c54, 0x7522}, +{0x2c56, 0x53B2}, +{0x2c58, 0x7524}, +{0x2c5a, 0x3CDC}, +{0x2c5c, 0x431F}, +{0x2c5e, 0x4D0E}, +{0x2c60, 0x533E}, +{0x2c62, 0x930E}, +{0x2c64, 0x2403}, +{0x2c66, 0x5F0F}, +{0x2c68, 0x831E}, +{0x2c6a, 0x23FD}, +{0x2c6c, 0x4FC2}, +{0x2c6e, 0x0A98}, +{0x2c70, 0x3FAA}, +{0x2c72, 0x4292}, +{0x2c74, 0x0A86}, +{0x2c76, 0x0782}, +{0x2c78, 0x421F}, +{0x2c7a, 0x0A88}, +{0x2c7c, 0x490E}, +{0x2c7e, 0x930E}, +{0x2c80, 0x2404}, +{0x2c82, 0xC312}, +{0x2c84, 0x100F}, +{0x2c86, 0x831E}, +{0x2c88, 0x23FC}, +{0x2c8a, 0x4F82}, +{0x2c8c, 0x0784}, +{0x2c8e, 0x3F6B}, +{0x2c90, 0x90F2}, +{0x2c92, 0x0010}, +{0x2c94, 0x00BA}, +{0x2c96, 0x2809}, +{0x2c98, 0x90F2}, +{0x2c9a, 0x0031}, +{0x2c9c, 0x00BA}, +{0x2c9e, 0x2C05}, +{0x2ca0, 0x403C}, +{0x2ca2, 0x0E05}, +{0x2ca4, 0x403D}, +{0x2ca6, 0x003C}, +{0x2ca8, 0x3EE3}, +{0x2caa, 0x90F2}, +{0x2cac, 0x0031}, +{0x2cae, 0x00BA}, +{0x2cb0, 0x280D}, +{0x2cb2, 0x90F2}, +{0x2cb4, 0x0039}, +{0x2cb6, 0x00BA}, +{0x2cb8, 0x2C09}, +{0x2cba, 0x403C}, +{0x2cbc, 0x0E09}, +{0x2cbe, 0x403D}, +{0x2cc0, 0x003C}, +{0x2cc2, 0x425E}, +{0x2cc4, 0x00BA}, +{0x2cc6, 0x507E}, +{0x2cc8, 0x0003}, +{0x2cca, 0x3ED4}, +{0x2ccc, 0x90F2}, +{0x2cce, 0x0039}, +{0x2cd0, 0x00BA}, +{0x2cd2, 0x280D}, +{0x2cd4, 0x90F2}, +{0x2cd6, 0x0041}, +{0x2cd8, 0x00BA}, +{0x2cda, 0x2C09}, +{0x2cdc, 0x403C}, +{0x2cde, 0x0C0B}, +{0x2ce0, 0x403D}, +{0x2ce2, 0x003C}, +{0x2ce4, 0x425E}, +{0x2ce6, 0x00BA}, +{0x2ce8, 0x507E}, +{0x2cea, 0x0005}, +{0x2cec, 0x3EC3}, +{0x2cee, 0x90F2}, +{0x2cf0, 0x0041}, +{0x2cf2, 0x00BA}, +{0x2cf4, 0x280D}, +{0x2cf6, 0x90F2}, +{0x2cf8, 0x0051}, +{0x2cfa, 0x00BA}, +{0x2cfc, 0x2C09}, +{0x2cfe, 0x403C}, +{0x2d00, 0x0A0F}, +{0x2d02, 0x403D}, +{0x2d04, 0x003C}, +{0x2d06, 0x425E}, +{0x2d08, 0x00BA}, +{0x2d0a, 0x507E}, +{0x2d0c, 0x0009}, +{0x2d0e, 0x3EB2}, +{0x2d10, 0x90F2}, +{0x2d12, 0x0051}, +{0x2d14, 0x00BA}, +{0x2d16, 0x280D}, +{0x2d18, 0x90F2}, +{0x2d1a, 0x0061}, +{0x2d1c, 0x00BA}, +{0x2d1e, 0x2C09}, +{0x2d20, 0x403C}, +{0x2d22, 0x0A11}, +{0x2d24, 0x403D}, +{0x2d26, 0x003C}, +{0x2d28, 0x425E}, +{0x2d2a, 0x00BA}, +{0x2d2c, 0x507E}, +{0x2d2e, 0x000B}, +{0x2d30, 0x3EA1}, +{0x2d32, 0x90F2}, +{0x2d34, 0x0061}, +{0x2d36, 0x00BA}, +{0x2d38, 0x2807}, +{0x2d3a, 0x90F2}, +{0x2d3c, 0x0075}, +{0x2d3e, 0x00BA}, +{0x2d40, 0x2C03}, +{0x2d42, 0x403C}, +{0x2d44, 0x0813}, +{0x2d46, 0x3FF0}, +{0x2d48, 0x90F2}, +{0x2d4a, 0x0075}, +{0x2d4c, 0x00BA}, +{0x2d4e, 0x280B}, +{0x2d50, 0x90F2}, +{0x2d52, 0xFF91}, +{0x2d54, 0x00BA}, +{0x2d56, 0x2C07}, +{0x2d58, 0x403C}, +{0x2d5a, 0x0813}, +{0x2d5c, 0x425E}, +{0x2d5e, 0x00BA}, +{0x2d60, 0x507E}, +{0x2d62, 0x000C}, +{0x2d64, 0x3E87}, +{0x2d66, 0x90F2}, +{0x2d68, 0xFF91}, +{0x2d6a, 0x00BA}, +{0x2d6c, 0x280B}, +{0x2d6e, 0x90F2}, +{0x2d70, 0xFFB1}, +{0x2d72, 0x00BA}, +{0x2d74, 0x2C07}, +{0x2d76, 0x403D}, +{0x2d78, 0x0060}, +{0x2d7a, 0x425E}, +{0x2d7c, 0x00BA}, +{0x2d7e, 0x507E}, +{0x2d80, 0x000D}, +{0x2d82, 0x3E78}, +{0x2d84, 0x90F2}, +{0x2d86, 0xFFB1}, +{0x2d88, 0x00BA}, +{0x2d8a, 0x280B}, +{0x2d8c, 0x90F2}, +{0x2d8e, 0xFFD1}, +{0x2d90, 0x00BA}, +{0x2d92, 0x2C07}, +{0x2d94, 0x403D}, +{0x2d96, 0x0050}, +{0x2d98, 0x425E}, +{0x2d9a, 0x00BA}, +{0x2d9c, 0x507E}, +{0x2d9e, 0x000E}, +{0x2da0, 0x3E69}, +{0x2da2, 0x403D}, +{0x2da4, 0x003C}, +{0x2da6, 0x403F}, +{0x2da8, 0x00BA}, +{0x2daa, 0x4F6E}, +{0x2dac, 0x507E}, +{0x2dae, 0x000F}, +{0x2db0, 0x90FF}, +{0x2db2, 0xFFF1}, +{0x2db4, 0x0000}, +{0x2db6, 0x2A5E}, +{0x2db8, 0x437E}, +{0x2dba, 0x3E5C}, +{0x2dbc, 0x425F}, +{0x2dbe, 0x00BA}, +{0x2dc0, 0x4F4C}, +{0x2dc2, 0x407A}, +{0x2dc4, 0x001C}, +{0x2dc6, 0x12B0}, +{0x2dc8, 0xFE8E}, +{0x2dca, 0x4E4F}, +{0x2dcc, 0xC312}, +{0x2dce, 0x104F}, +{0x2dd0, 0x114F}, +{0x2dd2, 0xF37F}, +{0x2dd4, 0x5F0F}, +{0x2dd6, 0x5F0F}, +{0x2dd8, 0x5F0F}, +{0x2dda, 0x5F0F}, +{0x2ddc, 0x403E}, +{0x2dde, 0x00F0}, +{0x2de0, 0x8F0E}, +{0x2de2, 0x3E30}, +{0x2de4, 0x421F}, +{0x2de6, 0x80BE}, +{0x2de8, 0x903F}, +{0x2dea, 0x0009}, +{0x2dec, 0x2C05}, +{0x2dee, 0x531F}, +{0x2df0, 0x4F82}, +{0x2df2, 0x80BE}, +{0x2df4, 0x4030}, +{0x2df6, 0xF9F4}, +{0x2df8, 0x421F}, +{0x2dfa, 0x80B6}, +{0x2dfc, 0x903F}, +{0x2dfe, 0x0098}, +{0x2e00, 0x2C05}, +{0x2e02, 0x531F}, +{0x2e04, 0x4F82}, +{0x2e06, 0x80B6}, +{0x2e08, 0x4030}, +{0x2e0a, 0xF9F4}, +{0x2e0c, 0x4382}, +{0x2e0e, 0x80B6}, +{0x2e10, 0x4030}, +{0x2e12, 0xF9F4}, +{0x2e14, 0x4E82}, +{0x2e16, 0x8098}, +{0x2e18, 0xD392}, +{0x2e1a, 0x7102}, +{0x2e1c, 0x4138}, +{0x2e1e, 0x4139}, +{0x2e20, 0x413A}, +{0x2e22, 0x413B}, +{0x2e24, 0x4130}, +{0x2e26, 0x0260}, +{0x2e28, 0x0000}, +{0x2e2a, 0x0C18}, +{0x2e2c, 0x0240}, +{0x2e2e, 0x0000}, +{0x2e30, 0x0260}, +{0x2e32, 0x0000}, +{0x2e34, 0x0C05}, +{0x2e36, 0x4130}, +{0x2e38, 0x4382}, +{0x2e3a, 0x7602}, +{0x2e3c, 0x4F82}, +{0x2e3e, 0x7600}, +{0x2e40, 0x0270}, +{0x2e42, 0x0000}, +{0x2e44, 0x0C07}, +{0x2e46, 0x0270}, +{0x2e48, 0x0001}, +{0x2e4a, 0x421F}, +{0x2e4c, 0x7606}, +{0x2e4e, 0x4FC2}, +{0x2e50, 0x0188}, +{0x2e52, 0x4130}, +{0x2e54, 0xDF02}, +{0x2e56, 0x3FFE}, +{0x2e58, 0x430E}, +{0x2e5a, 0x930A}, +{0x2e5c, 0x2407}, +{0x2e5e, 0xC312}, +{0x2e60, 0x100C}, +{0x2e62, 0x2801}, +{0x2e64, 0x5A0E}, +{0x2e66, 0x5A0A}, +{0x2e68, 0x930C}, +{0x2e6a, 0x23F7}, +{0x2e6c, 0x4130}, +{0x2e6e, 0x430E}, +{0x2e70, 0x430F}, +{0x2e72, 0x3C08}, +{0x2e74, 0xC312}, +{0x2e76, 0x100D}, +{0x2e78, 0x100C}, +{0x2e7a, 0x2802}, +{0x2e7c, 0x5A0E}, +{0x2e7e, 0x6B0F}, +{0x2e80, 0x5A0A}, +{0x2e82, 0x6B0B}, +{0x2e84, 0x930C}, +{0x2e86, 0x23F6}, +{0x2e88, 0x930D}, +{0x2e8a, 0x23F4}, +{0x2e8c, 0x4130}, +{0x2e8e, 0xEE4E}, +{0x2e90, 0x407B}, +{0x2e92, 0x0009}, +{0x2e94, 0x3C05}, +{0x2e96, 0x100D}, +{0x2e98, 0x6E4E}, +{0x2e9a, 0x9A4E}, +{0x2e9c, 0x2801}, +{0x2e9e, 0x8A4E}, +{0x2ea0, 0x6C4C}, +{0x2ea2, 0x6D0D}, +{0x2ea4, 0x835B}, +{0x2ea6, 0x23F7}, +{0x2ea8, 0x4130}, +{0x2eaa, 0xEF0F}, +{0x2eac, 0xEE0E}, +{0x2eae, 0x4039}, +{0x2eb0, 0x0021}, +{0x2eb2, 0x3C0A}, +{0x2eb4, 0x1008}, +{0x2eb6, 0x6E0E}, +{0x2eb8, 0x6F0F}, +{0x2eba, 0x9B0F}, +{0x2ebc, 0x2805}, +{0x2ebe, 0x2002}, +{0x2ec0, 0x9A0E}, +{0x2ec2, 0x2802}, +{0x2ec4, 0x8A0E}, +{0x2ec6, 0x7B0F}, +{0x2ec8, 0x6C0C}, +{0x2eca, 0x6D0D}, +{0x2ecc, 0x6808}, +{0x2ece, 0x8319}, +{0x2ed0, 0x23F1}, +{0x2ed2, 0x4130}, +{0x2ed4, 0x0000}, +{0x2ffe, 0xf000}, +{0x3000, 0x00AE}, +{0x3002, 0x00AE}, +{0x3004, 0x00AE}, +{0x3006, 0x00AE}, +{0x3008, 0x00AE}, +{0x4000, 0x0400}, +{0x4002, 0x0400}, +{0x4004, 0x0C04}, +{0x4006, 0x0C04}, +{0x4008, 0x0C04}, + +//--- FW End ---// + + +//--- Initial Set file ---// +{0x0B02, 0x0014}, +{0x0B04, 0x07C8}, +{0x0B06, 0x5ED7}, +{0x0B14, 0x430F}, //PLL Main Div[15:8]. Mclk 26.022Mhz / 0x430F = Pclk(87.174Mhz) +{0x0B16, 0x4A0B}, +{0x0B18, 0x0000}, +{0x0B1A, 0x1044}, + +{0x004C, 0x0100}, //tg_enable. +{0x000C, 0x0000}, +{0x0036, 0x0048}, //ramp_rst_offset +{0x0038, 0x4800}, //ramp_sig_poffset +{0x0138, 0x0104}, //pxl_drv_pwr +{0x013A, 0x0100}, //tx_idle +{0x0C00, 0x3BC7}, //BLC_ctl1. Line BLC on = 0x3b, off = 0x2A //LBLC_ctl1. [0]en_blc, [1]en_lblc_dpc, [2]en_channel_blc, [3]en_adj_pxl_dpc, [4]en_adp_dead_pxl_th +{0x0C0E, 0x0500}, //0x07 BLC display On, 0x05 BLC D off //BLC_ctl3. Frame BLC On = 0x05, off=0x04 //FBLC_ctl3. [0]en_fblc, [1]en_blc_bypass, [2]en_fblc_dpc, [5]en_fobp_dig_offset, [7]en_lobp_dpc_bypass +{0x0C10, 0x0510}, //dig_blc_offset_h +{0x0C16, 0x0000}, //fobp_dig_b_offset. red b[7] sign(0:+,1:-), b[6:0] dc offset 128(max) +{0x0C18, 0x0000}, //fobp_dig_Gb_offset. Gr b[7] sign(0:+,1:-), b[6:0] dc offset 128(max) +{0x0C36, 0x0100}, //r_g_sum_ctl. [0]:g_sum_en. '1'enable, '0'disable. + +//--- MIPI blank time --------------// +{0x0902, 0x4101}, //mipi_value_clk_trail. MIPI CLK mode [1]'1'cont(0x43),'0'non-cont(0x41) [6]'1'2lane(0x41), '0'1lane(0x01) +{0x090A, 0x03E4}, //mipi_vblank_delay_h. +{0x090C, 0x0020}, //mipi_hblank_short_delay_h. +{0x090E, 0x0020}, //mipi_hblank_long_delay_h. +{0x0910, 0x5D07}, //05 mipi_LPX +{0x0912, 0x061e}, //05 mipi_CLK_prepare +{0x0914, 0x0407}, //02 mipi_clk_pre +{0x0916, 0x0d0a}, //09 mipi_data_zero +{0x0918, 0x0e09}, //0c mipi_clk_post + +//--- Pixel Array Addressing ------// +{0x000E, 0x0000}, +{0x0014, 0x003F}, +{0x0010, 0x0050}, +{0x0016, 0x008F}, +{0x0012, 0x00AA}, +{0x0018, 0x0ACD}, +{0x0020, 0x0700}, +{0x0022, 0x0004}, +{0x0028, 0x000B}, +{0x0024, 0xFFFA}, +{0x002A, 0xFFFF}, +{0x0026, 0x0016}, +{0x002C, 0x07b1}, +{0x0034, 0x0700}, + +{0x0128, 0x0002}, // digital_crop_x_offset_l +{0x012A, 0x0000}, // digital_crop_y_offset_l +{0x012C, 0x0A20}, //2C}, //2592 digital_crop_image_width +{0x012E, 0x0798}, //A4}, //1944 digital_crop_image_height + +//----< Image FMT Size >--------------------// +//Image size 2592x1944 +{0x0110, 0x0A20}, //X_output_size_h +{0x0112, 0x0798}, //Y_output_size_h + +//----< Frame / Line Length >--------------// +{0x0006, 0x07c0}, //frame_length_h 1984 +{0x0008, 0x0B40}, //line_length_h 2880 +{0x000A, 0x0DB0}, +//---------------------------------------// +//--- ETC set ----// +{0x003C, 0x0000}, //fixed frame off. b[0] '1'enable, '0'disable +{0x0500, 0x0000}, //DGA_ctl. b[1]'0'OTP_color_ratio_disable, '1' OTP_color_ratio_enable, b[2]'0'data_pedestal_en, '1'data_pedestal_dis. +{0x0700, 0x0590}, //Scaler Normal +{0x001E, 0x0101}, +{0x0032, 0x0101}, +{0x0A02, 0x0100}, // Fast sleep Enable +{0x0C12, 0x0100}, // BLC Offset +{0x0116, 0x0024}, // FBLC Ratio +//----------------// + +//--- AG / DG control ----------------// +//AG +{0x003A, 0x0000}, //Analog Gain. 0x00=x1, 0x70=x8, 0xf0=x16. + +//DG +{0x0508, 0x0100}, //DG_Gr_h. 0x01=x1, 0x07=x8. +{0x050a, 0x0100}, //DG_Gb_h. 0x01=x1, 0x07=x8. +{0x050c, 0x0100}, //DG_R_h. 0x01=x1, 0x07=x8. +{0x050e, 0x0100}, //DG_B_h. 0x01=x1, 0x07=x8. +//----------------------------------// + +//-----< Exp.Time >------------------------// +// Pclk_88Mhz @ Line_length_pclk : 2880 @Exp.Time 33.33ms +{0x0002, 0x0539}, //Fine_int : 33.33ms@Pclk88mhz@Line_length2880 +{0x0004, 0x07E0}, //coarse_int : 33.33ms@Pclk88mhz@Line_length2880 + +//--- ISP enable Selection ---------------// +{0x0A04, 0x011A}, //isp_en. [9]s-gamma,[8]MIPI_en,[6]compresion10to8,[5]Scaler,[4]window,[3]DG,[2]LSC,[1]adpc,[0]tpg +//----------------------------------------// + +{0x0118, 0x0100}, //sleep Off +}; + +struct msm_camera_i2c_reg_setting sr544_init = { + sr544_init_reg, sizeof(sr544_init_reg)/sizeof(struct msm_camera_i2c_reg_array), MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_WORD_DATA, 100 +}; + +static struct msm_camera_i2c_reg_array init_otp_reg[] = { + {0x0118, 0x00, NULL, 100}, //sleep On + {0x0F02, 0x00, NULL, 0}, + {0x011A, 0x01, NULL, 0}, + {0x011B, 0x09, NULL, 0}, + {0x0D04, 0x01, NULL, 0}, + {0x0D00, 0x07, NULL, 0}, + {0x004C, 0x01, NULL, 0}, + {0x003E, 0x01, NULL, 0}, + {0x0118, 0x01, NULL, 0}, +}; + +struct msm_camera_i2c_reg_setting init_otp = { + init_otp_reg, sizeof(init_otp_reg)/sizeof(struct msm_camera_i2c_reg_array), MSM_CAMERA_I2C_WORD_ADDR, MSM_CAMERA_I2C_BYTE_DATA, 100 +}; + +extern uint8_t* get_eeprom_data_addr(void); +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2898e3f1448f1ccd8c1ccb1ebdb495e561b7fe69 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5 +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/io +obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o +obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o +obj-$(CONFIG_MSMB_CAMERA) += msm_led_i2c_trigger.o +obj-$(CONFIG_MSMB_CAMERA) += adp1660.o +obj-$(CONFIG_MSMB_CAMERA) += bd7710.o +obj-$(CONFIG_MSMB_CAMERA) += msm_led_torch.o +obj-$(CONFIG_MSMB_CAMERA) += lm3642.o diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/adp1660.c b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/adp1660.c new file mode 100644 index 0000000000000000000000000000000000000000..f57843c6ff2a0ff7d506f7811c03eabdc4af5a08 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/adp1660.c @@ -0,0 +1,212 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include "msm_led_flash.h" + +#define FLASH_NAME "qcom,led-flash" + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static struct msm_led_flash_ctrl_t fctrl; +static struct i2c_driver adp1660_i2c_driver; + +static struct msm_camera_i2c_reg_array adp1660_init_array[] = { + {0x01, 0x03}, + {0x02, 0x0F}, + {0x09, 0x28}, +}; + +static struct msm_camera_i2c_reg_array adp1660_off_array[] = { + {0x0f, 0x00}, +}; + +static struct msm_camera_i2c_reg_array adp1660_release_array[] = { + {0x0f, 0x00}, +}; + +static struct msm_camera_i2c_reg_array adp1660_low_array[] = { + {0x08, 0x04}, + {0x06, 0x1E}, + {0x01, 0xBD}, + {0x0f, 0x01}, +}; + +static struct msm_camera_i2c_reg_array adp1660_high_array[] = { + {0x02, 0x4F}, + {0x06, 0x3C}, + {0x09, 0x3C}, + {0x0f, 0x03}, + {0x01, 0xBB}, +}; + +static void __exit msm_flash_adp1660_i2c_remove(void) +{ + i2c_del_driver(&adp1660_i2c_driver); + return; +} + +static const struct of_device_id adp1660_trigger_dt_match[] = { + {.compatible = "qcom,led-flash", .data = &fctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, adp1660_trigger_dt_match); + +static const struct i2c_device_id flash_i2c_id[] = { + {"qcom,led-flash", (kernel_ulong_t)&fctrl}, + { } +}; + +static const struct i2c_device_id adp1660_i2c_id[] = { + {FLASH_NAME, (kernel_ulong_t)&fctrl}, + { } +}; + +static int msm_flash_adp1660_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + if (!id) { + pr_err("msm_flash_adp1660_i2c_probe: id is NULL"); + id = adp1660_i2c_id; + } + + return msm_flash_i2c_probe(client, id); +} + +static struct i2c_driver adp1660_i2c_driver = { + .id_table = adp1660_i2c_id, + .probe = msm_flash_adp1660_i2c_probe, + .remove = __exit_p(msm_flash_adp1660_i2c_remove), + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = adp1660_trigger_dt_match, + }, +}; + +static int msm_flash_adp1660_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + match = of_match_device(adp1660_trigger_dt_match, &pdev->dev); + if (!match) + return -EFAULT; + return msm_flash_probe(pdev, match->data); +} + +static struct platform_driver adp1660_platform_driver = { + .probe = msm_flash_adp1660_platform_probe, + .driver = { + .name = "qcom,led-flash", + .owner = THIS_MODULE, + .of_match_table = adp1660_trigger_dt_match, + }, +}; + +static int __init msm_flash_adp1660_init_module(void) +{ + int32_t rc = 0; + rc = platform_driver_register(&adp1660_platform_driver); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&adp1660_i2c_driver); +} + +static void __exit msm_flash_adp1660_exit_module(void) +{ + if (fctrl.pdev) + platform_driver_unregister(&adp1660_platform_driver); + else + i2c_del_driver(&adp1660_i2c_driver); +} + +static struct msm_camera_i2c_client adp1660_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static struct msm_camera_i2c_reg_setting adp1660_init_setting = { + .reg_setting = adp1660_init_array, + .size = ARRAY_SIZE(adp1660_init_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_off_setting = { + .reg_setting = adp1660_off_array, + .size = ARRAY_SIZE(adp1660_off_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_release_setting = { + .reg_setting = adp1660_release_array, + .size = ARRAY_SIZE(adp1660_release_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_low_setting = { + .reg_setting = adp1660_low_array, + .size = ARRAY_SIZE(adp1660_low_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting adp1660_high_setting = { + .reg_setting = adp1660_high_array, + .size = ARRAY_SIZE(adp1660_high_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_led_flash_reg_t adp1660_regs = { + .init_setting = &adp1660_init_setting, + .off_setting = &adp1660_off_setting, + .low_setting = &adp1660_low_setting, + .high_setting = &adp1660_high_setting, + .release_setting = &adp1660_release_setting, +}; + +static struct msm_flash_fn_t adp1660_func_tbl = { + .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, + .flash_led_config = msm_led_i2c_trigger_config, + .flash_led_init = msm_flash_led_init, + .flash_led_release = msm_flash_led_release, + .flash_led_off = msm_flash_led_off, + .flash_led_low = msm_flash_led_low, + .flash_led_high = msm_flash_led_high, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .flash_i2c_client = &adp1660_i2c_client, + .reg_setting = &adp1660_regs, + .func_tbl = &adp1660_func_tbl, +}; + +/*subsys_initcall(msm_flash_i2c_add_driver);*/ +module_init(msm_flash_adp1660_init_module); +module_exit(msm_flash_adp1660_exit_module); +MODULE_DESCRIPTION("adp1660 FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/bd7710.c b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/bd7710.c new file mode 100644 index 0000000000000000000000000000000000000000..4e18537f9bf7002adfb990fb3bb342c5b2ddca99 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/bd7710.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include +#include "msm_led_flash.h" + +#define FLASH_NAME "rohm-flash,bd7710" + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static struct msm_led_flash_ctrl_t fctrl; +static struct i2c_driver bd7710_i2c_driver; + +static struct msm_camera_i2c_reg_array bd7710_init_array[] = { + {0x00, 0x10}, +}; + +static struct msm_camera_i2c_reg_array bd7710_off_array[] = { + {0x05, 0x00}, + {0x02, 0x00}, +}; + +static struct msm_camera_i2c_reg_array bd7710_release_array[] = { + {0x00, 0x00}, +}; + +static struct msm_camera_i2c_reg_array bd7710_low_array[] = { + {0x05, 0x25}, + {0x00, 0x38}, + {0x02, 0x40}, +}; + +static struct msm_camera_i2c_reg_array bd7710_high_array[] = { + {0x05, 0x25}, + {0x02, 0xBF}, +}; + +static void __exit msm_flash_bd7710_i2c_remove(void) +{ + i2c_del_driver(&bd7710_i2c_driver); + return; +} + +static const struct of_device_id bd7710_trigger_dt_match[] = { + {.compatible = "rohm-flash,bd7710", .data = &fctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, bd7710_trigger_dt_match); + +static const struct i2c_device_id flash_i2c_id[] = { + {"rohm-flash,bd7710", (kernel_ulong_t)&fctrl}, + { } +}; + +static const struct i2c_device_id bd7710_i2c_id[] = { + {FLASH_NAME, (kernel_ulong_t)&fctrl}, + { } +}; + +static int msm_flash_bd7710_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + if (!id) { + pr_err("msm_flash_bd7710_i2c_probe: id is NULL"); + id = bd7710_i2c_id; + } + + return msm_flash_i2c_probe(client, id); +} + +static struct i2c_driver bd7710_i2c_driver = { + .id_table = bd7710_i2c_id, + .probe = msm_flash_bd7710_i2c_probe, + .remove = __exit_p(msm_flash_bd7710_i2c_remove), + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = bd7710_trigger_dt_match, + }, +}; + +static int msm_flash_bd7710_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + + match = of_match_device(bd7710_trigger_dt_match, &pdev->dev); + if (!match) + return -EFAULT; + return msm_flash_probe(pdev, match->data); +} + +static struct platform_driver bd7710_platform_driver = { + .probe = msm_flash_bd7710_platform_probe, + .driver = { + .name = "rohm-flash,bd7710", + .owner = THIS_MODULE, + .of_match_table = bd7710_trigger_dt_match, + }, +}; + +static int __init msm_flash_bd7710_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&bd7710_platform_driver); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&bd7710_i2c_driver); +} + +static void __exit msm_flash_bd7710_exit_module(void) +{ + if (fctrl.pdev) + platform_driver_unregister(&bd7710_platform_driver); + else + i2c_del_driver(&bd7710_i2c_driver); +} + +static struct msm_camera_i2c_client bd7710_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static struct msm_camera_i2c_reg_setting bd7710_init_setting = { + .reg_setting = bd7710_init_array, + .size = ARRAY_SIZE(bd7710_init_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_off_setting = { + .reg_setting = bd7710_off_array, + .size = ARRAY_SIZE(bd7710_off_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_release_setting = { + .reg_setting = bd7710_release_array, + .size = ARRAY_SIZE(bd7710_release_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_low_setting = { + .reg_setting = bd7710_low_array, + .size = ARRAY_SIZE(bd7710_low_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting bd7710_high_setting = { + .reg_setting = bd7710_high_array, + .size = ARRAY_SIZE(bd7710_high_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_led_flash_reg_t bd7710_regs = { + .init_setting = &bd7710_init_setting, + .off_setting = &bd7710_off_setting, + .low_setting = &bd7710_low_setting, + .high_setting = &bd7710_high_setting, + .release_setting = &bd7710_release_setting, +}; + +static struct msm_flash_fn_t bd7710_func_tbl = { + .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, + .flash_led_config = msm_led_i2c_trigger_config, + .flash_led_init = msm_flash_led_init, + .flash_led_release = msm_flash_led_release, + .flash_led_off = msm_flash_led_off, + .flash_led_low = msm_flash_led_low, + .flash_led_high = msm_flash_led_high, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .flash_i2c_client = &bd7710_i2c_client, + .reg_setting = &bd7710_regs, + .func_tbl = &bd7710_func_tbl, +}; + +/*subsys_initcall(msm_flash_i2c_add_driver);*/ +module_init(msm_flash_bd7710_init_module); +module_exit(msm_flash_bd7710_exit_module); +MODULE_DESCRIPTION("bd7710 FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/lm3642.c b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/lm3642.c new file mode 100644 index 0000000000000000000000000000000000000000..9a3237050fecfb3ef25e3a8dbcf919abc7bc7b53 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/lm3642.c @@ -0,0 +1,399 @@ +/* Copyright (c) 2014, The Linux Foundation. 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 and + * only 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 +#include +#include +#include "msm_camera_io_util.h" +#include "msm_led_flash.h" + +#define FLASH_NAME "ti,lm3642" + +#define CONFIG_LM3642_DEBUG +#ifdef CONFIG_LM3642_DEBUG +#define LM3642_DBG(fmt, args...) pr_err(fmt, ##args) +#else +#define LM3642_DBG(fmt, args...) +#endif + + +static struct msm_led_flash_ctrl_t fctrl; +static struct i2c_driver lm3642_i2c_driver; + +static struct msm_camera_i2c_reg_array lm3642_init_array[] = { + {0x0A, 0x00}, + {0x08, 0x07}, + {0x09, 0x19}, +}; + +static struct msm_camera_i2c_reg_array lm3642_off_array[] = { + {0x0A, 0x00}, +}; + +static struct msm_camera_i2c_reg_array lm3642_release_array[] = { + {0x0A, 0x00}, +}; + +static struct msm_camera_i2c_reg_array lm3642_low_array[] = { + {0x0A, 0x22}, +}; + +static struct msm_camera_i2c_reg_array lm3642_high_array[] = { + {0x0A, 0x23}, +}; + + +static const struct of_device_id lm3642_i2c_trigger_dt_match[] = { + {.compatible = "ti,lm3642"}, + {} +}; + +MODULE_DEVICE_TABLE(of, lm3642_i2c_trigger_dt_match); +static const struct i2c_device_id lm3642_i2c_id[] = { + {FLASH_NAME, (kernel_ulong_t)&fctrl}, + { } +}; + +static void msm_led_torch_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (value > LED_OFF) { + if(fctrl.func_tbl->flash_led_low) + fctrl.func_tbl->flash_led_low(&fctrl); + } else { + if(fctrl.func_tbl->flash_led_off) + fctrl.func_tbl->flash_led_off(&fctrl); + } +}; + +static struct led_classdev msm_torch_led = { + .name = "torch-light", + .brightness_set = msm_led_torch_brightness_set, + .brightness = LED_OFF, +}; + +static int32_t msm_lm3642_torch_create_classdev(struct device *dev , + void *data) +{ + int rc; + msm_led_torch_brightness_set(&msm_torch_led, LED_OFF); + rc = led_classdev_register(dev, &msm_torch_led); + if (rc) { + pr_err("Failed to register led dev. rc = %d\n", rc); + return rc; + } + + return 0; +}; + +int msm_flash_lm3642_led_init(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->init_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + return rc; +} + +int msm_flash_lm3642_led_release(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->release_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + return 0; +} + +int msm_flash_lm3642_led_off(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->off_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + + return rc; +} + +int msm_flash_lm3642_led_low(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->low_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} + +int msm_flash_lm3642_led_high(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + LM3642_DBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + + power_info = &flashdata->power_info; + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->high_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} +static int msm_flash_lm3642_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + int rc = 0 ; + LM3642_DBG("%s entry\n", __func__); + if (!id) { + pr_err("msm_flash_lm3642_i2c_probe: id is NULL"); + id = lm3642_i2c_id; + } + rc = msm_flash_i2c_probe(client, id); + + flashdata = fctrl.flashdata; + power_info = &flashdata->power_info; + + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + if (fctrl.pinctrl_info.use_pinctrl == true) { + pr_err("%s:%d PC:: flash pins setting to active state", + __func__, __LINE__); + rc = pinctrl_select_state(fctrl.pinctrl_info.pinctrl, + fctrl.pinctrl_info.gpio_state_active); + if (rc) + pr_err("%s:%d cannot set pin to active state", + __func__, __LINE__); + } + + if (!rc) + msm_lm3642_torch_create_classdev(&(client->dev),NULL); + return rc; +} + +static int msm_flash_lm3642_i2c_remove(struct i2c_client *client) +{ + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + int rc = 0 ; + LM3642_DBG("%s entry\n", __func__); + flashdata = fctrl.flashdata; + power_info = &flashdata->power_info; + + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 0); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + if (fctrl.pinctrl_info.use_pinctrl == true) { + rc = pinctrl_select_state(fctrl.pinctrl_info.pinctrl, + fctrl.pinctrl_info.gpio_state_suspend); + if (rc) + pr_err("%s:%d cannot set pin to suspend state", + __func__, __LINE__); + } + return rc; +} + + +static struct i2c_driver lm3642_i2c_driver = { + .id_table = lm3642_i2c_id, + .probe = msm_flash_lm3642_i2c_probe, + .remove = msm_flash_lm3642_i2c_remove, + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = lm3642_i2c_trigger_dt_match, + }, +}; + +static int __init msm_flash_lm3642_init(void) +{ + LM3642_DBG("%s entry\n", __func__); + return i2c_add_driver(&lm3642_i2c_driver); +} + +static void __exit msm_flash_lm3642_exit(void) +{ + LM3642_DBG("%s entry\n", __func__); + i2c_del_driver(&lm3642_i2c_driver); + return; +} + + +static struct msm_camera_i2c_client lm3642_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static struct msm_camera_i2c_reg_setting lm3642_init_setting = { + .reg_setting = lm3642_init_array, + .size = ARRAY_SIZE(lm3642_init_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_off_setting = { + .reg_setting = lm3642_off_array, + .size = ARRAY_SIZE(lm3642_off_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_release_setting = { + .reg_setting = lm3642_release_array, + .size = ARRAY_SIZE(lm3642_release_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_low_setting = { + .reg_setting = lm3642_low_array, + .size = ARRAY_SIZE(lm3642_low_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_camera_i2c_reg_setting lm3642_high_setting = { + .reg_setting = lm3642_high_array, + .size = ARRAY_SIZE(lm3642_high_array), + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, + .data_type = MSM_CAMERA_I2C_BYTE_DATA, + .delay = 0, +}; + +static struct msm_led_flash_reg_t lm3642_regs = { + .init_setting = &lm3642_init_setting, + .off_setting = &lm3642_off_setting, + .low_setting = &lm3642_low_setting, + .high_setting = &lm3642_high_setting, + .release_setting = &lm3642_release_setting, +}; + +static struct msm_flash_fn_t lm3642_func_tbl = { + .flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id, + .flash_led_config = msm_led_i2c_trigger_config, + .flash_led_init = msm_flash_lm3642_led_init, + .flash_led_release = msm_flash_lm3642_led_release, + .flash_led_off = msm_flash_lm3642_led_off, + .flash_led_low = msm_flash_lm3642_led_low, + .flash_led_high = msm_flash_lm3642_led_high, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .flash_i2c_client = &lm3642_i2c_client, + .reg_setting = &lm3642_regs, + .func_tbl = &lm3642_func_tbl, +}; + +module_init(msm_flash_lm3642_init); +module_exit(msm_flash_lm3642_exit); +MODULE_DESCRIPTION("lm3642 FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_flash.c new file mode 100644 index 0000000000000000000000000000000000000000..86058a9ca7b882580d5876c9f2f1265c1526c359 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_flash.c @@ -0,0 +1,140 @@ +/* Copyright (c) 2009-2013, The Linux Foundation. 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 and + * only 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. + * + */ + +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include "msm_led_flash.h" +#include + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +static long msm_led_flash_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_led_flash_ctrl_t *fctrl = NULL; + void __user *argp = (void __user *)arg; + if (!sd) { + pr_err("sd NULL\n"); + return -EINVAL; + } + fctrl = v4l2_get_subdevdata(sd); + if (!fctrl) { + pr_err("fctrl NULL\n"); + return -EINVAL; + } + switch (cmd) { + case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID: + return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp); + case VIDIOC_MSM_FLASH_LED_DATA_CFG: + return fctrl->func_tbl->flash_led_config(fctrl, argp); + case MSM_SD_SHUTDOWN: + *(int *)argp = MSM_CAMERA_LED_RELEASE; + return fctrl->func_tbl->flash_led_config(fctrl, argp); + default: + pr_err_ratelimited("invalid cmd %d\n", cmd); + return -ENOIOCTLCMD; + } +} + +static struct v4l2_subdev_core_ops msm_flash_subdev_core_ops = { + .ioctl = msm_led_flash_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_flash_subdev_ops = { + .core = &msm_flash_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_flash_internal_ops; + +int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev, void *data) +{ + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + CDBG("Enter\n"); + + if (!fctrl) { + pr_err("fctrl NULL\n"); + return -EINVAL; + } + + /* Initialize sub device */ + v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops); + v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl); + + fctrl->pdev = pdev; + fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops; + fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name), + "msm_flash"); + media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0); + fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH; + fctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; +#if defined(CONFIG_FLED_SM5701) + fctrl->led_irq_gpio1 = of_get_named_gpio(fctrl->pdev->dev.of_node, "flashen-gpio", 0); +#else + fctrl->led_irq_gpio1 = of_get_named_gpio(fctrl->pdev->dev.of_node, "qcom,led1-gpio", 0); +#endif + if (fctrl->led_irq_gpio1 < 0) { + pr_err("Fail : can't get led1-gpio\n"); + return -EINVAL; + } +#if defined(CONFIG_FLED_SM5701) + fctrl->led_irq_gpio2 = of_get_named_gpio(fctrl->pdev->dev.of_node, "flashtorch-gpio", 0); +#else + fctrl->led_irq_gpio2 = of_get_named_gpio(fctrl->pdev->dev.of_node, "qcom,led2-gpio", 0); +#endif + if (fctrl->led_irq_gpio2 < 0) { + pr_err("Fail : can't get led2-gpio\n"); + return -EINVAL; + } + + msm_sd_register(&fctrl->msm_sd); + + CDBG("probe success\n"); + return 0; +} + +int32_t msm_led_i2c_flash_create_v4lsubdev(void *data) +{ + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + CDBG("Enter\n"); + + if (!fctrl) { + pr_err("fctrl NULL\n"); + return -EINVAL; + } + + /* Initialize sub device */ + v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops); + v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl); + + fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops; + fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name), + "msm_flash"); + media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0); + fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH; + msm_sd_register(&fctrl->msm_sd); + + CDBG("probe success\n"); + return 0; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_flash.h new file mode 100644 index 0000000000000000000000000000000000000000..ad6aba89c7eea1c04f3b99b1154da2372ab98f86 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_flash.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2009-2014, The Linux Foundation. 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 and + * only 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. + * + */ +#ifndef MSM_LED_FLASH_H +#define MSM_LED_FLASH_H + +#include +#include +#include +#include "../../include/media/msm_cam_sensor.h" +#include "../../include/soc/qcom/camera2.h" +#include "msm_camera_i2c.h" +#include "msm_sd.h" + + +struct msm_led_flash_ctrl_t; + +struct msm_flash_fn_t { + int32_t (*flash_get_subdev_id)(struct msm_led_flash_ctrl_t *, void *); + int32_t (*flash_led_config)(struct msm_led_flash_ctrl_t *, void *); + int32_t (*flash_led_init)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_release)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_off)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_low)(struct msm_led_flash_ctrl_t *); + int32_t (*flash_led_high)(struct msm_led_flash_ctrl_t *); +}; + +struct msm_led_flash_reg_t { + struct msm_camera_i2c_reg_setting *init_setting; + struct msm_camera_i2c_reg_setting *off_setting; + struct msm_camera_i2c_reg_setting *release_setting; + struct msm_camera_i2c_reg_setting *low_setting; + struct msm_camera_i2c_reg_setting *high_setting; +}; + +struct msm_led_flash_ctrl_t { + struct msm_camera_i2c_client *flash_i2c_client; + struct msm_sd_subdev msm_sd; + struct platform_device *pdev; + struct msm_flash_fn_t *func_tbl; + struct msm_camera_sensor_board_info *flashdata; + struct msm_led_flash_reg_t *reg_setting; + const char *flash_trigger_name[MAX_LED_TRIGGERS]; + struct led_trigger *flash_trigger[MAX_LED_TRIGGERS]; + uint32_t flash_num_sources; + uint32_t flash_op_current[MAX_LED_TRIGGERS]; + uint32_t flash_max_current[MAX_LED_TRIGGERS]; + const char *torch_trigger_name; + struct led_trigger *torch_trigger; + uint32_t torch_op_current; + uint32_t torch_max_current; + void *data; + uint32_t num_sources; + enum msm_camera_device_type_t flash_device_type; + enum cci_i2c_master_t cci_i2c_master; + enum msm_camera_led_config_t led_state; + uint32_t subdev_id; + struct msm_pinctrl_info pinctrl_info; + int led_irq_gpio1; + int led_irq_gpio2; +}; + +int msm_flash_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id); + +int msm_flash_probe(struct platform_device *pdev, const void *data); + +int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev, + void *data); +int32_t msm_led_i2c_flash_create_v4lsubdev(void *data); + +int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, + void *arg); + +int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl, + void *data); + +int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl); +int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl); +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_i2c_trigger.c new file mode 100644 index 0000000000000000000000000000000000000000..f374ce639341de5973ef5d9bb79594f9a9c23c53 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_i2c_trigger.c @@ -0,0 +1,746 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + * + */ + +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include +#include "msm_led_flash.h" +#include "msm_camera_io_util.h" +#include "../msm_sensor.h" +#include "msm_led_flash.h" +#include "../cci/msm_cci.h" +#include + +#define FLASH_NAME "camera-led-flash" +#define CAM_FLASH_PINCTRL_STATE_SLEEP "cam_flash_suspend" +#define CAM_FLASH_PINCTRL_STATE_DEFAULT "cam_flash_default" +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("failed\n"); + return -EINVAL; + } + *subdev_id = fctrl->subdev_id; + + CDBG("subdev_id %d\n", *subdev_id); + return 0; +} + +int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl, + void *data) +{ + int rc = 0; + struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data; + CDBG("called led_state %d\n", cfg->cfgtype); + + if (!fctrl->func_tbl) { + pr_err("failed\n"); + return -EINVAL; + } + switch (cfg->cfgtype) { + + case MSM_CAMERA_LED_INIT: + if (fctrl->func_tbl->flash_led_init) + rc = fctrl->func_tbl->flash_led_init(fctrl); + break; + + case MSM_CAMERA_LED_RELEASE: + if (fctrl->func_tbl->flash_led_release) + rc = fctrl->func_tbl-> + flash_led_release(fctrl); + break; + + case MSM_CAMERA_LED_OFF: + if (fctrl->func_tbl->flash_led_off) + rc = fctrl->func_tbl->flash_led_off(fctrl); + break; + + case MSM_CAMERA_LED_LOW: + if (fctrl->func_tbl->flash_led_low) + rc = fctrl->func_tbl->flash_led_low(fctrl); + break; + + case MSM_CAMERA_LED_HIGH: + if (fctrl->func_tbl->flash_led_high) + rc = fctrl->func_tbl->flash_led_high(fctrl); + break; + default: + rc = -EFAULT; + break; + } + CDBG("flash_set_led_state: return %d\n", rc); + return rc; +} +static int msm_flash_pinctrl_init(struct msm_led_flash_ctrl_t *ctrl) +{ + struct msm_pinctrl_info *flash_pctrl = NULL; + flash_pctrl = &ctrl->pinctrl_info; + if (flash_pctrl->use_pinctrl != true) { + pr_err("%s: %d PINCTRL is not enables in Flash driver node\n", + __func__, __LINE__); + return 0; + } + flash_pctrl->pinctrl = devm_pinctrl_get(&ctrl->pdev->dev); + + if (IS_ERR_OR_NULL(flash_pctrl->pinctrl)) { + pr_err("%s:%d Getting pinctrl handle failed\n", + __func__, __LINE__); + return -EINVAL; + } + flash_pctrl->gpio_state_active = pinctrl_lookup_state( + flash_pctrl->pinctrl, + CAM_FLASH_PINCTRL_STATE_DEFAULT); + + if (IS_ERR_OR_NULL(flash_pctrl->gpio_state_active)) { + pr_err("%s:%d Failed to get the active state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + flash_pctrl->gpio_state_suspend = pinctrl_lookup_state( + flash_pctrl->pinctrl, + CAM_FLASH_PINCTRL_STATE_SLEEP); + + if (IS_ERR_OR_NULL(flash_pctrl->gpio_state_suspend)) { + pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + + +int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + CDBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + fctrl->led_state = MSM_CAMERA_LED_RELEASE; + if (power_info->gpio_conf->cam_gpiomux_conf_tbl != NULL) { + pr_err("%s:%d mux install\n", __func__, __LINE__); + msm_gpiomux_install( + (struct msm_gpiomux_config *) + power_info->gpio_conf->cam_gpiomux_conf_tbl, + power_info->gpio_conf->cam_gpiomux_conf_tbl_size); + } + + /* CCI Init */ + if (fctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_util( + fctrl->flash_i2c_client, MSM_CCI_INIT); + if (rc < 0) { + pr_err("cci_init failed\n"); + return rc; + } + } + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + if (fctrl->pinctrl_info.use_pinctrl == true) { + CDBG("%s:%d PC:: flash pins setting to active state", + __func__, __LINE__); + rc = pinctrl_select_state(fctrl->pinctrl_info.pinctrl, + fctrl->pinctrl_info.gpio_state_active); + if (rc) + pr_err("%s:%d cannot set pin to active state", + __func__, __LINE__); + } + msleep(20); + + CDBG("before FL_RESET\n"); + if (power_info->gpio_conf->gpio_num_info-> + valid[SENSOR_GPIO_FL_RESET] == 1) + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_RESET], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->init_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + fctrl->led_state = MSM_CAMERA_LED_INIT; + return rc; +} + +int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0, ret = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + + + if (fctrl->led_state != MSM_CAMERA_LED_INIT) { + pr_err("%s:%d invalid led state\n", __func__, __LINE__); + return -EINVAL; + } + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + CDBG("%s:%d called\n", __func__, __LINE__); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_LOW); + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + if (power_info->gpio_conf->gpio_num_info-> + valid[SENSOR_GPIO_FL_RESET] == 1) + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_RESET], + GPIO_OUT_LOW); + + if (fctrl->pinctrl_info.use_pinctrl == true) { + ret = pinctrl_select_state(fctrl->pinctrl_info.pinctrl, + fctrl->pinctrl_info.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state", + __func__, __LINE__); + } + rc = msm_camera_request_gpio_table( + power_info->gpio_conf->cam_gpio_req_tbl, + power_info->gpio_conf->cam_gpio_req_tbl_size, 0); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + + fctrl->led_state = MSM_CAMERA_LED_RELEASE; + /* CCI deInit */ + if (fctrl->flash_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_util( + fctrl->flash_i2c_client, MSM_CCI_RELEASE); + if (rc < 0) + pr_err("cci_deinit failed\n"); + } + + return 0; +} + +int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + + if (!fctrl) { + pr_err("%s:%d fctrl NULL\n", __func__, __LINE__); + return -EINVAL; + } + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + CDBG("%s:%d called\n", __func__, __LINE__); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->off_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + + return rc; +} + +int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + CDBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->low_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} + +int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl) +{ + int rc = 0; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + CDBG("%s:%d called\n", __func__, __LINE__); + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + + gpio_set_value_cansleep( + power_info->gpio_conf->gpio_num_info-> + gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + + if (fctrl->flash_i2c_client && fctrl->reg_setting) { + rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table( + fctrl->flash_i2c_client, + fctrl->reg_setting->high_setting); + if (rc < 0) + pr_err("%s:%d failed\n", __func__, __LINE__); + } + + return rc; +} + +static int32_t msm_led_get_dt_data(struct device_node *of_node, + struct msm_led_flash_ctrl_t *fctrl) +{ + int32_t rc = 0, i = 0; + struct msm_camera_gpio_conf *gconf = NULL; + struct device_node *flash_src_node = NULL; + struct msm_camera_sensor_board_info *flashdata = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + uint32_t count = 0; + uint16_t *gpio_array = NULL; + uint16_t gpio_array_size = 0; + uint32_t id_info[3]; + + CDBG("called\n"); + + if (!of_node) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + + fctrl->flashdata = kzalloc(sizeof( + struct msm_camera_sensor_board_info), + GFP_KERNEL); + if (!fctrl->flashdata) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + flashdata = fctrl->flashdata; + power_info = &flashdata->power_info; + + rc = of_property_read_u32(of_node, "cell-index", &fctrl->subdev_id); + if (rc < 0) { + pr_err("failed\n"); + return -EINVAL; + } + + CDBG("subdev id %d\n", fctrl->subdev_id); + + rc = of_property_read_string(of_node, "label", + &flashdata->sensor_name); + CDBG("%s label %s, rc %d\n", __func__, + flashdata->sensor_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &fctrl->cci_i2c_master); + CDBG("%s qcom,cci-master %d, rc %d\n", __func__, fctrl->cci_i2c_master, + rc); + if (rc < 0) { + /* Set default master 0 */ + fctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + fctrl->pinctrl_info.use_pinctrl = false; + fctrl->pinctrl_info.use_pinctrl = of_property_read_bool(of_node, + "qcom,enable_pinctrl"); + if (of_get_property(of_node, "qcom,flash-source", &count)) { + count /= sizeof(uint32_t); + CDBG("count %d\n", count); + if (count > MAX_LED_TRIGGERS) { + pr_err("failed\n"); + return -EINVAL; + } + for (i = 0; i < count; i++) { + flash_src_node = of_parse_phandle(of_node, + "qcom,flash-source", i); + if (!flash_src_node) { + pr_err("flash_src_node NULL\n"); + continue; + } + + rc = of_property_read_string(flash_src_node, + "linux,default-trigger", + &fctrl->flash_trigger_name[i]); + if (rc < 0) { + pr_err("failed\n"); + of_node_put(flash_src_node); + continue; + } + + CDBG("default trigger %s\n", + fctrl->flash_trigger_name[i]); + + rc = of_property_read_u32(flash_src_node, + "qcom,max-current", + &fctrl->flash_op_current[i]); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + of_node_put(flash_src_node); + continue; + } + + of_node_put(flash_src_node); + + CDBG("max_current[%d] %d\n", + i, fctrl->flash_op_current[i]); + + led_trigger_register_simple( + fctrl->flash_trigger_name[i], + &fctrl->flash_trigger[i]); + } + + } else { /*Handle LED Flash Ctrl by GPIO*/ + power_info->gpio_conf = + kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!power_info->gpio_conf) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + gconf = power_info->gpio_conf; + + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR4; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + + rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR5; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR6; + } + } + + flashdata->slave_info = + kzalloc(sizeof(struct msm_camera_slave_info), + GFP_KERNEL); + if (!flashdata->slave_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR8; + } + + rc = of_property_read_u32_array(of_node, "qcom,slave-id", + id_info, 3); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR9; + } + fctrl->flashdata->slave_info->sensor_slave_addr = id_info[0]; + fctrl->flashdata->slave_info->sensor_id_reg_addr = id_info[1]; + fctrl->flashdata->slave_info->sensor_id = id_info[2]; + + kfree(gpio_array); + return rc; +ERROR9: + kfree(fctrl->flashdata->slave_info); +ERROR8: + kfree(fctrl->flashdata->power_info.gpio_conf->gpio_num_info); +ERROR6: + kfree(gconf->cam_gpio_set_tbl); +ERROR5: + kfree(gconf->cam_gpio_req_tbl); +ERROR4: + kfree(gconf); +ERROR1: + kfree(fctrl->flashdata); + kfree(gpio_array); + } + return rc; +} + +static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl, +}; + +#ifdef CONFIG_DEBUG_FS +static int set_led_status(void *data, u64 val) +{ + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + int rc = -1; + pr_debug("set_led_status: Enter val: %llu", val); + if (!fctrl) { + pr_err("set_led_status: fctrl is NULL"); + return rc; + } + if (!fctrl->func_tbl) { + pr_err("set_led_status: fctrl->func_tbl is NULL"); + return rc; + } + if (val == 0) { + pr_debug("set_led_status: val is disable"); + rc = msm_flash_led_off(fctrl); + } else { + pr_debug("set_led_status: val is enable"); + rc = msm_flash_led_low(fctrl); + } + + return rc; +} + +DEFINE_SIMPLE_ATTRIBUTE(ledflashdbg_fops, + NULL, set_led_status, "%llu\n"); +#endif + +int msm_flash_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct msm_led_flash_ctrl_t *fctrl = NULL; +#ifdef CONFIG_DEBUG_FS + struct dentry *dentry; +#endif + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality failed\n"); + goto probe_failure; + } + + fctrl = (struct msm_led_flash_ctrl_t *)(id->driver_data); + if (fctrl->flash_i2c_client) + fctrl->flash_i2c_client->client = client; + /* Set device type as I2C */ + fctrl->flash_device_type = MSM_CAMERA_I2C_DEVICE; + + /* Assign name for sub device */ + snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name), + "%s", id->name); + + rc = msm_led_get_dt_data(client->dev.of_node, fctrl); + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + + msm_flash_pinctrl_init(fctrl); + if (fctrl->flash_i2c_client != NULL) { + fctrl->flash_i2c_client->client = client; + if (fctrl->flashdata->slave_info->sensor_slave_addr) + fctrl->flash_i2c_client->client->addr = + fctrl->flashdata->slave_info-> + sensor_slave_addr; + } else { + pr_err("%s %s sensor_i2c_client NULL\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + if (!fctrl->flash_i2c_client->i2c_func_tbl) + fctrl->flash_i2c_client->i2c_func_tbl = + &msm_sensor_qup_func_tbl; + + rc = msm_led_i2c_flash_create_v4lsubdev(fctrl); +#ifdef CONFIG_DEBUG_FS + dentry = debugfs_create_file("ledflash", S_IRUGO, NULL, (void *)fctrl, + &ledflashdbg_fops); + if (!dentry) + pr_err("Failed to create the debugfs ledflash file"); +#endif + CDBG("%s:%d probe success\n", __func__, __LINE__); + return 0; + +probe_failure: + CDBG("%s:%d probe failed\n", __func__, __LINE__); + return rc; +} + +int msm_flash_probe(struct platform_device *pdev, + const void *data) +{ + int rc = 0; + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + struct device_node *of_node = pdev->dev.of_node; + struct msm_camera_cci_client *cci_client = NULL; + + if (!of_node || !fctrl) { + pr_err("%s of_node is NULL or fctrl is NULL, line %d\n",__func__,__LINE__); + rc = -EFAULT; + goto probe_failure; + } + fctrl->pdev = pdev; + + rc = msm_led_get_dt_data(pdev->dev.of_node, fctrl); + if (rc < 0) { + pr_err("%s failed line %d rc = %d\n", __func__, __LINE__, rc); + rc = -EFAULT; + goto probe_failure; + } + + msm_flash_pinctrl_init(fctrl); + /* Assign name for sub device */ + snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name), + "%s", fctrl->flashdata->sensor_name); + /* Set device type as Platform*/ + fctrl->flash_device_type = MSM_CAMERA_PLATFORM_DEVICE; + + if (NULL == fctrl->flash_i2c_client) { + pr_err("%s flash_i2c_client NULL\n", + __func__); + rc = -EFAULT; + goto probe_failure; + } + + fctrl->flash_i2c_client->cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!fctrl->flash_i2c_client->cci_client) { + pr_err("%s failed line %d kzalloc failed\n", + __func__, __LINE__); + rc = -ENOMEM; + goto probe_failure; + } + + cci_client = fctrl->flash_i2c_client->cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = fctrl->cci_i2c_master; + if (fctrl->flashdata->slave_info->sensor_slave_addr) + cci_client->sid = + fctrl->flashdata->slave_info->sensor_slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + + if (!fctrl->flash_i2c_client->i2c_func_tbl) + fctrl->flash_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; + + rc = msm_led_flash_create_v4lsubdev(pdev, fctrl); + + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + goto probe_failure1; + } + + CDBG("%s: probe success\n", __func__); + return 0; + +probe_failure1: + kfree(fctrl->flash_i2c_client->cci_client); + +probe_failure: + + pr_err("%s probe failed\n", __func__); + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_torch.c b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_torch.c new file mode 100644 index 0000000000000000000000000000000000000000..ff6369634541c81c8dfec13dbcbc345947fbef8e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_torch.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + * + */ + +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include "msm_led_flash.h" + +static struct led_trigger *torch_trigger; + +static void msm_led_torch_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (!torch_trigger) { + pr_err("No torch trigger found, can't set brightness\n"); + return; + } + + led_trigger_event(torch_trigger, value); +}; + +static struct led_classdev msm_torch_led = { + .name = "torch-light", + .brightness_set = msm_led_torch_brightness_set, + .brightness = LED_OFF, +}; + +int32_t msm_led_torch_create_classdev(struct platform_device *pdev, + void *data) +{ + int rc; + struct msm_led_flash_ctrl_t *fctrl = + (struct msm_led_flash_ctrl_t *)data; + + if (!fctrl || !fctrl->torch_trigger) { + pr_err("Invalid fctrl or torch trigger\n"); + return -EINVAL; + } + + torch_trigger = fctrl->torch_trigger; + msm_led_torch_brightness_set(&msm_torch_led, LED_OFF); + + rc = led_classdev_register(&pdev->dev, &msm_torch_led); + if (rc) { + pr_err("Failed to register led dev. rc = %d\n", rc); + return rc; + } + + return 0; +}; diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_trigger.c new file mode 100644 index 0000000000000000000000000000000000000000..c47b8e496abc7ecd3eee51d00f016a8708db246c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/flash/msm_led_trigger.c @@ -0,0 +1,566 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. 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 and + * only 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. + * + */ + +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include +#if defined(CONFIG_FLED_SM5701) +#include +#endif +#ifdef CONFIG_FLED_RT5033_EXT_GPIO +#include +#endif +#if defined(CONFIG_FLED_SM5703_EXT_GPIO) || defined(CONFIG_FLED_SM5703) +#include +#endif +#ifdef CONFIG_FLED_SM5703 +#include +#endif +#include "msm_led_flash.h" + +#define FLASH_NAME "camera-led-flash" + +#if defined(CONFIG_FLED_LM3632) +extern void ssflash_led_turn_on(void); +extern void ssflash_led_turn_off(void); +#endif +#if defined(CONFIG_FLED_KTD2692) +extern void ktd2692_flash_on(unsigned data); +#endif + +extern int system_rev; + + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +extern int32_t msm_led_torch_create_classdev( + struct platform_device *pdev, void *data); +#ifdef CONFIG_FLED_RT5033_EXT_GPIO +extern void rt5033_fled_strobe_critial_section_lock(struct rt_fled_info *fled_info); +extern void rt5033_fled_strobe_critial_section_unlock(struct rt_fled_info *fled_info); +extern bool assistive_light; +#endif + +#if defined(CONFIG_FLED_SM5701) +extern bool assistive_light; +#endif + +#ifdef CONFIG_FLED_SM5703_EXT_GPIO +extern bool assistive_light; +extern int32_t sm5703_fled_notification(struct sm_fled_info *info); +static int led_prev_mode = 0; +#endif + +static enum flash_type flashtype; +static struct msm_led_flash_ctrl_t fctrl; +#ifdef CONFIG_FLED_RT5033_EXT_GPIO +static bool lock_state = false; +#endif + +static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl, + void *arg) +{ + uint32_t *subdev_id = (uint32_t *)arg; + if (!subdev_id) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -EINVAL; + } + *subdev_id = fctrl->pdev->id; + CDBG("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id); + return 0; +} + +static int32_t msm_led_trigger_config(struct msm_led_flash_ctrl_t *fctrl, + void *data) +{ + int rc = 0; + struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data; +#if !defined(CONFIG_FLED_SM5703) + uint32_t i; +#endif +#ifdef CONFIG_FLED_RT5033_EXT_GPIO + rt_fled_info_t *fled_info = rt_fled_get_info_by_name(NULL); +#endif +#if defined(CONFIG_FLED_SM5703_EXT_GPIO) || defined(CONFIG_FLED_SM5703) + sm_fled_info_t *fled_info = sm_fled_get_info_by_name(NULL); +#endif +#if 0 + uint32_t curr_l, max_curr_l; +#endif + CDBG("called led_state %d\n", cfg->cfgtype); + + if (!fctrl) { + pr_err("[%s:%d]failed\n", __func__, __LINE__); + return -EINVAL; + } + +#ifdef CONFIG_SEC_NOVEL_PROJECT + pr_err("MSM-Not control flash %d\n", cfg->cfgtype); + return 0; +#endif + + switch (cfg->cfgtype) { + case MSM_CAMERA_LED_OFF: + pr_err("MSM_CAMERA_LED_OFF\n"); +#if defined(CONFIG_FLED_LM3632) || defined(CONFIG_FLED_KTD2692) + if(system_rev < 5){ + CDBG("ssflaash led turn on msm_led_trigger\n"); + ssflash_led_turn_off(); + }else{ + ktd2692_flash_on(0); + CDBG("Ktd2692 led turn on msm_led_trigger\n"); + } +#endif + +#ifdef CONFIG_FLED_RT5033_EXT_GPIO + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } +#endif +#ifdef CONFIG_FLED_SM5703_EXT_GPIO + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } + if (fled_info) { + flashlight_set_mode(fled_info->flashlight_dev, FLASHLIGHT_MODE_OFF); + flashlight_strobe(fled_info->flashlight_dev, TURN_WAY_GPIO); + sm5703_fled_notification(fled_info); + } + break; + +#endif +#if defined(CONFIG_FLED_SM5701) + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } + sm5701_led_ready(LED_DISABLE); + sm5701_set_fleden(SM5701_FLEDEN_DISABLED); +#else + gpio_request(fctrl->led_irq_gpio1, NULL); + gpio_request(fctrl->led_irq_gpio2, NULL); + gpio_direction_output(fctrl->led_irq_gpio1, 0); + gpio_direction_output(fctrl->led_irq_gpio2, 0); + gpio_free(fctrl->led_irq_gpio1); + gpio_free(fctrl->led_irq_gpio2); +#endif +#ifdef CONFIG_FLED_RT5033_EXT_GPIO + if (lock_state) { + if (fled_info) { + rt5033_fled_strobe_critial_section_unlock(fled_info); + lock_state = false; + } + } +#endif + break; +#if 0 + for (i = 0; i < fctrl->num_sources; i++) + if (fctrl->flash_trigger[i]) + led_trigger_event(fctrl->flash_trigger[i], 0); + if (fctrl->torch_trigger) + led_trigger_event(fctrl->torch_trigger, 0); + break; +#endif + + case MSM_CAMERA_LED_LOW: + pr_err("MSM_CAMERA_LED_LOW\n"); +#if defined(CONFIG_FLED_LM3632) || defined(CONFIG_FLED_KTD2692) + if (cfg->torch_current == FRONT_CAMERA_B) { + if(system_rev < 5){ + ssflash_led_turn_on(); + }else{ + ktd2692_flash_on(1); + } + break; + } +#endif + +#ifdef CONFIG_FLED_RT5033_EXT_GPIO + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } +#endif +#ifdef CONFIG_FLED_SM5703_EXT_GPIO + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } + if (fled_info) { + flashlight_set_mode(fled_info->flashlight_dev, FLASHLIGHT_MODE_TORCH); + sm5703_fled_notification(fled_info); + flashlight_strobe(fled_info->flashlight_dev, TURN_WAY_GPIO); + } + break; +#endif +#if defined(CONFIG_FLED_SM5701) + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } + sm5701_led_ready(MOVIE_MODE); + sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE); +#else + gpio_request(fctrl->led_irq_gpio1, NULL); + gpio_direction_output(fctrl->led_irq_gpio1, 1); + gpio_free(fctrl->led_irq_gpio1); +#endif + break; +#if 0 + if (fctrl->torch_trigger) { + max_curr_l = fctrl->torch_max_current; + if (cfg->torch_current > 0 && + cfg->torch_current < max_curr_l) { + curr_l = cfg->torch_current; + } else { + curr_l = fctrl->torch_op_current; + pr_debug("LED current clamped to %d\n", + curr_l); + } + led_trigger_event(fctrl->torch_trigger, + curr_l); + } + break; +#endif + + case MSM_CAMERA_LED_HIGH: + pr_err("MSM_CAMERA_LED_HIGH\n"); +#ifdef CONFIG_FLED_RT5033_EXT_GPIO + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } + if (fled_info) { + rt5033_fled_strobe_critial_section_lock(fled_info); + lock_state = true; + } +#endif +#ifdef CONFIG_FLED_SM5703_EXT_GPIO + if (assistive_light == true) { + pr_err("When assistive light, Not control flash\n"); + return 0; + } + if (fled_info) { + flashlight_set_mode(fled_info->flashlight_dev, FLASHLIGHT_MODE_FLASH); + sm5703_fled_notification(fled_info); + flashlight_strobe(fled_info->flashlight_dev, TURN_WAY_GPIO); + } + break; + +#endif +#if defined(CONFIG_FLED_SM5701) + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } + sm5701_led_ready(FLASH_MODE); + sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH); +#else + gpio_request(fctrl->led_irq_gpio2, NULL); + gpio_direction_output(fctrl->led_irq_gpio2, 1); + gpio_free(fctrl->led_irq_gpio2); +#endif + break; +#if 0 + if (fctrl->torch_trigger) + led_trigger_event(fctrl->torch_trigger, 0); + for (i = 0; i < fctrl->num_sources; i++) + if (fctrl->flash_trigger[i]) { + max_curr_l = fctrl->flash_max_current[i]; + if (cfg->flash_current[i] > 0 && + cfg->flash_current[i] < max_curr_l) { + curr_l = cfg->flash_current[i]; + } else { + curr_l = fctrl->flash_op_current[i]; + pr_debug("LED current clamped to %d\n", + curr_l); + } + led_trigger_event(fctrl->flash_trigger[i], + curr_l); + } + break; +#endif + case MSM_CAMERA_LED_INIT: + case MSM_CAMERA_LED_RELEASE: + CDBG("MSM_CAMERA_LED_INIT\n"); +#if defined(CONFIG_FLED_SM5703_EXT_GPIO) + + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + } else if (fled_info) { + flashlight_set_mode(fled_info->flashlight_dev, FLASHLIGHT_MODE_OFF); + flashlight_strobe(fled_info->flashlight_dev, TURN_WAY_GPIO); + sm5703_fled_notification(fled_info); + + } + /*for (i = 0; i < fctrl->flash_num_sources; i++) + { + if (fctrl->flash_trigger[i]) + led_trigger_event(fctrl->flash_trigger[i], 0); + if (fctrl->torch_trigger) + led_trigger_event(fctrl->torch_trigger[i], 0); + }*/ + break; + +#endif +#ifdef CONFIG_FLED_RT5033_EXT_GPIO + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + } else { + gpio_request(fctrl->led_irq_gpio1, NULL); + gpio_request(fctrl->led_irq_gpio2, NULL); + gpio_direction_output(fctrl->led_irq_gpio1, 0); + gpio_direction_output(fctrl->led_irq_gpio2, 0); + gpio_free(fctrl->led_irq_gpio1); + gpio_free(fctrl->led_irq_gpio2); + if (lock_state) { + if (fled_info) { + rt5033_fled_strobe_critial_section_unlock(fled_info); + lock_state = false; + } + } + } +#endif +#if defined(CONFIG_FLED_SM5701) + if (assistive_light == true) { + CDBG("When assistive light, Not control flash\n"); + return 0; + } + sm5701_led_ready(LED_DISABLE); + sm5701_set_fleden(SM5701_FLEDEN_DISABLED); +#endif +#if !defined(CONFIG_FLED_SM5703_EXT_GPIO) + for (i = 0; i < fctrl->num_sources; i++) + if (fctrl->flash_trigger[i]) + led_trigger_event(fctrl->flash_trigger[i], 0); + if (fctrl->torch_trigger) + led_trigger_event(fctrl->torch_trigger, 0); + break; +#endif + default: + pr_err("LED state error!\n"); + rc = -EFAULT; + break; + } + CDBG("flash_set_led_state: return %d\n", rc); + return rc; +} + +static const struct of_device_id msm_led_trigger_dt_match[] = { + {.compatible = "qcom,camera-led-flash"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_led_trigger_dt_match); + +static struct platform_driver msm_led_trigger_driver = { + .driver = { + .name = FLASH_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_led_trigger_dt_match, + }, +}; + +static int32_t msm_led_trigger_probe(struct platform_device *pdev) +{ + int32_t rc = 0, rc_1 = 0, i = 0; + struct device_node *of_node = pdev->dev.of_node; + struct device_node *flash_src_node = NULL; + uint32_t count = 0; + struct led_trigger *temp = NULL; + + CDBG("called\n"); + + if (!of_node) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + + fctrl.pdev = pdev; + fctrl.num_sources = 0; + + rc = of_property_read_u32(of_node, "cell-index", &pdev->id); + if (rc < 0) { + pr_err("failed\n"); + return -EINVAL; + } + CDBG("pdev id %d\n", pdev->id); + + rc = of_property_read_u32(of_node, + "qcom,flash-type", &flashtype); + if (rc < 0) { + pr_err("flash-type: read failed\n"); + return -EINVAL; + } + + if (of_get_property(of_node, "qcom,flash-source", &count)) { + count /= sizeof(uint32_t); + CDBG("count %d\n", count); + if (count > MAX_LED_TRIGGERS) { + pr_err("invalid count\n"); + return -EINVAL; + } + fctrl.num_sources = count; + for (i = 0; i < count; i++) { + flash_src_node = of_parse_phandle(of_node, + "qcom,flash-source", i); + if (!flash_src_node) { + pr_err("flash_src_node NULL\n"); + continue; + } + + rc = of_property_read_string(flash_src_node, + "linux,default-trigger", + &fctrl.flash_trigger_name[i]); + if (rc < 0) { + pr_err("default-trigger: read failed\n"); + of_node_put(flash_src_node); + continue; + } + + CDBG("default trigger %s\n", + fctrl.flash_trigger_name[i]); + + if (flashtype == GPIO_FLASH) { + /* use fake current */ + fctrl.flash_op_current[i] = LED_FULL; + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,current", + &fctrl.flash_op_current[i]); + rc_1 = of_property_read_u32(flash_src_node, + "qcom,max-current", + &fctrl.flash_max_current[i]); + if ((rc < 0) || (rc_1 < 0)) { + pr_err("current: read failed\n"); + of_node_put(flash_src_node); + continue; + } + } + + of_node_put(flash_src_node); + + CDBG("max_current[%d] %d\n", + i, fctrl.flash_op_current[i]); + + led_trigger_register_simple(fctrl.flash_trigger_name[i], + &fctrl.flash_trigger[i]); + + if (flashtype == GPIO_FLASH) + if (fctrl.flash_trigger[i]) + temp = fctrl.flash_trigger[i]; + } + + /* Torch source */ + flash_src_node = of_parse_phandle(of_node, "qcom,torch-source", + 0); + if (flash_src_node) { + rc = of_property_read_string(flash_src_node, + "linux,default-trigger", + &fctrl.torch_trigger_name); + if (rc < 0) { + pr_err("default-trigger: read failed\n"); + goto torch_failed; + } + + CDBG("default trigger %s\n", + fctrl.torch_trigger_name); + + if (flashtype == GPIO_FLASH) { + /* use fake current */ + fctrl.torch_op_current = LED_HALF; + if (temp) + fctrl.torch_trigger = temp; + else + led_trigger_register_simple( + fctrl.torch_trigger_name, + &fctrl.torch_trigger); + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,current", + &fctrl.torch_op_current); + rc_1 = of_property_read_u32(flash_src_node, + "qcom,max-current", + &fctrl.torch_max_current); + + if ((rc < 0) || (rc_1 < 0)) { + pr_err("current: read failed\n"); + goto torch_failed; + } + + CDBG("torch max_current %d\n", + fctrl.torch_op_current); + + led_trigger_register_simple( + fctrl.torch_trigger_name, + &fctrl.torch_trigger); + } +torch_failed: + of_node_put(flash_src_node); + } + } + + rc = msm_led_flash_create_v4lsubdev(pdev, &fctrl); + if (!rc) { + msm_led_torch_create_classdev(pdev, &fctrl); + } + + return rc; +} + +static int __init msm_led_trigger_add_driver(void) +{ + CDBG("called\n"); + return platform_driver_probe(&msm_led_trigger_driver, + msm_led_trigger_probe); +} + +static struct msm_flash_fn_t msm_led_trigger_func_tbl = { + .flash_get_subdev_id = msm_led_trigger_get_subdev_id, + .flash_led_config = msm_led_trigger_config, +}; + +static struct msm_led_flash_ctrl_t fctrl = { + .func_tbl = &msm_led_trigger_func_tbl, +}; +#if defined(CONFIG_FLED_SM5703) +int set_led_flash(int mode) +{ + struct msm_camera_led_cfg_t cfg; + int rc = 0; + cfg.cfgtype = mode; + + if (led_prev_mode && mode) + return -1; + + rc = msm_led_trigger_config(&fctrl, &mode); + + if (rc == 0) + led_prev_mode = mode; + + return rc; +} +EXPORT_SYMBOL(set_led_flash); +#endif +module_init(msm_led_trigger_add_driver); +MODULE_DESCRIPTION("LED TRIGGER FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2_j5/sensor/gc0339.c new file mode 100755 index 0000000000000000000000000000000000000000..bada8365fc4c345e86f145bb5eed52c4e7c950b1 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/gc0339.c @@ -0,0 +1,704 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#include "msm_camera_i2c_mux.h" + + +#define GC0339_SENSOR_NAME "gc0339" +DEFINE_MSM_MUTEX(gc0339_mut); + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + + +static struct msm_sensor_ctrl_t gc0339_s_ctrl; + +static struct msm_sensor_power_setting gc0339_power_setting[] = { + + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 1, + }, +}; + +static struct v4l2_subdev_info gc0339_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static int32_t msm_gc0339_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &gc0339_s_ctrl); +} + +static const struct i2c_device_id gc0339_i2c_id[] = { + {GC0339_SENSOR_NAME, (kernel_ulong_t)&gc0339_s_ctrl}, + { } +}; + +static struct i2c_driver gc0339_i2c_driver = { + .id_table = gc0339_i2c_id, + .probe = msm_gc0339_i2c_probe, + .driver = { + .name = GC0339_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client gc0339_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +int32_t gc0339_power_up(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0, index = 0; + struct msm_sensor_power_setting_array *power_setting_array = NULL; + struct msm_sensor_power_setting *power_setting = NULL; + struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; + struct msm_camera_power_ctrl_t *power_info = &data->power_info; + struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf; + + CDBG("%s:%d\n", __func__, __LINE__); + power_setting_array = &s_ctrl->power_setting_array; + + if (gpio_conf->cam_gpiomux_conf_tbl != NULL) { + pr_err("%s:%d mux install\n", __func__, __LINE__); + msm_gpiomux_install( + (struct msm_gpiomux_config *) + gpio_conf->cam_gpiomux_conf_tbl, + gpio_conf->cam_gpiomux_conf_tbl_size); + } + + rc = msm_camera_request_gpio_table( + gpio_conf->cam_gpio_req_tbl, + gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + for (index = 0; index < power_setting_array->size; index++) { + CDBG("%s index %d\n", __func__, index); + power_setting = &power_setting_array->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + if (power_setting->seq_val >= + power_info->clk_info_size) { + pr_err("%s clk index %d >= max %d\n", __func__, + power_setting->seq_val, + power_info->clk_info_size); + goto power_up_failed; + } + if (power_setting->config_val) + power_info->clk_info[power_setting->seq_val]. + clk_rate = power_setting->config_val; + + rc = msm_cam_clk_enable(power_info->dev, + &power_info->clk_info[0], + (struct clk **)&power_setting->data[0], + power_info->clk_info_size, + 1); + if (rc < 0) { + pr_err("%s: clk enable failed\n", + __func__); + goto power_up_failed; + } + break; + case SENSOR_GPIO: + if (power_setting->seq_val >= SENSOR_GPIO_MAX || + !gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__, + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]); + if (gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]) + gpio_set_value_cansleep( + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + power_setting->config_val); + break; + case SENSOR_VREG: + if (power_setting->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + msm_camera_config_single_vreg(power_info->dev, + &power_info->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 1); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( + s_ctrl->sensor_i2c_client, MSM_CCI_INIT); + if (rc < 0) { + pr_err("%s cci_init failed\n", __func__); + goto power_up_failed; + } + } + + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + 0xfc, + 0x10, MSM_CAMERA_I2C_BYTE_DATA); + + if (s_ctrl->func_tbl->sensor_match_id) + rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); + else + rc = msm_sensor_match_id(s_ctrl); + if (rc < 0) { + pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc); + goto power_up_failed; + } + + CDBG("%s exit\n", __func__); + return 0; +power_up_failed: + pr_err("%s:%d failed\n", __func__, __LINE__); + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( + s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE); + } + + for (index--; index >= 0; index--) { + CDBG("%s index %d\n", __func__, index); + power_setting = &power_setting_array->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + msm_cam_clk_enable(power_info->dev, + &power_info->clk_info[0], + (struct clk **)&power_setting->data[0], + power_info->clk_info_size, + 0); + break; + case SENSOR_GPIO: + if (gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]) + gpio_set_value_cansleep( + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VREG: + msm_camera_config_single_vreg(power_info->dev, + &power_info->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 0); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + msm_camera_request_gpio_table( + gpio_conf->cam_gpio_req_tbl, + gpio_conf->cam_gpio_req_tbl_size, 0); + return rc; +} + +int32_t gc0339_power_down(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t index = 0; + struct msm_sensor_power_setting_array *power_setting_array = NULL; + struct msm_sensor_power_setting *power_setting = NULL; + struct msm_camera_sensor_board_info *data = s_ctrl->sensordata; + struct msm_camera_power_ctrl_t *power_info = &data->power_info; + struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf; + + CDBG("%s:%d\n", __func__, __LINE__); + power_setting_array = &s_ctrl->power_setting_array; + + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util( + s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE); + } + + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + 0xfc, + 0x01, MSM_CAMERA_I2C_BYTE_DATA); + + for (index = (power_setting_array->size - 1); index >= 0; index--) { + CDBG("%s index %d\n", __func__, index); + power_setting = &power_setting_array->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + msm_cam_clk_enable(power_info->dev, + &power_info->clk_info[0], + (struct clk **)&power_setting->data[0], + power_info->clk_info_size, + 0); + break; + case SENSOR_GPIO: + if (power_setting->seq_val >= SENSOR_GPIO_MAX || + !gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + continue; + } + if (gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]) + gpio_set_value_cansleep( + gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VREG: + if (power_setting->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + continue; + } + msm_camera_config_single_vreg(power_info->dev, + &power_info->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 0); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + msm_camera_request_gpio_table( + gpio_conf->cam_gpio_req_tbl, + gpio_conf->cam_gpio_req_tbl_size, 0); + CDBG("%s exit\n", __func__); + return 0; +} + +int32_t gc0339_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint16_t chipid = 0; + + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + s_ctrl->sensordata->slave_info->sensor_id_reg_addr, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + if (chipid != s_ctrl->sensordata->slave_info->sensor_id) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + return rc; +} + +int32_t gc0339_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_sensor_power_setting_array *power_setting_array; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + s_ctrl->power_setting_array = + sensor_slave_info.power_setting_array; + power_setting_array = &s_ctrl->power_setting_array; + power_setting_array->power_setting = kzalloc( + power_setting_array->size * + sizeof(struct msm_sensor_power_setting), GFP_KERNEL); + if (!power_setting_array->power_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(power_setting_array->power_setting, + (void *) + sensor_slave_info.power_setting_array.power_setting, + power_setting_array->size * + sizeof(struct msm_sensor_power_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + power_setting_array->size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + power_setting_array->power_setting[slave_index]. + seq_type, + power_setting_array->power_setting[slave_index]. + seq_val, + power_setting_array->power_setting[slave_index]. + config_val, + power_setting_array->power_setting[slave_index]. + delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + if (conf_array.addr_type == MSM_CAMERA_I2C_WORD_ADDR + || conf_array.data_type == MSM_CAMERA_I2C_WORD_DATA + || !conf_array.size) + break; + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down( + s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, + stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + return rc; +} + +static struct msm_sensor_fn_t gc0339_sensor_fn_t = { + .sensor_power_up = gc0339_power_up, + .sensor_power_down = gc0339_power_down, + .sensor_match_id = gc0339_match_id, + .sensor_config = gc0339_config, +}; + + +static struct msm_sensor_ctrl_t gc0339_s_ctrl = { + .sensor_i2c_client = &gc0339_sensor_i2c_client, + .power_setting_array.power_setting = gc0339_power_setting, + .power_setting_array.size = ARRAY_SIZE(gc0339_power_setting), + .msm_sensor_mutex = &gc0339_mut, + .sensor_v4l2_subdev_info = gc0339_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(gc0339_subdev_info), + .func_tbl = &gc0339_sensor_fn_t, +}; + +static const struct of_device_id gc0339_dt_match[] = { + {.compatible = "shinetech,gc0339", .data = &gc0339_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, gc0339_dt_match); + +static struct platform_driver gc0339_platform_driver = { + .driver = { + .name = "shinetech,gc0339", + .owner = THIS_MODULE, + .of_match_table = gc0339_dt_match, + }, +}; + +static int32_t gc0339_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + + match = of_match_device(gc0339_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init gc0339_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_probe(&gc0339_platform_driver, + gc0339_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&gc0339_i2c_driver); +} + +static void __exit gc0339_exit_module(void) +{ + if (gc0339_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&gc0339_s_ctrl); + platform_driver_unregister(&gc0339_platform_driver); + } else + i2c_del_driver(&gc0339_i2c_driver); + return; +} + +module_init(gc0339_init_module); +module_exit(gc0339_exit_module); +MODULE_DESCRIPTION("gc0339"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/hi256.c b/drivers/media/platform/msm/camera_v2_j5/sensor/hi256.c new file mode 100755 index 0000000000000000000000000000000000000000..e61f57a3927d37fdcd6220a5b04eb9efe11a4dbe --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/hi256.c @@ -0,0 +1,2157 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#define HI256_SENSOR_NAME "hi256" +#define PLATFORM_DRIVER_NAME "msm_camera_hi256" + +#define CONFIG_MSMB_CAMERA_DEBUG +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + + +DEFINE_MSM_MUTEX(hi256_mut); +static struct msm_sensor_ctrl_t hi256_s_ctrl; + +static struct msm_sensor_power_setting hi256_power_setting[] = { + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf hi256_uxga_settings[] = { + {0x03, 0x00}, + {0x01, 0xf1}, + {0x03, 0x20}, + {0x10, 0x1c}, + {0x03, 0x22}, + {0x10, 0x69}, + {0x03, 0x00}, + {0x12, 0x00}, + {0x20, 0x00}, + {0x21, 0x0a}, + {0x22, 0x00}, + {0x23, 0x0a}, + {0x40, 0x01}, + {0x41, 0x68}, + {0x42, 0x00}, + {0x43, 0x12}, + {0x03, 0x10}, + {0x3f, 0x00}, + {0x03, 0x12}, + {0x20, 0x0f}, + {0x21, 0x0f}, + {0x90, 0x5d}, + {0x03, 0x13}, + {0x80, 0xfd}, + {0x03, 0x00}, + {0x10, 0x00}, + {0x03, 0x48}, + {0x72, 0x81}, + {0x30, 0x0c}, + {0x31, 0x80}, + {0x03, 0x00}, + {0x01, 0xf0}, +}; + +static struct msm_camera_i2c_reg_conf hi256_start_settings[] = { + {0x03, 0x00}, + {0x01, 0xf0}, +}; + +static struct msm_camera_i2c_reg_conf hi256_stop_settings[] = { + {0x03, 0x00}, + {0x01, 0xf1}, +}; + +static struct msm_camera_i2c_reg_conf hi256_recommend_settings[] = { + {0x01, 0xf1}, + {0x01, 0xf3}, + {0x01, 0xf1}, + + {0x08, 0x0f}, + {0x0a, 0x00}, + + {0x03, 0x20}, + {0x10, 0x1c}, + {0x03, 0x22}, + {0x10, 0x69}, + + {0x03, 0x00}, + {0x10, 0x13}, + {0x11, 0x90}, /* no H/V flip */ + {0x12, 0x00}, + {0x0b, 0xaa}, + {0x0c, 0xaa}, + {0x0d, 0xaa}, + {0x20, 0x00}, + {0x21, 0x06}, + {0x22, 0x00}, + {0x23, 0x05}, + {0x24, 0x04}, + {0x25, 0xb0}, + {0x26, 0x06}, + {0x27, 0x40}, + {0x40, 0x01}, + {0x41, 0x78}, + {0x42, 0x00}, + {0x43, 0x14}, + {0x45, 0x04}, + {0x46, 0x18}, + {0x47, 0xd8}, + {0x80, 0x2e}, + {0x81, 0x7e}, + {0x82, 0x90}, + {0x83, 0x00}, + {0x84, 0x0c}, + {0x85, 0x00}, + {0x90, 0x0c}, + {0x91, 0x0c}, + {0x92, 0x78}, + {0x93, 0x70}, + {0x94, 0xff}, + {0x95, 0xff}, + {0x96, 0xdc}, + {0x97, 0xfe}, + {0x98, 0x38}, + {0xa0, 0x45}, + {0xa2, 0x45}, + {0xa4, 0x45}, + {0xa6, 0x45}, + {0xa8, 0x45}, + {0xaa, 0x45}, + {0xac, 0x45}, + {0xae, 0x45}, + {0x99, 0x43}, + {0x9a, 0x43}, + {0x9b, 0x43}, + {0x9c, 0x43}, + {0x03, 0x02}, + {0x12, 0x03}, + {0x13, 0x03}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x17, 0x8C}, + {0x18, 0x4c}, + {0x19, 0x00}, + {0x1a, 0x39}, + {0x1c, 0x09}, + {0x1d, 0x40}, + {0x1e, 0x30}, + {0x1f, 0x10}, + {0x20, 0x77}, + {0x21, 0x6d}, + {0x22, 0x77}, + {0x23, 0x30}, + {0x24, 0x77}, + {0x27, 0x3c}, + {0x2b, 0x80}, + {0x2e, 0x00}, + {0x2f, 0x00}, + {0x30, 0x05}, + {0x50, 0x20}, + {0x52, 0x01}, + {0x53, 0xc1}, + {0x55, 0x1c}, + {0x56, 0x11}, + {0x58, 0x22}, + {0x59, 0x20}, + {0x5d, 0xa2}, + {0x5e, 0x5a}, + {0x60, 0x87}, + {0x61, 0x99}, + {0x62, 0x88}, + {0x63, 0x97}, + {0x64, 0x88}, + {0x65, 0x97}, + {0x67, 0x0c}, + {0x68, 0x0c}, + {0x69, 0x0c}, + {0x72, 0x89}, + {0x73, 0x96}, + {0x74, 0x89}, + {0x75, 0x96}, + {0x76, 0x89}, + {0x77, 0x96}, + {0x7c, 0x85}, + {0x7d, 0xaf}, + {0x80, 0x01}, + {0x81, 0x7f}, + {0x82, 0x13}, + {0x83, 0x24}, + {0x84, 0x7d}, + {0x85, 0x81}, + {0x86, 0x7d}, + {0x87, 0x81}, + {0x92, 0x48}, + {0x93, 0x54}, + {0x94, 0x7d}, + {0x95, 0x81}, + {0x96, 0x7d}, + {0x97, 0x81}, + {0xa0, 0x02}, + {0xa1, 0x7b}, + {0xa2, 0x02}, + {0xa3, 0x7b}, + {0xa4, 0x7b}, + {0xa5, 0x02}, + {0xa6, 0x7b}, + {0xa7, 0x02}, + {0xa8, 0x85}, + {0xa9, 0x8c}, + {0xaa, 0x85}, + {0xab, 0x8c}, + {0xac, 0x10}, + {0xad, 0x16}, + {0xae, 0x10}, + {0xaf, 0x16}, + {0xb0, 0x99}, + {0xb1, 0xa3}, + {0xb2, 0xa4}, + {0xb3, 0xae}, + {0xb4, 0x9b}, + {0xb5, 0xa2}, + {0xb6, 0xa6}, + {0xb7, 0xac}, + {0xb8, 0x9b}, + {0xb9, 0x9f}, + {0xba, 0xa6}, + {0xbb, 0xaa}, + {0xbc, 0x9b}, + {0xbd, 0x9f}, + {0xbe, 0xa6}, + {0xbf, 0xaa}, + {0xc4, 0x2c}, + {0xc5, 0x43}, + {0xc6, 0x63}, + {0xc7, 0x79}, + {0xc8, 0x2d}, + {0xc9, 0x42}, + {0xca, 0x2d}, + {0xcb, 0x42}, + {0xcc, 0x64}, + {0xcd, 0x78}, + {0xce, 0x64}, + {0xcf, 0x78}, + {0xd0, 0x0a}, + {0xd1, 0x09}, + {0xd4, 0x0c}, + {0xd5, 0x0c}, + {0xd6, 0x78}, + {0xd7, 0x70}, + {0xe0, 0xc4}, + {0xe1, 0xc4}, + {0xe2, 0xc4}, + {0xe3, 0xc4}, + {0xe4, 0x00}, + {0xe8, 0x80}, + {0xe9, 0x40}, + {0xea, 0x7f}, + {0xf0, 0xc1}, + {0xf1, 0xc1}, + {0xf2, 0xc1}, + {0xf3, 0xc1}, + {0xf4, 0xc1}, + {0x03, 0x03}, + {0x10, 0x10}, + {0x03, 0x10}, + {0x10, 0x03}, + {0x12, 0x30}, + {0x13, 0x02}, + {0x20, 0x00}, + {0x30, 0x00}, + {0x31, 0x00}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x30}, + {0x35, 0x00}, + {0x36, 0x00}, + {0x38, 0x00}, + {0x3e, 0x58}, + {0x3f, 0x00}, + {0x40, 0x80}, + {0x41, 0x00}, + {0x48, 0x95}, + {0x60, 0x67}, + {0x61, 0x88}, + {0x62, 0x90}, + {0x63, 0x50}, + {0x64, 0x41}, + {0x66, 0x42}, + {0x67, 0x20}, + {0x6a, 0x71}, + {0x6b, 0x84}, + {0x6c, 0x72}, + {0x6d, 0x83}, + {0x03, 0x11}, + {0x10, 0x7f}, + {0x11, 0x40}, + {0x12, 0x0a}, + {0x13, 0xbb}, + {0x26, 0x31}, + {0x27, 0x34}, + {0x28, 0x0f}, + {0x29, 0x10}, + {0x2b, 0x30}, + {0x2c, 0x32}, + {0x30, 0x70}, + {0x31, 0x10}, + {0x32, 0x58}, + {0x33, 0x09}, + {0x34, 0x06}, + {0x35, 0x03}, + {0x36, 0x70}, + {0x37, 0x18}, + {0x38, 0x58}, + {0x39, 0x09}, + {0x3a, 0x06}, + {0x3b, 0x03}, + {0x3c, 0x80}, + {0x3d, 0x18}, + {0x3e, 0x80}, + {0x3f, 0x0c}, + {0x40, 0x05}, + {0x41, 0x06}, + {0x42, 0x80}, + {0x43, 0x18}, + {0x44, 0x80}, + {0x45, 0x0c}, + {0x46, 0x05}, + {0x47, 0x06}, + {0x48, 0x90}, + {0x49, 0x40}, + {0x4a, 0x80}, + {0x4b, 0x13}, + {0x4c, 0x10}, + {0x4d, 0x11}, + {0x4e, 0x80}, + {0x4f, 0x30}, + {0x50, 0x80}, + {0x51, 0x13}, + {0x52, 0x10}, + {0x53, 0x13}, + {0x54, 0x11}, + {0x55, 0x17}, + {0x56, 0x20}, + {0x57, 0x01}, + {0x58, 0x00}, + {0x59, 0x00}, + {0x5a, 0x18}, + {0x5b, 0x00}, + {0x5c, 0x00}, + {0x60, 0x3f}, + {0x62, 0x60}, + {0x70, 0x06}, + {0x03, 0x12}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x25, 0x00}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2a, 0x00}, + {0x30, 0x50}, + {0x31, 0x18}, + {0x32, 0x32}, + {0x33, 0x40}, + {0x34, 0x50}, + {0x35, 0x70}, + {0x36, 0xa0}, + {0x40, 0xa0}, + {0x41, 0x40}, + {0x42, 0xa0}, + {0x43, 0x90}, + {0x44, 0x90}, + {0x45, 0x80}, + {0x46, 0xb0}, + {0x47, 0x55}, + {0x48, 0xa0}, + {0x49, 0x90}, + {0x4a, 0x90}, + {0x4b, 0x80}, + {0x4c, 0xb0}, + {0x4d, 0x40}, + {0x4e, 0x90}, + {0x4f, 0x60}, + {0x50, 0xa0}, + {0x51, 0x80}, + {0x52, 0xb0}, + {0x53, 0x40}, + {0x54, 0x90}, + {0x55, 0x60}, + {0x56, 0xa0}, + {0x57, 0x80}, + {0x58, 0x90}, + {0x59, 0x40}, + {0x5a, 0xd0}, + {0x5b, 0xd0}, + {0x5c, 0xe0}, + {0x5d, 0x80}, + {0x5e, 0x88}, + {0x5f, 0x40}, + {0x60, 0xe0}, + {0x61, 0xe0}, + {0x62, 0xe0}, + {0x63, 0x80}, + {0x70, 0x15}, + {0x71, 0x01}, + {0x72, 0x18}, + {0x73, 0x01}, + {0x74, 0x25}, + {0x75, 0x15}, + {0x80, 0x20}, + {0x81, 0x40}, + {0x82, 0x65}, + {0x85, 0x1a}, + {0x88, 0x00}, + {0x89, 0x00}, + {0x90, 0x5d}, + {0xD0, 0x0c}, + {0xD1, 0x80}, + {0xD2, 0x17}, + {0xD3, 0x00}, + {0xD4, 0x00}, + {0xD5, 0x0f}, + {0xD6, 0xff}, + {0xD7, 0xff}, + {0x3b, 0x06}, + {0x3c, 0x06}, + {0xc5, 0x00}, + {0xc6, 0x00}, + {0x03, 0x13}, + {0x10, 0xcb}, + {0x11, 0x7b}, + {0x12, 0x07}, + {0x14, 0x00}, + {0x20, 0x15}, + {0x21, 0x13}, + {0x22, 0x33}, + {0x23, 0x05}, + {0x24, 0x09}, + {0x25, 0x0a}, + {0x26, 0x18}, + {0x27, 0x30}, + {0x29, 0x12}, + {0x2a, 0x50}, + {0x2b, 0x02}, + {0x2c, 0x02}, + {0x25, 0x06}, + {0x2d, 0x0c}, + {0x2e, 0x12}, + {0x2f, 0x12}, + {0x50, 0x10}, + {0x51, 0x14}, + {0x52, 0x12}, + {0x53, 0x0c}, + {0x54, 0x0f}, + {0x55, 0x0c}, + {0x56, 0x10}, + {0x57, 0x13}, + {0x58, 0x12}, + {0x59, 0x0c}, + {0x5a, 0x0f}, + {0x5b, 0x0c}, + {0x5c, 0x25}, + {0x5d, 0x25}, + {0x5e, 0x25}, + {0x5f, 0x25}, + {0x60, 0x25}, + {0x61, 0x25}, + {0x62, 0x25}, + {0x63, 0x25}, + {0x64, 0x25}, + {0x65, 0x25}, + {0x66, 0x25}, + {0x67, 0x25}, + {0x68, 0x07}, + {0x69, 0x07}, + {0x6a, 0x07}, + {0x6b, 0x05}, + {0x6c, 0x05}, + {0x6d, 0x05}, + {0x6e, 0x07}, + {0x6f, 0x07}, + {0x70, 0x07}, + {0x71, 0x05}, + {0x72, 0x05}, + {0x73, 0x05}, + {0x80, 0x01}, + {0x81, 0x1f}, + {0x82, 0x05}, + {0x83, 0x31}, + {0x90, 0x05}, + {0x91, 0x05}, + {0x92, 0x33}, + {0x93, 0x30}, + {0x94, 0x03}, + {0x95, 0x14}, + {0x97, 0x20}, + {0x99, 0x20}, + {0xa0, 0x01}, + {0xa1, 0x02}, + {0xa2, 0x01}, + {0xa3, 0x02}, + {0xa4, 0x05}, + {0xa5, 0x05}, + {0xa6, 0x07}, + {0xa7, 0x08}, + {0xa8, 0x07}, + {0xa9, 0x08}, + {0xaa, 0x07}, + {0xab, 0x08}, + {0xb0, 0x22}, + {0xb1, 0x2a}, + {0xb2, 0x28}, + {0xb3, 0x22}, + {0xb4, 0x2a}, + {0xb5, 0x28}, + {0xb6, 0x22}, + {0xb7, 0x2a}, + {0xb8, 0x28}, + {0xb9, 0x22}, + {0xba, 0x2a}, + {0xbb, 0x28}, + {0xbc, 0x25}, + {0xbd, 0x2a}, + {0xbe, 0x27}, + {0xbf, 0x25}, + {0xc0, 0x2a}, + {0xc1, 0x27}, + {0xc2, 0x1e}, + {0xc3, 0x24}, + {0xc4, 0x20}, + {0xc5, 0x1e}, + {0xc6, 0x24}, + {0xc7, 0x20}, + {0xc8, 0x18}, + {0xc9, 0x20}, + {0xca, 0x1e}, + {0xcb, 0x18}, + {0xcc, 0x20}, + {0xcd, 0x1e}, + {0xce, 0x18}, + {0xcf, 0x20}, + {0xd0, 0x1e}, + {0xd1, 0x18}, + {0xd2, 0x20}, + {0xd3, 0x1e}, + {0x03, 0x14}, + {0x10, 0x11}, + {0x14, 0x80}, + {0x15, 0x80}, + {0x16, 0x80}, + {0x17, 0x80}, + {0x18, 0x80}, + {0x19, 0x80}, + {0x20, 0x80}, + {0x21, 0x80}, + {0x22, 0x80}, + {0x23, 0x80}, + {0x24, 0x80}, + {0x30, 0xc8}, + {0x31, 0x2b}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x90}, + {0x40, 0x32}, + {0x50, 0x21}, + {0x60, 0x19}, + {0x70, 0x21}, + {0x03, 0x15}, + {0x10, 0x0f}, + {0x14, 0x46}, + {0x15, 0x36}, + {0x16, 0x26}, + {0x17, 0x2f}, + {0x30, 0x8f}, + {0x31, 0x59}, + {0x32, 0x0a}, + {0x33, 0x15}, + {0x34, 0x5b}, + {0x35, 0x06}, + {0x36, 0x07}, + {0x37, 0x40}, + {0x38, 0x87}, + {0x40, 0x94}, + {0x41, 0x20}, + {0x42, 0x89}, + {0x43, 0x84}, + {0x44, 0x03}, + {0x45, 0x01}, + {0x46, 0x88}, + {0x47, 0x9c}, + {0x48, 0x28}, + {0x50, 0x02}, + {0x51, 0x82}, + {0x52, 0x00}, + {0x53, 0x07}, + {0x54, 0x11}, + {0x55, 0x98}, + {0x56, 0x00}, + {0x57, 0x0b}, + {0x58, 0x8b}, + {0x80, 0x03}, + {0x85, 0x40}, + {0x87, 0x02}, + {0x88, 0x00}, + {0x89, 0x00}, + {0x8a, 0x00}, + {0x03, 0x16}, + {0x10, 0x31}, + {0x18, 0x5e}, + {0x19, 0x5d}, + {0x1a, 0x0e}, + {0x1b, 0x01}, + {0x1c, 0xdc}, + {0x1d, 0xfe}, + {0x30, 0x00}, + {0x31, 0x0a}, + {0x32, 0x1f}, + {0x33, 0x33}, + {0x34, 0x53}, + {0x35, 0x6c}, + {0x36, 0x81}, + {0x37, 0x94}, + {0x38, 0xa4}, + {0x39, 0xb3}, + {0x3a, 0xc0}, + {0x3b, 0xcb}, + {0x3c, 0xd5}, + {0x3d, 0xde}, + {0x3e, 0xe6}, + {0x3f, 0xee}, + {0x40, 0xf5}, + {0x41, 0xfc}, + {0x42, 0xff}, + {0x50, 0x00}, + {0x51, 0x08}, + {0x52, 0x1e}, + {0x53, 0x36}, + {0x54, 0x5a}, + {0x55, 0x75}, + {0x56, 0x8d}, + {0x57, 0xa1}, + {0x58, 0xb2}, + {0x59, 0xbe}, + {0x5a, 0xc9}, + {0x5b, 0xd2}, + {0x5c, 0xdb}, + {0x5d, 0xe3}, + {0x5e, 0xeb}, + {0x5f, 0xf0}, + {0x60, 0xf5}, + {0x61, 0xf7}, + {0x62, 0xf8}, + {0x70, 0x00}, + {0x71, 0x08}, + {0x72, 0x17}, + {0x73, 0x2f}, + {0x74, 0x53}, + {0x75, 0x6c}, + {0x76, 0x81}, + {0x77, 0x94}, + {0x78, 0xa4}, + {0x79, 0xb3}, + {0x7a, 0xc0}, + {0x7b, 0xcb}, + {0x7c, 0xd5}, + {0x7d, 0xde}, + {0x7e, 0xe6}, + {0x7f, 0xee}, + {0x80, 0xf4}, + {0x81, 0xfa}, + {0x82, 0xff}, + {0x03, 0x17}, + {0x10, 0xf7}, + {0xC4, 0x66}, + {0xC5, 0x55}, + {0x03, 0x20}, + {0x11, 0x1c}, + {0x18, 0x30}, + {0x1a, 0x08}, + {0x20, 0x05}, + {0x21, 0x30}, + {0x22, 0x10}, + {0x23, 0x00}, + {0x24, 0x00}, + {0x28, 0xe7}, + {0x29, 0x0d}, + {0x2a, 0xf0}, + {0x2b, 0x34}, + {0x30, 0x78}, + {0x2c, 0xc2}, + {0x2d, 0xff}, + {0x2e, 0x33}, + {0x30, 0x78}, + {0x32, 0x03}, + {0x33, 0x2e}, + {0x34, 0x30}, + {0x35, 0xd4}, + {0x36, 0xfe}, + {0x37, 0x32}, + {0x38, 0x04}, + {0x39, 0x22}, + {0x3a, 0xde}, + {0x3b, 0x22}, + {0x3c, 0xde}, + {0x50, 0x45}, + {0x51, 0x88}, + {0x56, 0x03}, + {0x57, 0xf7}, + {0x58, 0x14}, + {0x59, 0x88}, + {0x5a, 0x04}, + {0x60, 0xaa}, + {0x61, 0xaa}, + {0x62, 0xaa}, + {0x63, 0xaa}, + {0x64, 0xaa}, + {0x65, 0xaa}, + {0x66, 0xab}, + {0x67, 0xEa}, + {0x68, 0xab}, + {0x69, 0xEa}, + {0x6a, 0xaa}, + {0x6b, 0xaa}, + {0x6c, 0xaa}, + {0x6d, 0xaa}, + {0x6e, 0xaa}, + {0x6f, 0xaa}, + {0x70, 0x76}, + {0x71, 0x80}, + {0x76, 0x43}, + {0x77, 0x04}, + {0x78, 0x23}, + {0x79, 0x46}, + {0x7a, 0x23}, + {0x7b, 0x22}, + {0x7d, 0x23}, + {0x83, 0x01}, + {0x84, 0x5f}, + {0x85, 0x90}, + {0x86, 0x01}, + {0x87, 0x2c}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x8B, 0x75}, + {0x8C, 0x30}, + {0x8D, 0x61}, + {0x8E, 0x44}, + {0x9c, 0x08}, + {0x9d, 0x34}, + {0x9e, 0x01}, + {0x9f, 0x2c}, + {0xb0, 0x18}, + {0xb1, 0x14}, + {0xb2, 0x80}, + {0xb3, 0x18}, + {0xb4, 0x1a}, + {0xb5, 0x44}, + {0xb6, 0x2f}, + {0xb7, 0x28}, + {0xb8, 0x25}, + {0xb9, 0x22}, + {0xba, 0x21}, + {0xbb, 0x20}, + {0xbc, 0x32}, + {0xbd, 0x30}, + {0xc0, 0x10}, + {0xc1, 0x2b}, + {0xc2, 0x2b}, + {0xc3, 0x2b}, + {0xc4, 0x08}, + {0xc8, 0x40}, + {0xc9, 0x40}, + {0x03, 0x22}, + {0x10, 0xfd}, + {0x11, 0x2e}, + {0x19, 0x01}, + {0x20, 0x10}, + {0x21, 0x80}, + {0x24, 0x01}, + {0x30, 0x80}, + {0x31, 0x80}, + {0x38, 0x11}, + {0x39, 0x34}, + {0x40, 0xfa}, + {0x41, 0x44}, + {0x42, 0x43}, + {0x43, 0xf6}, + {0x44, 0x44}, + {0x45, 0x33}, + {0x46, 0x00}, + {0x50, 0xb2}, + {0x51, 0x81}, + {0x52, 0x98}, + {0x80, 0x38}, + {0x81, 0x20}, + {0x82, 0x38}, + {0x83, 0x5e}, + {0x84, 0x18}, + {0x85, 0x58}, + {0x86, 0x20}, + {0x87, 0x49}, + {0x88, 0x33}, + {0x89, 0x37}, + {0x8a, 0x2a}, + {0x8b, 0x41}, + {0x8c, 0x39}, + {0x8d, 0x34}, + {0x8e, 0x29}, + {0x8f, 0x53}, + {0x90, 0x52}, + {0x91, 0x51}, + {0x92, 0x4e}, + {0x93, 0x46}, + {0x94, 0x3d}, + {0x95, 0x34}, + {0x96, 0x2e}, + {0x97, 0x29}, + {0x98, 0x22}, + {0x99, 0x1c}, + {0x9a, 0x18}, + {0x9b, 0x77}, + {0x9c, 0x77}, + {0x9d, 0x48}, + {0x9e, 0x38}, + {0x9f, 0x30}, + {0xa0, 0x60}, + {0xa1, 0x34}, + {0xa2, 0x6f}, + {0xa3, 0xff}, + {0xa4, 0x14}, + {0xa5, 0x2c}, + {0xa6, 0xcf}, + {0xad, 0x40}, + {0xae, 0x4a}, + {0xaf, 0x28}, + {0xb0, 0x26}, + {0xb1, 0x00}, + {0xb4, 0xea}, + {0xb8, 0xa0}, + {0xb9, 0x00}, + {0x03, 0x48}, + {0x70, 0x03}, + {0x71, 0x30}, + {0x72, 0x81}, + {0x73, 0x10}, + {0x70, 0x85}, + {0x03, 0x48}, + {0x03, 0x48}, + {0x03, 0x48}, + {0x03, 0x48}, + {0x70, 0x95}, + {0x10, 0x1c}, + {0x11, 0x10}, + {0x12, 0x00}, + {0x14, 0x00}, + {0x16, 0x04}, + {0x18, 0x80}, + {0x19, 0x00}, + {0x1a, 0xa0}, + {0x1b, 0x0d}, + {0x1c, 0x01}, + {0x1d, 0x0a}, + {0x1e, 0x07}, + {0x1f, 0x0b}, + {0x23, 0x01}, + {0x24, 0x1e}, + {0x25, 0x00}, + {0x26, 0x00}, + {0x27, 0x08}, + {0x28, 0x00}, + {0x30, 0x06}, + {0x31, 0x40}, + {0x32, 0x13}, + {0x33, 0x0c}, + {0x34, 0x04}, + {0x35, 0x06}, + {0x36, 0x01}, + {0x37, 0x06}, + {0x39, 0x4f}, + {0x03, 0x20}, + {0x10, 0x9c}, + {0x03, 0x22}, + {0x10, 0xe9}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x03, 0x00}, + {0x0e, 0x03}, + {0x0e, 0x73}, + {0x03, 0x00}, + {0x01, 0xf0}, +}; + +static struct v4l2_subdev_info hi256_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf hi256_svga_settings[] = { + {0x03, 0x20}, + {0x10, 0x1c}, + {0x03, 0x22}, + {0x10, 0x69}, + {0x03, 0x00}, + {0x10, 0x13}, + {0x12, 0x00}, + {0x20, 0x00}, + {0x21, 0x04}, + {0x22, 0x00}, + {0x23, 0x07}, + {0x40, 0x01}, + {0x41, 0x78}, + {0x42, 0x00}, + {0x43, 0x14}, + {0x03, 0x10}, + {0x3f, 0x02}, + {0x03, 0x12}, + {0x20, 0x0f}, + {0x21, 0x0f}, + {0x90, 0x5d}, + {0x03, 0x13}, + {0x80, 0x00}, + {0x03, 0x48}, + {0x72, 0x81}, + {0x30, 0x06}, + {0x31, 0x40}, + {0x03, 0x20}, + {0x88, 0x01}, + {0x89, 0x5f}, + {0x8a, 0x90}, + {0x03, 0x20}, + {0x10, 0x9c}, + {0x03, 0x22}, + {0x10, 0xe9}, +}; + +static struct msm_camera_i2c_reg_conf hi256_sleep_settings[] = { + + {0x03, 0x00}, + {0x01, 0xf1}, + {0x03, 0x02}, + {0x55, 0x10}, + + {0x01, 0xf1}, + {0x01, 0xf3}, + {0x01, 0xf1}, + +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_saturation[11][3] = { + { + {0x03, 0x10}, + {0x61, 0x1c}, + {0x62, 0x1c}, + }, + { + {0x03, 0x10}, + {0x61, 0x30}, + {0x62, 0x30}, + }, + { + {0x03, 0x10}, + {0x61, 0x44}, + {0x62, 0x44}, + }, + { + {0x03, 0x10}, + {0x61, 0x58}, + {0x62, 0x58}, + }, + { + {0x03, 0x10}, + {0x61, 0x6c}, + {0x62, 0x6c}, + }, + { + {0x03, 0x10}, + {0x61, 0x80}, + {0x62, 0x80}, + }, + { + {0x03, 0x10}, + {0x61, 0x94}, + {0x62, 0x94}, + }, + { + {0x03, 0x10}, + {0x61, 0xa8}, + {0x62, 0xa8}, + }, + { + {0x03, 0x10}, + {0x61, 0xbc}, + {0x62, 0xbc}, + }, + { + {0x03, 0x10}, + {0x61, 0xd0}, + {0x62, 0xd0}, + }, + { + {0x03, 0x10}, + {0x61, 0xe4}, + {0x62, 0xe4}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_contrast[11][3] = { + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x1c}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x30}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x44}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x58}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x6c}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x80}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0x94}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xa8}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xbc}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xd0}, + }, + { + {0x03, 0x10}, + {0x13, 0x02}, + {0x48, 0xe4}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_sharpness[7][9] = { + { + {0x03, 0x13}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0x00}, + {0x91, 0x00}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 0*/ + { + {0x03, 0x13}, + {0x20, 0x04}, + {0x21, 0x03}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0x08}, + {0x91, 0x08}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 1*/ + { + {0x03, 0x13}, + {0x20, 0x08}, + {0x21, 0x07}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0x32}, + {0x91, 0x32}, + {0x94, 0x04}, + {0x95, 0x0a}, + }, /* SHARPNESS LEVEL 2*/ + { + {0x03, 0x13}, + {0x20, 0x15}, + {0x21, 0x15}, + {0x23, 0x09}, + {0x24, 0x11}, + {0x90, 0x05}, + {0x91, 0x05}, + {0x94, 0x10}, + {0x95, 0x5a}, + }, /* SHARPNESS LEVEL 3*/ + { + {0x03, 0x13}, + {0x20, 0x15}, + {0x21, 0x15}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0xaf}, + {0x91, 0xaf}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 4*/ + { + {0x03, 0x13}, + {0x20, 0x20}, + {0x21, 0x20}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0xdf}, + {0x91, 0xdf}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 5*/ + { + {0x03, 0x13}, + {0x20, 0x25}, + {0x21, 0x25}, + {0x23, 0x04}, + {0x24, 0x80}, + {0x90, 0xff}, + {0x91, 0xff}, + {0x94, 0x24}, + {0x95, 0x65}, + }, /* SHARPNESS LEVEL 6*/ +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_iso[7][3] = { + /* auto */ + { + {0x03, 0x20}, + {0x10, 0x9c}, + {0xb0, 0x18}, + }, + /* auto hjt */ + { + {0x03, 0x20}, + {0x10, 0x9c}, + {0xb0, 0x18}, + }, + /* iso 100 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x1B}, + }, + /* iso 200 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x35}, + }, + /* iso 400 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x65}, + }, + /* iso 800 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0x95}, + }, + /* iso 1600 */ + { + {0x03, 0x20}, + {0x10, 0x0c}, + {0xb0, 0xd0}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_exposure_compensation[5][2] = { + /* -2 */ + { + {0x03, 0x10}, + {0x40, 0xa4}, + }, + /* -1 */ + { + {0x03, 0x10}, + {0x40, 0x94}, + }, + /* 0 */ + { + {0x03, 0x10}, + {0x40, 0x80}, + }, + /* 1 */ + { + {0x03, 0x10}, + {0x40, 0x14}, + }, + /* 2 */ + { + {0x03, 0x10}, + {0x40, 0x24}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_antibanding[][2] = { + /* OFF */ + { + {0x03, 0x20}, + {0x10, 0xcc}, + }, + /* 50Hz */ + { + {0x03, 0x20}, + {0x10, 0x9c}, + }, + /* 60Hz */ + { + {0x03, 0x20}, + {0x10, 0x8c}, + }, + /* AUTO */ + { + {0x03, 0x20}, + {0x10, 0xcc}, + }, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_normal[] = { + /* normal: */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0X30}, + {0x13, 0x0a}, + {0x44, 0x80}, + {0x45, 0x80}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_black_white[] = { + /* B&W: */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x33}, + {0x13, 0x02}, + {0x44, 0x80}, + {0x45, 0x80}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_negative[] = { + /* Negative: */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x08}, + {0x13, 0x0a}, + {0x14, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_old_movie[] = { + /* Sepia(antique): */ + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x03}, + {0x12, 0x33}, + {0x13, 0x0a}, + {0x44, 0x25}, + {0x45, 0xa6}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_effect_solarize[] = { + {0x03, 0x20}, + {0x28, 0xe7}, + {0x03, 0x10}, + {0x11, 0x0b}, + {0x12, 0x00}, + {0x13, 0x00}, + {0x14, 0x00}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_auto[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_portrait[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_landscape[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x05}, + {0x89, 0x7e}, + {0x8a, 0x40}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_scene_night[] = { + /* */ + {0x03, 0x20}, + {0x10, 0x1c}, + {0x18, 0x38}, + {0x88, 0x09}, + {0x89, 0x27}, + {0x8a, 0xc0}, + {0x10, 0x9c}, + {0x18, 0x30}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_auto[] = { + /* Auto: */ + {0x03, 0x22}, + {0x11, 0x2e}, + {0x83, 0x60}, + {0x84, 0x0a}, + {0x85, 0x60}, + {0x86, 0x15}, + {0x10, 0xfd}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_sunny[] = { + /* Sunny: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x33}, + {0x82, 0x3d}, + {0x83, 0x2e}, + {0x84, 0x24}, + {0x85, 0x43}, + {0x86, 0x3d}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_cloudy[] = { + /* Cloudy: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x49}, + {0x82, 0x24}, + {0x83, 0x50}, + {0x84, 0x45}, + {0x85, 0x24}, + {0x86, 0x1E}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_office[] = { + /* Office: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x20}, + {0x82, 0x58}, + {0x83, 0x27}, + {0x84, 0x22}, + {0x85, 0x58}, + {0x86, 0x52}, +}; + +static struct msm_camera_i2c_reg_conf HI256_reg_wb_home[] = { + /* Home: */ + {0x03, 0x22}, + {0x11, 0x28}, + {0x80, 0x29}, + {0x82, 0x54}, + {0x83, 0x2e}, + {0x84, 0x23}, + {0x85, 0x58}, + {0x86, 0x4f}, +}; + + +static const struct i2c_device_id hi256_i2c_id[] = { + {HI256_SENSOR_NAME, (kernel_ulong_t)&hi256_s_ctrl}, + { } +}; + +static int32_t msm_hi256_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &hi256_s_ctrl); +} + +static struct i2c_driver hi256_i2c_driver = { + .id_table = hi256_i2c_id, + .probe = msm_hi256_i2c_probe, + .driver = { + .name = HI256_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client hi256_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_BYTE_ADDR, +}; + +static const struct of_device_id hi256_dt_match[] = { + {.compatible = "shinetech,hi256", .data = &hi256_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, hi256_dt_match); + +static struct platform_driver hi256_platform_driver = { + .driver = { + .name = "shinetech,hi256", + .owner = THIS_MODULE, + .of_match_table = hi256_dt_match, + }, +}; + +static void hi256_i2c_write_table(struct msm_sensor_ctrl_t *s_ctrl, + struct msm_camera_i2c_reg_conf *table, + int num) +{ + int i = 0; + int rc = 0; + for (i = 0; i < num; ++i) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write( + s_ctrl->sensor_i2c_client, table->reg_addr, + table->reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + msleep(100); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write( + s_ctrl->sensor_i2c_client, table->reg_addr, + table->reg_data, + MSM_CAMERA_I2C_BYTE_DATA); + } + table++; + } +} + +static int32_t hi256_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) +{ + hi256_i2c_write_table(s_ctrl, &hi256_sleep_settings[0], + ARRAY_SIZE(hi256_sleep_settings)); + return msm_sensor_power_down(s_ctrl); +} + +static int32_t hi256_platform_probe(struct platform_device *pdev) +{ + int32_t rc; + const struct of_device_id *match; + match = of_match_device(hi256_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init hi256_init_module(void) +{ + int32_t rc; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&hi256_platform_driver, + hi256_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&hi256_i2c_driver); +} + +static void __exit hi256_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (hi256_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&hi256_s_ctrl); + platform_driver_unregister(&hi256_platform_driver); + } else + i2c_del_driver(&hi256_i2c_driver); + return; +} + +static int32_t hi256_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint16_t chipid = 0; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + s_ctrl->sensordata->slave_info->sensor_id_reg_addr, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: hi256 read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, + s_ctrl->sensordata->slave_info->sensor_id); + if (chipid != s_ctrl->sensordata->slave_info->sensor_id) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + return rc; +} + +static void hi256_set_stauration(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_saturation[value][0], + ARRAY_SIZE(HI256_reg_saturation[value])); +} + +static void hi256_set_contrast(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_contrast[value][0], + ARRAY_SIZE(HI256_reg_contrast[value])); +} + +static void hi256_set_sharpness(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + int val = value / 6; + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_sharpness[val][0], + ARRAY_SIZE(HI256_reg_sharpness[val])); +} + + +static void hi256_set_iso(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_iso[value][0], + ARRAY_SIZE(HI256_reg_iso[value])); +} + +static void hi256_set_exposure_compensation(struct msm_sensor_ctrl_t *s_ctrl, + int value) +{ + int val = (value + 12) / 6; + pr_debug("%s %d", __func__, val); + hi256_i2c_write_table(s_ctrl, &HI256_reg_exposure_compensation[val][0], + ARRAY_SIZE(HI256_reg_exposure_compensation[val])); +} + +static void hi256_set_effect(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + switch (value) { + case MSM_CAMERA_EFFECT_MODE_OFF: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0], + ARRAY_SIZE(HI256_reg_effect_normal)); + break; + } + case MSM_CAMERA_EFFECT_MODE_MONO: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_black_white[0], + ARRAY_SIZE(HI256_reg_effect_black_white)); + break; + } + case MSM_CAMERA_EFFECT_MODE_NEGATIVE: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_negative[0], + ARRAY_SIZE(HI256_reg_effect_negative)); + break; + } + case MSM_CAMERA_EFFECT_MODE_SEPIA: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_old_movie[0], + ARRAY_SIZE(HI256_reg_effect_old_movie)); + break; + } + case MSM_CAMERA_EFFECT_MODE_SOLARIZE: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_solarize[0], + ARRAY_SIZE(HI256_reg_effect_solarize)); + break; + } + default: + hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0], + ARRAY_SIZE(HI256_reg_effect_normal)); + } +} + +static void hi256_set_antibanding(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + hi256_i2c_write_table(s_ctrl, &HI256_reg_antibanding[value][0], + ARRAY_SIZE(HI256_reg_antibanding[value])); +} + +static void hi256_set_scene_mode(struct msm_sensor_ctrl_t *s_ctrl, int value) +{ + pr_debug("%s %d", __func__, value); + switch (value) { + case MSM_CAMERA_SCENE_MODE_OFF: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0], + ARRAY_SIZE(HI256_reg_scene_auto)); + break; + } + case MSM_CAMERA_SCENE_MODE_NIGHT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_night[0], + ARRAY_SIZE(HI256_reg_scene_night)); + break; + } + case MSM_CAMERA_SCENE_MODE_LANDSCAPE: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_landscape[0], + ARRAY_SIZE(HI256_reg_scene_landscape)); + break; + } + case MSM_CAMERA_SCENE_MODE_PORTRAIT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_portrait[0], + ARRAY_SIZE(HI256_reg_scene_portrait)); + break; + } + default: + hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0], + ARRAY_SIZE(HI256_reg_scene_auto)); + } +} + +static void hi256_set_white_balance_mode(struct msm_sensor_ctrl_t *s_ctrl, + int value) +{ + pr_debug("%s %d", __func__, value); + switch (value) { + case MSM_CAMERA_WB_MODE_AUTO: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0], + ARRAY_SIZE(HI256_reg_wb_auto)); + break; + } + case MSM_CAMERA_WB_MODE_INCANDESCENT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_home[0], + ARRAY_SIZE(HI256_reg_wb_home)); + break; + } + case MSM_CAMERA_WB_MODE_DAYLIGHT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_sunny[0], + ARRAY_SIZE(HI256_reg_wb_sunny)); + break; + } + case MSM_CAMERA_WB_MODE_FLUORESCENT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_office[0], + ARRAY_SIZE(HI256_reg_wb_office)); + break; + } + case MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT: { + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_cloudy[0], + ARRAY_SIZE(HI256_reg_wb_cloudy)); + break; + } + default: + hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0], + ARRAY_SIZE(HI256_reg_wb_auto)); + } +} + +int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + CDBG("init setting"); + hi256_i2c_write_table(s_ctrl, + &hi256_recommend_settings[0], + ARRAY_SIZE(hi256_recommend_settings)); + CDBG("init setting X"); + break; + case CFG_SET_RESOLUTION: { + int val = 0; + if (copy_from_user(&val, + (void *)cdata->cfg.setting, sizeof(int))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + if (val == 0) + hi256_i2c_write_table(s_ctrl, &hi256_uxga_settings[0], + ARRAY_SIZE(hi256_uxga_settings)); + else if (val == 1) + hi256_i2c_write_table(s_ctrl, &hi256_svga_settings[0], + ARRAY_SIZE(hi256_svga_settings)); + break; + } + case CFG_SET_STOP_STREAM: + hi256_i2c_write_table(s_ctrl, + &hi256_stop_settings[0], + ARRAY_SIZE(hi256_stop_settings)); + break; + case CFG_SET_START_STREAM: + hi256_i2c_write_table(s_ctrl, + &hi256_start_settings[0], + ARRAY_SIZE(hi256_start_settings)); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_sensor_power_setting_array *power_setting_array; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + s_ctrl->power_setting_array = + sensor_slave_info.power_setting_array; + power_setting_array = &s_ctrl->power_setting_array; + power_setting_array->power_setting = kzalloc( + power_setting_array->size * + sizeof(struct msm_sensor_power_setting), GFP_KERNEL); + if (!power_setting_array->power_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(power_setting_array->power_setting, + (void *) + sensor_slave_info.power_setting_array.power_setting, + power_setting_array->size * + sizeof(struct msm_sensor_power_setting))) { + kfree(power_setting_array->power_setting); + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + power_setting_array->size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + power_setting_array->power_setting[slave_index]. + seq_type, + power_setting_array->power_setting[slave_index]. + seq_val, + power_setting_array->power_setting[slave_index]. + config_val, + power_setting_array->power_setting[slave_index]. + delay); + } + kfree(power_setting_array->power_setting); + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_SATURATION: { + int32_t sat_lev; + if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Saturation Value is %d", __func__, sat_lev); + hi256_set_stauration(s_ctrl, sat_lev); + break; + } + case CFG_SET_CONTRAST: { + int32_t con_lev; + if (copy_from_user(&con_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Contrast Value is %d", __func__, con_lev); + hi256_set_contrast(s_ctrl, con_lev); + break; + } + case CFG_SET_SHARPNESS: { + int32_t shp_lev; + if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Sharpness Value is %d", __func__, shp_lev); + hi256_set_sharpness(s_ctrl, shp_lev); + break; + } + case CFG_SET_ISO: { + int32_t iso_lev; + if (copy_from_user(&iso_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: ISO Value is %d", __func__, iso_lev); + hi256_set_iso(s_ctrl, iso_lev); + break; + } + case CFG_SET_EXPOSURE_COMPENSATION: { + int32_t ec_lev; + if (copy_from_user(&ec_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Exposure compensation Value is %d", + __func__, ec_lev); + hi256_set_exposure_compensation(s_ctrl, ec_lev); + break; + } + case CFG_SET_EFFECT: { + int32_t effect_mode; + if (copy_from_user(&effect_mode, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Effect mode is %d", __func__, effect_mode); + hi256_set_effect(s_ctrl, effect_mode); + break; + } + case CFG_SET_ANTIBANDING: { + int32_t antibanding_mode; + if (copy_from_user(&antibanding_mode, + (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: anti-banding mode is %d", __func__, + antibanding_mode); + hi256_set_antibanding(s_ctrl, antibanding_mode); + break; + } + case CFG_SET_BESTSHOT_MODE: { + int32_t bs_mode; + if (copy_from_user(&bs_mode, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: best shot mode is %d", __func__, bs_mode); + hi256_set_scene_mode(s_ctrl, bs_mode); + break; + } + case CFG_SET_WHITE_BALANCE: { + int32_t wb_mode; + if (copy_from_user(&wb_mode, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: white balance is %d", __func__, wb_mode); + hi256_set_white_balance_mode(s_ctrl, wb_mode); + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +static struct msm_sensor_fn_t hi256_sensor_func_tbl = { + .sensor_config = hi256_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = hi256_sensor_power_down, + .sensor_match_id = hi256_sensor_match_id, +}; + +static struct msm_sensor_ctrl_t hi256_s_ctrl = { + .sensor_i2c_client = &hi256_sensor_i2c_client, + .power_setting_array.power_setting = hi256_power_setting, + .power_setting_array.size = ARRAY_SIZE(hi256_power_setting), + .msm_sensor_mutex = &hi256_mut, + .sensor_v4l2_subdev_info = hi256_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(hi256_subdev_info), + .func_tbl = &hi256_sensor_func_tbl, +}; + +module_init(hi256_init_module); +module_exit(hi256_exit_module); +MODULE_DESCRIPTION("Hi256 2MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/imx132.c b/drivers/media/platform/msm/camera_v2_j5/sensor/imx132.c new file mode 100755 index 0000000000000000000000000000000000000000..f9d057ac403c8730258641ab0f6d3d24e49ae422 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/imx132.c @@ -0,0 +1,154 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define IMX132_SENSOR_NAME "imx132" +DEFINE_MSM_MUTEX(imx132_mut); + +static struct msm_sensor_ctrl_t imx132_s_ctrl; + +static struct msm_sensor_power_setting imx132_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info imx132_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SRGGB10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id imx132_i2c_id[] = { + {IMX132_SENSOR_NAME, (kernel_ulong_t)&imx132_s_ctrl}, + { } +}; + +static int32_t msm_imx132_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &imx132_s_ctrl); +} +static struct i2c_driver imx132_i2c_driver = { + .id_table = imx132_i2c_id, + .probe = msm_imx132_i2c_probe, + .driver = { + .name = IMX132_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client imx132_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id imx132_dt_match[] = { + {.compatible = "qcom,imx132", .data = &imx132_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, imx132_dt_match); + +static struct platform_driver imx132_platform_driver = { + .driver = { + .name = "qcom,imx132", + .owner = THIS_MODULE, + .of_match_table = imx132_dt_match, + }, +}; + +static int32_t imx132_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(imx132_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init imx132_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&imx132_platform_driver, + imx132_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&imx132_i2c_driver); +} + +static void __exit imx132_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (imx132_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&imx132_s_ctrl); + platform_driver_unregister(&imx132_platform_driver); + } else + i2c_del_driver(&imx132_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t imx132_s_ctrl = { + .sensor_i2c_client = &imx132_sensor_i2c_client, + .power_setting_array.power_setting = imx132_power_setting, + .power_setting_array.size = ARRAY_SIZE(imx132_power_setting), + .msm_sensor_mutex = &imx132_mut, + .sensor_v4l2_subdev_info = imx132_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx132_subdev_info), +}; + +module_init(imx132_init_module); +module_exit(imx132_exit_module); +MODULE_DESCRIPTION("imx132"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/imx134.c b/drivers/media/platform/msm/camera_v2_j5/sensor/imx134.c new file mode 100755 index 0000000000000000000000000000000000000000..17a50889a88af155627634384efc4c93889fb37c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/imx134.c @@ -0,0 +1,174 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define IMX134_SENSOR_NAME "imx134" +DEFINE_MSM_MUTEX(imx134_mut); + +static struct msm_sensor_ctrl_t imx134_s_ctrl; + +static struct msm_sensor_power_setting imx134_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info imx134_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id imx134_i2c_id[] = { + {IMX134_SENSOR_NAME, (kernel_ulong_t)&imx134_s_ctrl}, + { } +}; + +static int32_t msm_imx134_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &imx134_s_ctrl); +} + +static struct i2c_driver imx134_i2c_driver = { + .id_table = imx134_i2c_id, + .probe = msm_imx134_i2c_probe, + .driver = { + .name = IMX134_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client imx134_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id imx134_dt_match[] = { + {.compatible = "sne,imx134", .data = &imx134_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, imx134_dt_match); + +static struct platform_driver imx134_platform_driver = { + .driver = { + .name = "sne,imx134", + .owner = THIS_MODULE, + .of_match_table = imx134_dt_match, + }, +}; + +static int32_t imx134_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(imx134_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init imx134_init_module(void) +{ + int32_t rc = 0; + pr_debug("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&imx134_platform_driver, + imx134_platform_probe); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&imx134_i2c_driver); +} + +static void __exit imx134_exit_module(void) +{ + pr_debug("%s:%d\n", __func__, __LINE__); + if (imx134_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&imx134_s_ctrl); + platform_driver_unregister(&imx134_platform_driver); + } else { + i2c_del_driver(&imx134_i2c_driver); + } + return; +} + +static struct msm_sensor_ctrl_t imx134_s_ctrl = { + .sensor_i2c_client = &imx134_sensor_i2c_client, + .power_setting_array.power_setting = imx134_power_setting, + .power_setting_array.size = ARRAY_SIZE(imx134_power_setting), + .msm_sensor_mutex = &imx134_mut, + .sensor_v4l2_subdev_info = imx134_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx134_subdev_info), +}; + +module_init(imx134_init_module); +module_exit(imx134_exit_module); +MODULE_DESCRIPTION("imx134"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/imx135.c b/drivers/media/platform/msm/camera_v2_j5/sensor/imx135.c new file mode 100755 index 0000000000000000000000000000000000000000..c26e4fffbd4f25de8d5594522f2a0040eafec50f --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/imx135.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define IMX135_SENSOR_NAME "imx135" +DEFINE_MSM_MUTEX(imx135_mut); + +static struct msm_sensor_ctrl_t imx135_s_ctrl; + +static struct msm_sensor_power_setting imx135_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info imx135_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id imx135_i2c_id[] = { + {IMX135_SENSOR_NAME, (kernel_ulong_t)&imx135_s_ctrl}, + { } +}; + +static int32_t msm_imx135_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &imx135_s_ctrl); +} + +static struct i2c_driver imx135_i2c_driver = { + .id_table = imx135_i2c_id, + .probe = msm_imx135_i2c_probe, + .driver = { + .name = IMX135_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client imx135_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id imx135_dt_match[] = { + {.compatible = "qcom,imx135", .data = &imx135_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, imx135_dt_match); + +static struct platform_driver imx135_platform_driver = { + .driver = { + .name = "qcom,imx135", + .owner = THIS_MODULE, + .of_match_table = imx135_dt_match, + }, +}; + +static int32_t imx135_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(imx135_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init imx135_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&imx135_platform_driver, + imx135_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&imx135_i2c_driver); +} + +static void __exit imx135_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (imx135_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&imx135_s_ctrl); + platform_driver_unregister(&imx135_platform_driver); + } else + i2c_del_driver(&imx135_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t imx135_s_ctrl = { + .sensor_i2c_client = &imx135_sensor_i2c_client, + .power_setting_array.power_setting = imx135_power_setting, + .power_setting_array.size = ARRAY_SIZE(imx135_power_setting), + .msm_sensor_mutex = &imx135_mut, + .sensor_v4l2_subdev_info = imx135_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx135_subdev_info), +}; + +module_init(imx135_init_module); +module_exit(imx135_exit_module); +MODULE_DESCRIPTION("imx135"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/Makefile b/drivers/media/platform/msm/camera_v2_j5/sensor/io/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ad43af82be37de24aebc55b17edffa33fcbff74 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/Makefile @@ -0,0 +1,4 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/ +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor +ccflags-y += -Idrivers/media/platform/msm/camera_v2_j5/sensor/cci +obj-$(CONFIG_MSMB_CAMERA) += msm_camera_io_util.o msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_i2c_mux.o msm_camera_spi.o msm_camera_dt_util.o diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_cci_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..8318b7ed537b65e5aecc3534b24a6f2ed8adf730 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_cci_i2c.c @@ -0,0 +1,599 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 "../../include/soc/qcom/camera2.h" +#include "msm_camera_i2c.h" +#include "msm_cci.h" + +//#define CONFIG_MSMB_CAMERA_DEBUG 1 +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#define S_I2C_DBG(fmt, args...) do { } while (0) +#endif + +#define I2C_COMPARE_MATCH 0 +#define I2C_COMPARE_MISMATCH 1 +#define I2C_POLL_MAX_ITERATION 20 + +int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + struct msm_camera_cci_ctrl cci_ctrl; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) + *data = buf[0]; + else + *data = buf[0] << 8 | buf[1]; + + S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); + return rc; +} + +int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char *buf = NULL; + int i; + struct msm_camera_cci_ctrl cci_ctrl; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + buf = kzalloc(num_byte, GFP_KERNEL); + if (!buf) { + pr_err("%s:%d no memory\n", __func__, __LINE__); + return -ENOMEM; + } + cci_ctrl.status = 0; //prevent + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); + rc = cci_ctrl.status; + + S_I2C_DBG("%s addr = 0x%x", __func__, addr); + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + kfree(buf); + return rc; +} + +int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + struct msm_camera_cci_ctrl cci_ctrl; + struct msm_camera_i2c_reg_array reg_conf_tbl; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + CDBG("%s:%d reg addr = 0x%x data type: %d\n", + __func__, __LINE__, addr, data_type); + reg_conf_tbl.reg_addr = addr; + reg_conf_tbl.reg_data = data; + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = ®_conf_tbl; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = 1; +#if defined(CONFIG_SR200PC20) + if (addr == 0xff){ + pr_err("delay START = %d\n", (int)data*10); + mdelay(data*10); + return 0; + } +#endif + + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + return rc; +} + +int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + uint8_t i = 0; + struct msm_camera_cci_ctrl cci_ctrl = {0}; + struct msm_camera_i2c_reg_array reg_conf_tbl[num_byte]; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", + __func__, addr, num_byte); + memset(reg_conf_tbl, 0, + num_byte * sizeof(struct msm_camera_i2c_reg_array)); + reg_conf_tbl[0].reg_addr = addr; + for (i = 0; i < num_byte; i++) { + reg_conf_tbl[i].reg_data = data[i]; + reg_conf_tbl[i].delay = 0; + } + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc); + rc = cci_ctrl.status; + return rc; +} + +int32_t msm_camera_cci_i2c_write_burst(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + uint32_t i = 0; + struct msm_camera_cci_ctrl cci_ctrl; + struct msm_camera_i2c_reg_array *reg_conf_tbl = NULL; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + reg_conf_tbl = (struct msm_camera_i2c_reg_array *) + kzalloc(num_byte * sizeof(struct msm_camera_i2c_reg_array), GFP_KERNEL); + if (!reg_conf_tbl) { + pr_err("%s:%d failed: no memory", __func__, __LINE__); + return -ENOMEM; + } + + CDBG("%s reg addr = 0x%x num bytes: %d\n", + __func__, addr, num_byte); + memset(reg_conf_tbl, 0, + num_byte * sizeof(struct msm_camera_i2c_reg_array)); + reg_conf_tbl[0].reg_addr = addr; + for (i = 0; i < num_byte; i++) { + reg_conf_tbl[i].reg_data = data[i]; + reg_conf_tbl[i].delay = 0; + CDBG("%s:%d data[%d] %x\n", __func__, __LINE__, i, + reg_conf_tbl[i].reg_data); + } + cci_ctrl.status = 0;//prevent + cci_ctrl.cmd = MSM_CCI_I2C_WRITE_BURST; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BURST_DATA; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s:%d failed: VIDIOC_MSM_CCI_CFG rc %d\n", __func__, __LINE__, + rc); + } + + rc = cci_ctrl.status; + kfree(reg_conf_tbl); + return rc; +} + +int32_t msm_camera_cci_i2c_write_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + struct msm_camera_cci_ctrl cci_ctrl; + + if (!client || !write_setting) { + pr_err("[CCI]%s:%d failed\n", __func__, __LINE__); + return rc; + } + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) { + pr_err("[CCI]%s:%d failed\n", __func__, __LINE__); + return rc; + } + + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = + write_setting->reg_setting; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + +int32_t msm_camera_cci_i2c_write_burst_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + struct msm_camera_i2c_reg_array *reg_array = NULL; + + if (!client || !write_setting) { + pr_err("[CCI]%s:%d failed\n", __func__, __LINE__); + return rc; + } + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA + && write_setting->data_type != MSM_CAMERA_I2C_BURST_DATA)) { + pr_err("[CCI]%s:%d failed data_type(%d)\n", __func__, __LINE__, write_setting->data_type); + return rc; + } + + reg_array = + (struct msm_camera_i2c_reg_array *)write_setting->reg_setting; + CDBG("%s:%d size %d addr %x\n", __func__, __LINE__, + reg_array->delay, reg_array->reg_addr); + rc = msm_camera_cci_i2c_write_burst(client, reg_array->reg_addr, + reg_array->reg_burst_data, reg_array->delay); + if (rc < 0) { + pr_err("%s:%d failed: msm_camera_cci_i2c_write_seq rc %d\n", + __func__, __LINE__, rc); + } + + return rc; +} + +int32_t msm_camera_cci_i2c_write_seq_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_seq_reg_array *reg_setting; + uint16_t client_addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { + pr_err("%s Invalide addr type %d\n", __func__, + write_setting->addr_type); + return rc; + } + + reg_setting = write_setting->reg_setting; + client_addr_type = client->addr_type; + client->addr_type = write_setting->addr_type; + + for (i = 0; i < write_setting->size; i++) { + rc = msm_camera_cci_i2c_write_seq(client, reg_setting->reg_addr, + reg_setting->reg_data, reg_setting->reg_data_size); + if (rc < 0) + return rc; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + client->addr_type = client_addr_type; + return rc; +} + +int32_t msm_camera_cci_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int32_t rc = -EFAULT; + struct msm_camera_cci_ctrl cci_ctrl; + + if (!client || !write_setting) + return rc; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + cci_ctrl.cmd = MSM_CCI_I2C_WRITE; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = + write_setting->reg_setting; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + rc = cci_ctrl.status; + return rc; +} + +static int32_t msm_camera_cci_i2c_compare(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data = 0; + int data_len = 0; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + data_len = data_type; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + data_len = MSM_CAMERA_I2C_BYTE_DATA; + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + data_len = MSM_CAMERA_I2C_WORD_DATA; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_len); + if (rc < 0) + return rc; + + rc = I2C_COMPARE_MISMATCH; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + if (data == reg_data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_SET_WORD_MASK: + if ((reg_data & data) == data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + if (!(reg_data & data)) + rc = I2C_COMPARE_MATCH; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + S_I2C_DBG("%s: Register and data match result %d\n", __func__, + rc); + return rc; +} + +int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", + __func__, addr, data, data_type); + + rc = msm_camera_cci_i2c_compare(client, + addr, data, data_type); + return rc; +} + +static int32_t msm_camera_cci_i2c_set_mask(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t mask, + enum msm_camera_i2c_data_type data_type, uint16_t set_mask) +{ + int32_t rc; + uint16_t reg_data; + + rc = msm_camera_cci_i2c_read(client, addr, ®_data, data_type); + if (rc < 0) { + S_I2C_DBG("%s read fail\n", __func__); + return rc; + } + S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", + __func__, addr, reg_data, mask); + + if (set_mask) + reg_data |= mask; + else + reg_data &= ~mask; + S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); + + rc = msm_camera_cci_i2c_write(client, addr, reg_data, data_type); + if (rc < 0) + S_I2C_DBG("%s write fail\n", __func__); + + return rc; +} + +static int32_t msm_camera_cci_i2c_set_write_mask_data( + struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, int16_t mask, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data; + CDBG("%s\n", __func__); + if (mask == -1) + return 0; + if (mask == 0) { + rc = msm_camera_cci_i2c_write(client, addr, data, data_type); + } else { + rc = msm_camera_cci_i2c_read(client, addr, ®_data, + data_type); + if (rc < 0) { + CDBG("%s read fail\n", __func__); + return rc; + } + reg_data &= ~mask; + reg_data |= (data & mask); + rc = msm_camera_cci_i2c_write(client, addr, reg_data, + data_type); + if (rc < 0) + CDBG("%s write fail\n", __func__); + } + return rc; +} + +int32_t msm_camera_cci_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type) +{ + int i; + int32_t rc = -EFAULT; + for (i = 0; i < size; i++) { + enum msm_camera_i2c_data_type dt; + if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { + rc = msm_camera_cci_i2c_poll(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->dt); + } else { + if (reg_conf_tbl->dt == 0) + dt = data_type; + else + dt = reg_conf_tbl->dt; + switch (dt) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + rc = msm_camera_cci_i2c_write( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, dt); + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + rc = msm_camera_cci_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: + rc = msm_camera_cci_i2c_set_write_mask_data( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->mask, + MSM_CAMERA_I2C_BYTE_DATA); + break; + default: + pr_err("%s: Unsupport data type: %d\n", + __func__, dt); + break; + } + } + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + +int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, + uint16_t cci_cmd) +{ + int32_t rc = 0; + struct msm_camera_cci_ctrl cci_ctrl; + + CDBG("%s line %d\n", __func__, __LINE__); + cci_ctrl.cmd = cci_cmd; + cci_ctrl.cci_info = client->cci_client; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + pr_err("%s line %d rc = %d\n", __func__, __LINE__, rc); + return rc; + } + return cci_ctrl.status; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_dt_util.c new file mode 100644 index 0000000000000000000000000000000000000000..ffc1c33f5d914d66fedcea6d7e973e5dcf420c95 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_dt_util.c @@ -0,0 +1,1638 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 +#include "msm_camera_dt_util.h" +#include "msm_camera_io_util.h" +#include "msm_camera_i2c_mux.h" +#include "msm_cci.h" + +#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" +#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default" +//#define CONFIG_MSM_CAMERA_DT_DEBUG +#undef CDBG +#ifdef CONFIG_MSM_CAMERA_DT_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, + int num_vreg, struct msm_sensor_power_setting *power_setting, + uint16_t power_setting_size) +{ + uint16_t i = 0; + int j = 0; + + /* Validate input parameters */ + if (!cam_vreg || !power_setting) { + pr_err("%s:%d failed: cam_vreg %p power_setting %p", __func__, + __LINE__, cam_vreg, power_setting); + return -EINVAL; + } + + /* Validate size of num_vreg */ + if (num_vreg <= 0) { + pr_err("failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + for (i = 0; i < power_setting_size; i++) { + if (power_setting[i].seq_type != SENSOR_VREG) + continue; + + switch (power_setting[i].seq_val) { + case CAM_VDIG: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vdig")) { + CDBG("%s:%d i %d j %d cam_vdig\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + case CAM_VIO: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vio")) { + CDBG("%s:%d i %d j %d cam_vio\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + case CAM_VANA: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vana")) { + CDBG("%s:%d i %d j %d cam_vana\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + case CAM_VAF: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vaf")) { + CDBG("%s:%d i %d j %d cam_vaf\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) + case CAM_VIO_VT: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vio_vt")) { + CDBG("%s:%d i %d j %d cam_vio_vt\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; +#endif + + case CAM_VANA_VT: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(cam_vreg[j].reg_name, "cam_vana_vt")) { + CDBG("%s:%d i %d j %d cam_vana_vt\n", + __func__, __LINE__, i, j); + power_setting[i].seq_val = j; + break; + } + } + break; + + default: + pr_err("%s:%d invalid seq_val %d\n", __func__, + __LINE__, power_setting[i].seq_val); + break; + } + } + + return 0; +} + +int msm_sensor_get_sub_module_index(struct device_node *of_node, + struct msm_sensor_info_t **s_info) +{ + int rc = 0, i = 0; + uint32_t val = 0, count = 0; + uint32_t *val_array = NULL; + struct device_node *src_node = NULL; + struct msm_sensor_info_t *sensor_info; + + sensor_info = kzalloc(sizeof(*sensor_info), GFP_KERNEL); + if (!sensor_info) { + pr_err("%s:%d failed\n", __func__, __LINE__); + return -ENOMEM; + } + for (i = 0; i < SUB_MODULE_MAX; i++) + sensor_info->subdev_id[i] = -1; + + src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0); + if (!src_node) { + CDBG("%s:%d src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val; + of_node_put(src_node); + src_node = NULL; + } + + src_node = of_parse_phandle(of_node, "qcom,eeprom-src", 0); + if (!src_node) { + CDBG("%s:%d eeprom src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; + of_node_put(src_node); + src_node = NULL; + } + + rc = of_property_read_u32(of_node, "qcom,eeprom-sd-index", &val); + if (rc != -EINVAL) { + CDBG("%s qcom,eeprom-sd-index %d, rc %d\n", __func__, val, rc); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; + } else + rc = 0; + + src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0); + if (!src_node) { + CDBG("%s:%d src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s:%d failed %d\n", __func__, __LINE__, rc); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val; + of_node_put(src_node); + src_node = NULL; + } + + rc = of_property_read_u32(of_node, "qcom,strobe-flash-sd-index", &val); + if (rc != -EINVAL) { + CDBG("%s qcom,strobe-flash-sd-index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc); + goto ERROR; + } + sensor_info->subdev_id[SUB_MODULE_STROBE_FLASH] = val; + } else + rc = 0; + + if (of_get_property(of_node, "qcom,csiphy-sd-index", &count)) { + count /= sizeof(uint32_t); + if (count > 2) { + pr_err("%s qcom,csiphy-sd-index count %d > 2\n", + __func__, count); + goto ERROR; + } + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + + rc = of_property_read_u32_array(of_node, "qcom,csiphy-sd-index", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + kfree(val_array); + goto ERROR; + } + for (i = 0; i < count; i++) { + sensor_info->subdev_id[SUB_MODULE_CSIPHY + i] = + val_array[i]; + CDBG("%s csiphy_core[%d] = %d\n", + __func__, i, val_array[i]); + } + kfree(val_array); + } else { + pr_err("%s:%d qcom,csiphy-sd-index not present\n", __func__, + __LINE__); + rc = -EINVAL; + goto ERROR; + } + + if (of_get_property(of_node, "qcom,csid-sd-index", &count)) { + count /= sizeof(uint32_t); + if (count > 2) { + pr_err("%s qcom,csid-sd-index count %d > 2\n", + __func__, count); + rc = -EINVAL; + goto ERROR; + } + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + + rc = of_property_read_u32_array(of_node, "qcom,csid-sd-index", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + kfree(val_array); + goto ERROR; + } + for (i = 0; i < count; i++) { + sensor_info->subdev_id + [SUB_MODULE_CSID + i] = val_array[i]; + CDBG("%s csid_core[%d] = %d\n", + __func__, i, val_array[i]); + } + kfree(val_array); + } else { + pr_err("%s:%d qcom,csid-sd-index not present\n", __func__, + __LINE__); + rc = -EINVAL; + goto ERROR; + } + + *s_info = sensor_info; + return rc; +ERROR: + kfree(sensor_info); + return rc; +} + +int msm_sensor_get_dt_actuator_data(struct device_node *of_node, + struct msm_actuator_info **act_info) +{ + int rc = 0; + uint32_t val = 0; + struct msm_actuator_info *actuator_info; + + rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val); + CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc); + if (rc < 0) + return 0; + + actuator_info = kzalloc(sizeof(*actuator_info), GFP_KERNEL); + if (!actuator_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR; + } + + actuator_info->cam_name = val; + + rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val); + CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc); + if (!rc) + actuator_info->vcm_pwd = val; + + rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val); + CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc); + if (!rc) + actuator_info->vcm_enable = val; + + *act_info = actuator_info; + return 0; +ERROR: + kfree(actuator_info); + return rc; +} + +int msm_sensor_get_dt_csi_data(struct device_node *of_node, + struct msm_camera_csi_lane_params **csi_lane_params) +{ + int rc = 0; + uint32_t val = 0; + struct msm_camera_csi_lane_params *clp; + + clp = kzalloc(sizeof(*clp), GFP_KERNEL); + if (!clp) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + *csi_lane_params = clp; + + rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val); + CDBG("%s qcom,csi-lane-assign 0x%x, rc %d\n", __func__, val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + clp->csi_lane_assign = val; + + rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val); + CDBG("%s qcom,csi-lane-mask 0x%x, rc %d\n", __func__, val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR; + } + clp->csi_lane_mask = val; + + return rc; +ERROR: + kfree(clp); + return rc; +} + +int msm_camera_get_dt_power_setting_data(struct device_node *of_node, + struct camera_vreg_t *cam_vreg, int num_vreg, + struct msm_camera_power_ctrl_t *power_info) +{ + int rc = 0, i, j; + int count = 0; + const char *seq_name = NULL; + uint32_t *array = NULL; + struct msm_sensor_power_setting *ps; + + struct msm_sensor_power_setting *power_setting; + uint16_t *power_setting_size, size = 0; + bool need_reverse = 0; + + if (!power_info) + return -EINVAL; + + power_setting = power_info->power_setting; + power_setting_size = &power_info->power_setting_size; + + count = of_property_count_strings(of_node, "qcom,cam-power-seq-type"); + *power_setting_size = count; + + CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count); + + if (count <= 0) + return 0; + + ps = kzalloc(sizeof(*ps) * count, GFP_KERNEL); + if (!ps) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + power_setting = ps; + power_info->power_setting = ps; + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-power-seq-type", i, + &seq_name); + CDBG("%s seq_name[%d] = %s\n", __func__, i, + seq_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + if (!strcmp(seq_name, "sensor_vreg")) { + ps[i].seq_type = SENSOR_VREG; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else if (!strcmp(seq_name, "sensor_gpio")) { + ps[i].seq_type = SENSOR_GPIO; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else if (!strcmp(seq_name, "sensor_clk")) { + ps[i].seq_type = SENSOR_CLK; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else if (!strcmp(seq_name, "sensor_i2c_mux")) { + ps[i].seq_type = SENSOR_I2C_MUX; + CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__, + i, ps[i].seq_type); + } else { + CDBG("%s: unrecognized seq-type\n", __func__); + rc = -EILSEQ; + goto ERROR1; + } + } + + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-power-seq-val", i, + &seq_name); + CDBG("%s seq_name[%d] = %s\n", __func__, i, + seq_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + switch (ps[i].seq_type) { + case SENSOR_VREG: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(seq_name, cam_vreg[j].reg_name)) + break; + } + if (j < num_vreg) + ps[i].seq_val = j; + else + rc = -EILSEQ; + break; + case SENSOR_GPIO: + if (!strcmp(seq_name, "sensor_gpio_reset")) + ps[i].seq_val = SENSOR_GPIO_RESET; + else if (!strcmp(seq_name, "sensor_gpio_standby")) + ps[i].seq_val = SENSOR_GPIO_STANDBY; + else if (!strcmp(seq_name, "sensor_gpio_vdig")) + ps[i].seq_val = SENSOR_GPIO_VDIG; + else if (!strcmp(seq_name, "sensor_gpio_vana")) + ps[i].seq_val = SENSOR_GPIO_VANA; + else if (!strcmp(seq_name, "sensor_gpio_vt_reset")) + ps[i].seq_val = SENSOR_GPIO_VT_RESET; +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) + else if (!strcmp(seq_name, "sensor_gpio_vt_standby")) + ps[i].seq_val = SENSOR_GPIO_VT_STANDBY; +#endif + else + rc = -EILSEQ; + break; + case SENSOR_CLK: + if (!strcmp(seq_name, "sensor_cam_mclk")) + ps[i].seq_val = SENSOR_CAM_MCLK; + else if (!strcmp(seq_name, "sensor_cam_clk")) + ps[i].seq_val = SENSOR_CAM_CLK; + else + rc = -EILSEQ; + break; + case SENSOR_I2C_MUX: + if (!strcmp(seq_name, "none")) + ps[i].seq_val = 0; + else + rc = -EILSEQ; + break; + default: + rc = -EILSEQ; + break; + } + if (rc < 0) { + CDBG("%s: unrecognized seq-val\n", __func__); + goto ERROR1; + } + } + + array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val", + array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + if (ps[i].seq_type == SENSOR_GPIO) { + if (array[i] == 0) + ps[i].config_val = GPIO_OUT_LOW; + else if (array[i] == 1) + ps[i].config_val = GPIO_OUT_HIGH; + } else { + ps[i].config_val = array[i]; + } + CDBG("%s power_setting[%d].config_val = %ld\n", __func__, i, + ps[i].config_val); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay", + array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + ps[i].delay = array[i]; + CDBG("%s power_setting[%d].delay = %d\n", __func__, + i, ps[i].delay); + } + kfree(array); + + size = *power_setting_size; + + if (NULL != ps && 0 != size) + need_reverse = 1; + + power_info->power_down_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + + if (!power_info->power_down_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + memcpy(power_info->power_down_setting, + ps, sizeof(*ps) * size); + + power_info->power_down_setting_size = size; + + if (need_reverse) { + int c, end = size - 1; + struct msm_sensor_power_setting power_down_setting_t; + for (c = 0; c < size/2; c++) { + power_down_setting_t = + power_info->power_down_setting[c]; + power_info->power_down_setting[c] = + power_info->power_down_setting[end]; + power_info->power_down_setting[end] = + power_down_setting_t; + end--; + } +#if defined(CONFIG_SR544) || defined(CONFIG_SR200PC20) + for (c = 0; c < size; c ++) { + if(power_info->power_down_setting[c].seq_val == SENSOR_GPIO_VDIG) + { + int i = c + 1; + power_down_setting_t = power_info->power_down_setting[c]; + power_info->power_down_setting[c] = power_info->power_down_setting[i]; + power_info->power_down_setting[i] = power_down_setting_t; + power_info->power_down_setting[c].delay = 0; + break; + } + } +#endif + } + return rc; +ERROR2: + kfree(array); +ERROR1: + kfree(ps); + power_setting_size = 0; + return rc; +} + +int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int rc = 0, i = 0; + uint32_t count = 0; + uint32_t *val_array = NULL; + + if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count)) + return 0; + + count /= sizeof(uint32_t); + if (!count) { + pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__); + return 0; + } + + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + gconf->cam_gpio_req_tbl = kzalloc(sizeof(struct gpio) * count, + GFP_KERNEL); + if (!gconf->cam_gpio_req_tbl) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + gconf->cam_gpio_req_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + if (val_array[i] >= gpio_array_size) { + pr_err("%s gpio req tbl index %d invalid\n", + __func__, val_array[i]); + return -EINVAL; + } + gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]]; + CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i, + gconf->cam_gpio_req_tbl[i].gpio); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_req_tbl[i].flags = val_array[i]; + CDBG("%s cam_gpio_req_tbl[%d].flags = %ld\n", __func__, i, + gconf->cam_gpio_req_tbl[i].flags); + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,gpio-req-tbl-label", i, + &gconf->cam_gpio_req_tbl[i].label); + CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i, + gconf->cam_gpio_req_tbl[i].label); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + } + + kfree(val_array); + return rc; + +ERROR2: + kfree(gconf->cam_gpio_req_tbl); +ERROR1: + kfree(val_array); + gconf->cam_gpio_req_tbl_size = 0; + return rc; +} + +int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int rc = 0, i = 0; + uint32_t count = 0; + uint32_t *val_array = NULL; + + if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count)) + return 0; + + count /= sizeof(uint32_t); + if (!count) { + pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__); + return 0; + } + + val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!val_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + gconf->cam_gpio_set_tbl = kzalloc(sizeof(struct msm_gpio_set_tbl) * + count, GFP_KERNEL); + if (!gconf->cam_gpio_set_tbl) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + gconf->cam_gpio_set_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + if (val_array[i] >= gpio_array_size) { + pr_err("%s gpio set tbl index %d invalid\n", + __func__, val_array[i]); + return -EINVAL; + } + gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]]; + CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i, + gconf->cam_gpio_set_tbl[i].gpio); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_set_tbl[i].flags = val_array[i]; + CDBG("%s cam_gpio_set_tbl[%d].flags = %ld\n", __func__, i, + gconf->cam_gpio_set_tbl[i].flags); + } + + rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay", + val_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + gconf->cam_gpio_set_tbl[i].delay = val_array[i]; + CDBG("%s cam_gpio_set_tbl[%d].delay = %d\n", __func__, i, + gconf->cam_gpio_set_tbl[i].delay); + } + + kfree(val_array); + return rc; + +ERROR2: + kfree(gconf->cam_gpio_set_tbl); +ERROR1: + kfree(val_array); + gconf->cam_gpio_set_tbl_size = 0; + return rc; +} + +int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int rc = 0, val = 0; + + gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info), + GFP_KERNEL); + if (!gconf->gpio_num_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + return rc; + } + + rc = of_property_read_u32(of_node, "qcom,gpio-vio", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-vio failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-vio invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_VIO] = 1; + CDBG("%s qcom,gpio-vana %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-vana failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-vana invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_VANA] = 1; + CDBG("%s qcom,gpio-vana %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-vdig failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-vdig invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_VDIG] = 1; + CDBG("%s qcom,gpio-vdig %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-reset failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-reset invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_RESET] = 1; + CDBG("%s qcom,gpio-reset %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-standby", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-standby failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-standby invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_STANDBY] = 1; + CDBG("%s qcom,gpio-standby %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-vt-reset", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-vt-reset failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-vt-reset invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VT_RESET] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_VT_RESET] = 1; + CDBG("%s qcom,gpio-vt-reset %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VT_RESET]); + } else + rc = 0; + +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) + rc = of_property_read_u32(of_node, "qcom,gpio-vt-standby", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-vt-standby failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-vt-standby invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VT_STANDBY] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_VT_STANDBY] = 1; + CDBG("%s qcom,gpio-vt-standby %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VT_STANDBY]); + } else + rc = 0; +#endif + + rc = of_property_read_u32(of_node, "qcom,gpio-af-pwdm", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-af-pwdm failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_AF_PWDM] = 1; + CDBG("%s qcom,gpio-af-pwdm %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-flash-en invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_FL_EN] = 1; + CDBG("%s qcom,gpio-flash-en %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-flash-now invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_FL_NOW] = 1; + CDBG("%s qcom,gpio-flash-now %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW]); + } else + rc = 0; + + rc = of_property_read_u32(of_node, "qcom,gpio-flash-reset", &val); + if (rc != -EINVAL) { + if (rc < 0) { + pr_err("%s:%dread qcom,gpio-flash-reset failed rc %d\n", + __func__, __LINE__, rc); + goto ERROR; + } else if (val >= gpio_array_size) { + pr_err("%s:%d qcom,gpio-flash-reset invalid %d\n", + __func__, __LINE__, val); + rc = -EINVAL; + goto ERROR; + } + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET] = + gpio_array[val]; + gconf->gpio_num_info->valid[SENSOR_GPIO_FL_RESET] = 1; + CDBG("%s qcom,gpio-flash-reset %d\n", __func__, + gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_RESET]); + } else + rc = 0; + return rc; + +ERROR: + kfree(gconf->gpio_num_info); + gconf->gpio_num_info = NULL; + return rc; +} + +#if defined (CONFIG_CAMERA_SYSFS_V2) +int msm_camera_get_dt_camera_info(struct device_node *of_node, char *buf) +{ + int rc = 0, val = 0; + char camera_info[100] = {0, }; + + rc = of_property_read_u32(of_node, "cam,isp", + &val); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + strcpy(camera_info, "ISP="); + switch(val) { + case CAM_INFO_ISP_TYPE_INTERNAL : + strcat(camera_info, "INT;"); + break; + case CAM_INFO_ISP_TYPE_EXTERNAL : + strcat(camera_info, "EXT;"); + break; + case CAM_INFO_ISP_TYPE_SOC : + strcat(camera_info, "SOC;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + rc = of_property_read_u32(of_node, "cam,cal_memory", + &val); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + strcat(camera_info, "CALMEM="); + switch(val) { + case CAM_INFO_CAL_MEM_TYPE_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_CAL_MEM_TYPE_FROM : + case CAM_INFO_CAL_MEM_TYPE_EEPROM : + case CAM_INFO_CAL_MEM_TYPE_OTP : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + rc = of_property_read_u32(of_node, "cam,read_version", + &val); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + strcat(camera_info, "READVER="); + switch(val) { + case CAM_INFO_READ_VER_SYSFS : + strcat(camera_info, "SYSFS;"); + break; + case CAM_INFO_READ_VER_CAMON : + strcat(camera_info, "CAMON;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + rc = of_property_read_u32(of_node, "cam,core_voltage", + &val); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + strcat(camera_info, "COREVOLT="); + switch(val) { + case CAM_INFO_CORE_VOLT_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_CORE_VOLT_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + rc = of_property_read_u32(of_node, "cam,upgrade", + &val); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + strcat(camera_info, "UPGRADE="); + switch(val) { + case CAM_INFO_FW_UPGRADE_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_FW_UPGRADE_SYSFS : + strcat(camera_info, "SYSFS;"); + break; + case CAM_INFO_FW_UPGRADE_CAMON : + strcat(camera_info, "CAMON;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + rc = of_property_read_u32(of_node, "cam,companion_chip", + &val); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + strcat(camera_info, "CC="); + switch(val) { + case CAM_INFO_COMPANION_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_COMPANION_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + rc = of_property_read_u32(of_node, "cam,ois", + &val); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + strcat(camera_info, "OIS="); + switch(val) { + case CAM_INFO_OIS_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_OIS_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + snprintf(buf, sizeof(camera_info), "%s", camera_info); + return 0; + +ERROR1: + strcpy(camera_info, "ISP=NULL;CALMEM=NULL;READVER=NULL;COREVOLT=NULL;UPGRADE=NULL;FW_CC=NULL;OIS=NULL"); + snprintf(buf, sizeof(camera_info), "%s", camera_info); + return 0; +} +#endif + +int msm_camera_get_dt_vreg_data(struct device_node *of_node, + struct camera_vreg_t **cam_vreg, int *num_vreg) +{ + int rc = 0, i = 0; + uint32_t count = 0; + uint32_t *vreg_array = NULL; + struct camera_vreg_t *vreg = NULL; + + count = of_property_count_strings(of_node, "qcom,cam-vreg-name"); + CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count); + + if (!count) + return 0; + + vreg = kzalloc(sizeof(*vreg) * count, GFP_KERNEL); + if (!vreg) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + *cam_vreg = vreg; + *num_vreg = count; + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-vreg-name", i, + &vreg[i].reg_name); + CDBG("%s reg_name[%d] = %s\n", __func__, i, + vreg[i].reg_name); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR1; + } + } + + vreg_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL); + if (!vreg_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto ERROR1; + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].type = vreg_array[i]; + CDBG("%s cam_vreg[%d].type = %d\n", __func__, i, + vreg[i].type); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].min_voltage = vreg_array[i]; + CDBG("%s cam_vreg[%d].min_voltage = %d\n", __func__, + i, vreg[i].min_voltage); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].max_voltage = vreg_array[i]; + CDBG("%s cam_vreg[%d].max_voltage = %d\n", __func__, + i, vreg[i].max_voltage); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode", + vreg_array, count); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR2; + } + for (i = 0; i < count; i++) { + vreg[i].op_mode = vreg_array[i]; + CDBG("%s cam_vreg[%d].op_mode = %d\n", __func__, i, + vreg[i].op_mode); + } + + kfree(vreg_array); + return rc; +ERROR2: + kfree(vreg_array); +ERROR1: + kfree(vreg); + *num_vreg = 0; + return rc; +} + +static int msm_camera_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) +{ + struct v4l2_subdev *i2c_mux_sd = + dev_get_drvdata(&i2c_conf->mux_dev->dev); + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_INIT, NULL); + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode); + return 0; +} + +static int msm_camera_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf) +{ + struct v4l2_subdev *i2c_mux_sd = + dev_get_drvdata(&i2c_conf->mux_dev->dev); + v4l2_subdev_call(i2c_mux_sd, core, ioctl, + VIDIOC_MSM_I2C_MUX_RELEASE, NULL); + return 0; +} + +static int msm_camera_pinctrl_init(struct msm_camera_power_ctrl_t *ctrl) +{ + struct msm_pinctrl_info *sensor_pctrl = NULL; + + sensor_pctrl = &ctrl->pinctrl_info; + sensor_pctrl->pinctrl = devm_pinctrl_get(ctrl->dev); + if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { + pr_err("%s:%d Getting pinctrl handle failed\n", + __func__, __LINE__); + return -EINVAL; + } + sensor_pctrl->gpio_state_active = + pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) { + pr_err("%s:%d Failed to get the active state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + sensor_pctrl->gpio_state_suspend + = pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) { + pr_err("%s:%d Failed to get the suspend state pinctrl handle\n", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + +int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client) +{ + int rc = 0, index = 0, no_gpio = 0, ret = 0; + struct msm_sensor_power_setting *power_setting = NULL; + + CDBG("%s:%d\n", __func__, __LINE__); + if (!ctrl || !sensor_i2c_client) { + pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, + sensor_i2c_client); + return -EINVAL; + } + if (ctrl->gpio_conf->cam_gpiomux_conf_tbl != NULL) { + pr_err("%s:%d mux install\n", __func__, __LINE__); + msm_gpiomux_install( + (struct msm_gpiomux_config *) + ctrl->gpio_conf->cam_gpiomux_conf_tbl, + ctrl->gpio_conf->cam_gpiomux_conf_tbl_size); + } + ret = msm_camera_pinctrl_init(ctrl); + if (ret < 0) { + pr_err("%s:%d Initialization of pinctrl failed\n", + __func__, __LINE__); + ctrl->cam_pinctrl_status = 0; + } else { + ctrl->cam_pinctrl_status = 1; + } + + if(ctrl->gpio_conf->cam_gpio_req_tbl_size > 0) { + rc = msm_camera_request_gpio_table( + ctrl->gpio_conf->cam_gpio_req_tbl, + ctrl->gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) + no_gpio = rc; + } + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_active); + if (ret) + pr_err("%s:%d cannot set pin to active state", + __func__, __LINE__); + } + for (index = 0; index < ctrl->power_setting_size; index++) { + CDBG("%s index %d\n", __func__, index); + power_setting = &ctrl->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_CLK: + if (power_setting->seq_val >= ctrl->clk_info_size) { + pr_err("%s clk index %d >= max %d\n", __func__, + power_setting->seq_val, + ctrl->clk_info_size); + goto power_up_failed; + } + if (power_setting->config_val) + ctrl->clk_info[power_setting->seq_val]. + clk_rate = power_setting->config_val; + + rc = msm_cam_clk_enable(ctrl->dev, + &ctrl->clk_info[0], + (struct clk **)&power_setting->data[0], + ctrl->clk_info_size, + 1); + if (rc < 0) { + pr_err("%s: clk enable failed\n", + __func__); + goto power_up_failed; + } + break; + case SENSOR_GPIO: + if (no_gpio) { + pr_err("%s: request gpio failed\n", __func__); + return no_gpio; + } + if (power_setting->seq_val >= SENSOR_GPIO_MAX || + !ctrl->gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + if (!ctrl->gpio_conf->gpio_num_info->valid + [power_setting->seq_val]) + continue; + CDBG("%s:%d gpio set val %d\n", __func__, __LINE__, + ctrl->gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val]); + gpio_set_value_cansleep( + ctrl->gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], + power_setting->config_val); + break; + case SENSOR_VREG: + if (power_setting->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + power_setting->seq_val, + SENSOR_GPIO_MAX); + goto power_up_failed; + } + msm_camera_config_single_vreg(ctrl->dev, + &ctrl->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 1); + break; + case SENSOR_I2C_MUX: + if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) + msm_camera_enable_i2c_mux(ctrl->i2c_conf); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + + if (device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = sensor_i2c_client->i2c_func_tbl->i2c_util( + sensor_i2c_client, MSM_CCI_INIT); + if (rc < 0) { + pr_err("%s cci_init failed\n", __func__); + goto power_up_failed; + } + } + + CDBG("%s exit\n", __func__); + return 0; +power_up_failed: + pr_err("%s:%d failed\n", __func__, __LINE__); + for (index--; index >= 0; index--) { + CDBG("%s index %d\n", __func__, index); + power_setting = &ctrl->power_setting[index]; + CDBG("%s type %d\n", __func__, power_setting->seq_type); + switch (power_setting->seq_type) { + + case SENSOR_CLK: + msm_cam_clk_enable(ctrl->dev, + &ctrl->clk_info[0], + (struct clk **)&power_setting->data[0], + ctrl->clk_info_size, + 0); + break; + case SENSOR_GPIO: + if (!ctrl->gpio_conf->gpio_num_info->valid + [power_setting->seq_val]) + continue; + gpio_set_value_cansleep( + ctrl->gpio_conf->gpio_num_info->gpio_num + [power_setting->seq_val], GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VREG: + msm_camera_config_single_vreg(ctrl->dev, + &ctrl->cam_vreg[power_setting->seq_val], + (struct regulator **)&power_setting->data[0], + 0); + break; + case SENSOR_I2C_MUX: + if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) + msm_camera_disable_i2c_mux(ctrl->i2c_conf); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state\n", + __func__, __LINE__); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + ctrl->cam_pinctrl_status = 0; + if (ctrl->gpio_conf->cam_gpio_req_tbl_size > 0) { + msm_camera_request_gpio_table( + ctrl->gpio_conf->cam_gpio_req_tbl, + ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); + } + return rc; +} + +static struct msm_sensor_power_setting* +msm_camera_get_power_settings(struct msm_camera_power_ctrl_t *ctrl, + enum msm_sensor_power_seq_type_t seq_type, + uint16_t seq_val) +{ + struct msm_sensor_power_setting *power_setting, *ps = NULL; + int idx; + + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + power_setting = &ctrl->power_setting[idx]; + if (power_setting->seq_type == seq_type && + power_setting->seq_val == seq_val) { + ps = power_setting; + return ps; + } + + } + return ps; +} + +int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client) +{ + int index = 0, ret = 0; + struct msm_sensor_power_setting *pd = NULL; + struct msm_sensor_power_setting *ps; + + CDBG("%s:%d\n", __func__, __LINE__); + if (!ctrl || !sensor_i2c_client) { + pr_err("failed ctrl %p sensor_i2c_client %p\n", ctrl, + sensor_i2c_client); + return -EINVAL; + } + if (device_type == MSM_CAMERA_PLATFORM_DEVICE) + sensor_i2c_client->i2c_func_tbl->i2c_util( + sensor_i2c_client, MSM_CCI_RELEASE); + + for (index = 0; index < ctrl->power_down_setting_size; index++) { + CDBG("%s index %d\n", __func__, index); + pd = &ctrl->power_down_setting[index]; + ps = NULL; + CDBG("%s type %d\n", __func__, pd->seq_type); + switch (pd->seq_type) { + case SENSOR_CLK: + + ps = msm_camera_get_power_settings(ctrl, + pd->seq_type, + pd->seq_val); + if (ps) + msm_cam_clk_enable(ctrl->dev, + &ctrl->clk_info[0], + (struct clk **)&ps->data[0], + ctrl->clk_info_size, + 0); + else + pr_err("%s error in power up/down seq data\n", + __func__); + break; + case SENSOR_GPIO: + if (pd->seq_val >= SENSOR_GPIO_MAX || + !ctrl->gpio_conf->gpio_num_info) { + pr_err("%s gpio index %d >= max %d\n", __func__, + pd->seq_val, + SENSOR_GPIO_MAX); + continue; + } + if (!ctrl->gpio_conf->gpio_num_info->valid + [pd->seq_val]) + continue; + gpio_set_value_cansleep( + ctrl->gpio_conf->gpio_num_info->gpio_num + [pd->seq_val], + 0); + break; + case SENSOR_VREG: + if (pd->seq_val >= CAM_VREG_MAX) { + pr_err("%s vreg index %d >= max %d\n", __func__, + pd->seq_val, + SENSOR_GPIO_MAX); + continue; + } + + ps = msm_camera_get_power_settings(ctrl, + pd->seq_type, + pd->seq_val); + + if (ps) + msm_camera_config_single_vreg(ctrl->dev, + &ctrl->cam_vreg[pd->seq_val], + (struct regulator **)&ps->data[0], + 0); + else + pr_err("%s error in power up/down seq data\n", + __func__); + break; + case SENSOR_I2C_MUX: + if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux) + msm_camera_disable_i2c_mux(ctrl->i2c_conf); + break; + default: + pr_err("%s error power seq type %d\n", __func__, + pd->seq_type); + break; + } + if (pd->delay > 20) { + msleep(pd->delay); + } else if (pd->delay) { + usleep_range(pd->delay * 1000, + (pd->delay * 1000) + 1000); + } + } + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state(ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + pr_err("%s:%d cannot set pin to suspend state", + __func__, __LINE__); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + ctrl->cam_pinctrl_status = 0; + if(ctrl->gpio_conf->cam_gpio_req_tbl_size > 0) { + msm_camera_request_gpio_table( + ctrl->gpio_conf->cam_gpio_req_tbl, + ctrl->gpio_conf->cam_gpio_req_tbl_size, 0); + } + CDBG("%s exit\n", __func__); + return 0; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_dt_util.h new file mode 100644 index 0000000000000000000000000000000000000000..f8e858307a7b4091a62c5089fc9fc8bf8b6ec281 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_dt_util.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CAMERA_DT_UTIL_H__ +#define MSM_CAMERA_DT_UTIL_H__ + +#include "../../include/soc/qcom/camera2.h" +#include +#include +#include "msm_camera_i2c.h" + +int msm_sensor_get_sub_module_index(struct device_node *of_node, + struct msm_sensor_info_t **s_info); + +int msm_sensor_get_dt_actuator_data(struct device_node *of_node, + struct msm_actuator_info **act_info); + +int msm_sensor_get_dt_csi_data(struct device_node *of_node, + struct msm_camera_csi_lane_params **csi_lane_params); + +int msm_camera_get_dt_power_setting_data(struct device_node *of_node, + struct camera_vreg_t *cam_vreg, int num_vreg, + struct msm_camera_power_ctrl_t *power_info); + +int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int msm_camera_init_gpio_pin_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int msm_camera_get_dt_vreg_data(struct device_node *of_node, + struct camera_vreg_t **cam_vreg, int *num_vreg); + +#if defined (CONFIG_CAMERA_SYSFS_V2) +int msm_camera_get_dt_camera_info(struct device_node *of_node, char *buf); +#endif + +int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client); + +int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, + enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client); + +int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg, + int num_vreg, struct msm_sensor_power_setting *power_setting, + uint16_t power_setting_size); + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..00a2a6332e787df845a9a0ed0a4cd8cb0fa3a956 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c.h @@ -0,0 +1,130 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_CAMERA_CCI_I2C_H +#define MSM_CAMERA_CCI_I2C_H + +#include +#include +#include "../../include/media/msm_cam_sensor.h" + +struct msm_camera_i2c_client { + struct msm_camera_i2c_fn_t *i2c_func_tbl; + struct i2c_client *client; + struct msm_camera_cci_client *cci_client; + struct msm_camera_spi_client *spi_client; + enum msm_camera_i2c_reg_addr_type addr_type; +}; + +struct msm_camera_i2c_fn_t { + int (*i2c_read) (struct msm_camera_i2c_client *, uint32_t, uint16_t *, + enum msm_camera_i2c_data_type); + int32_t (*i2c_read_seq)(struct msm_camera_i2c_client *, uint32_t, + uint8_t *, uint32_t); + int (*i2c_write) (struct msm_camera_i2c_client *, uint32_t, uint16_t, + enum msm_camera_i2c_data_type); + int (*i2c_write_seq) (struct msm_camera_i2c_client *, uint32_t , + uint8_t *, uint32_t); + int32_t (*i2c_write_table)(struct msm_camera_i2c_client *, + struct msm_camera_i2c_reg_setting *); + int32_t (*i2c_write_burst_table)(struct msm_camera_i2c_client *, + struct msm_camera_i2c_reg_setting *); + int32_t (*i2c_write_seq_table)(struct msm_camera_i2c_client *, + struct msm_camera_i2c_seq_reg_setting *); + int32_t (*i2c_write_table_w_microdelay) + (struct msm_camera_i2c_client *, + struct msm_camera_i2c_reg_setting *); + int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t); + int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + int32_t (*i2c_poll)(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); +}; + +int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_cci_i2c_write_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_cci_i2c_write_burst_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_cci_i2c_write_seq_table( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting); + +int32_t msm_camera_cci_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_cci_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client, + uint16_t cci_cmd); + +int32_t msm_camera_cci_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting); + +int32_t msm_camera_qup_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting); + +int32_t msm_camera_qup_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type); + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c_mux.c b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c_mux.c new file mode 100644 index 0000000000000000000000000000000000000000..cd2af2c2751eabdafe9d0e19e3e97091fb86fc6b --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c_mux.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2011-2013, The Linux Foundatation. 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 and + * only 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 +#include +#include +#include +#include +#include +#include "msm_camera_i2c_mux.h" + +/* TODO move this somewhere else */ +#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux" +static int msm_i2c_mux_config(struct i2c_mux_device *mux_device, uint8_t *mode) +{ + uint32_t val; + val = msm_camera_io_r(mux_device->ctl_base); + if (*mode == MODE_DUAL) { + msm_camera_io_w(val | 0x3, mux_device->ctl_base); + } else if (*mode == MODE_L) { + msm_camera_io_w(((val | 0x2) & ~(0x1)), mux_device->ctl_base); + val = msm_camera_io_r(mux_device->ctl_base); + CDBG("the camio mode config left value is %d\n", val); + } else { + msm_camera_io_w(((val | 0x1) & ~(0x2)), mux_device->ctl_base); + val = msm_camera_io_r(mux_device->ctl_base); + CDBG("the camio mode config right value is %d\n", val); + } + return 0; +} + +static int msm_i2c_mux_init(struct i2c_mux_device *mux_device) +{ + int rc = 0, val = 0; + if (mux_device->use_count == 0) { + mux_device->ctl_base = ioremap(mux_device->ctl_mem->start, + resource_size(mux_device->ctl_mem)); + if (!mux_device->ctl_base) { + rc = -ENOMEM; + return rc; + } + mux_device->rw_base = ioremap(mux_device->rw_mem->start, + resource_size(mux_device->rw_mem)); + if (!mux_device->rw_base) { + rc = -ENOMEM; + iounmap(mux_device->ctl_base); + return rc; + } + val = msm_camera_io_r(mux_device->rw_base); + msm_camera_io_w((val | 0x200), mux_device->rw_base); + } + mux_device->use_count++; + return 0; +}; + +static int msm_i2c_mux_release(struct i2c_mux_device *mux_device) +{ + int val = 0; + mux_device->use_count--; + if (mux_device->use_count == 0) { + val = msm_camera_io_r(mux_device->rw_base); + msm_camera_io_w((val & ~0x200), mux_device->rw_base); + iounmap(mux_device->rw_base); + iounmap(mux_device->ctl_base); + } + return 0; +} + +static long msm_i2c_mux_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct i2c_mux_device *mux_device; + int rc = 0; + mux_device = v4l2_get_subdevdata(sd); + if (mux_device == NULL) { + rc = -ENOMEM; + return rc; + } + mutex_lock(&mux_device->mutex); + switch (cmd) { + case VIDIOC_MSM_I2C_MUX_CFG: + rc = msm_i2c_mux_config(mux_device, (uint8_t *) arg); + break; + case VIDIOC_MSM_I2C_MUX_INIT: + rc = msm_i2c_mux_init(mux_device); + break; + case VIDIOC_MSM_I2C_MUX_RELEASE: + rc = msm_i2c_mux_release(mux_device); + break; + default: + rc = -ENOIOCTLCMD; + } + mutex_unlock(&mux_device->mutex); + return rc; +} + +static struct v4l2_subdev_core_ops msm_i2c_mux_subdev_core_ops = { + .ioctl = &msm_i2c_mux_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_i2c_mux_subdev_ops = { + .core = &msm_i2c_mux_subdev_core_ops, +}; + +static int i2c_mux_probe(struct platform_device *pdev) +{ + struct i2c_mux_device *mux_device; + int rc = 0; + CDBG("%s: device id = %d\n", __func__, pdev->id); + mux_device = kzalloc(sizeof(struct i2c_mux_device), GFP_KERNEL); + if (!mux_device) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + v4l2_subdev_init(&mux_device->subdev, &msm_i2c_mux_subdev_ops); + v4l2_set_subdevdata(&mux_device->subdev, mux_device); + platform_set_drvdata(pdev, &mux_device->subdev); + mutex_init(&mux_device->mutex); + + mux_device->ctl_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "i2c_mux_ctl"); + if (!mux_device->ctl_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto i2c_mux_no_resource; + } + mux_device->ctl_io = request_mem_region(mux_device->ctl_mem->start, + resource_size(mux_device->ctl_mem), pdev->name); + if (!mux_device->ctl_io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto i2c_mux_no_resource; + } + mux_device->rw_mem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "i2c_mux_rw"); + if (!mux_device->rw_mem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto i2c_mux_no_resource; + } + mux_device->rw_io = request_mem_region(mux_device->rw_mem->start, + resource_size(mux_device->rw_mem), pdev->name); + if (!mux_device->rw_io) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto i2c_mux_no_resource; + } + mux_device->pdev = pdev; + return 0; + +i2c_mux_no_resource: + mutex_destroy(&mux_device->mutex); + kfree(mux_device); + return 0; +} + +static struct platform_driver i2c_mux_driver = { + .probe = i2c_mux_probe, + .driver = { + .name = MSM_I2C_MUX_DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_camera_i2c_mux_init_module(void) +{ + return platform_driver_register(&i2c_mux_driver); +} + +static void __exit msm_camera_i2c_mux_exit_module(void) +{ + platform_driver_unregister(&i2c_mux_driver); +} + +module_init(msm_camera_i2c_mux_init_module); +module_exit(msm_camera_i2c_mux_exit_module); +MODULE_DESCRIPTION("MSM Camera I2C mux driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c_mux.h b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c_mux.h new file mode 100644 index 0000000000000000000000000000000000000000..30f908b12e155e054c6cec7631e0891310ce072b --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_i2c_mux.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_I2C_MUX_H +#define MSM_I2C_MUX_H + +#include +#include + +struct i2c_mux_device { + struct platform_device *pdev; + struct v4l2_subdev subdev; + struct resource *ctl_mem; + struct resource *ctl_io; + void __iomem *ctl_base; + struct resource *rw_mem; + struct resource *rw_io; + void __iomem *rw_base; + struct mutex mutex; + unsigned use_count; +}; + +struct i2c_mux_cfg_params { + struct v4l2_subdev *subdev; + void *parms; +}; + +#define VIDIOC_MSM_I2C_MUX_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct i2c_mux_cfg_params) + +#define VIDIOC_MSM_I2C_MUX_INIT \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct v4l2_subdev*) + +#define VIDIOC_MSM_I2C_MUX_RELEASE \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct v4l2_subdev*) + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_io_util.c new file mode 100644 index 0000000000000000000000000000000000000000..cce3f08d6907d3318889e8a6d425006edeb60bb6 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_io_util.c @@ -0,0 +1,666 @@ +/* Copyright (c) 2011-2014, The Linux Foundataion. 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 and + * only 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 +#include +#include +#include +#include +#include +#include "../../include/soc/qcom/camera2.h" +#include +#include +#include "msm_camera_io_util.h" + +#define BUFF_SIZE_128 128 + +//#define CONFIG_MSMB_CAMERA_DEBUG 1 +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +#ifdef CONFIG_MFD_RT5033_RESET_WA +#ifdef CONFIG_CAM_USE_EXT_VANA_GPIO +#define RT5033_RESET_WA_VREG_NAME ("cam_vdig") +#else +#define RT5033_RESET_WA_VREG_NAME ("cam_vana") +#endif +#endif + +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) +extern unsigned int system_rev; +#endif + +void msm_camera_io_w(u32 data, void __iomem *addr) +{ + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + writel_relaxed((data), (addr)); +} + +void msm_camera_io_w_mb(u32 data, void __iomem *addr) +{ + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + wmb(); + writel_relaxed((data), (addr)); + wmb(); +} + +u32 msm_camera_io_r(void __iomem *addr) +{ + uint32_t data = readl_relaxed(addr); + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + return data; +} + +u32 msm_camera_io_r_mb(void __iomem *addr) +{ + uint32_t data; + rmb(); + data = readl_relaxed(addr); + rmb(); + CDBG("%s: 0x%p %08x\n", __func__, (addr), (data)); + return data; +} + +void msm_camera_io_memcpy_toio(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + + for (i = 0; i < len; i++) + writel_relaxed(*s++, d++); +} + +void msm_camera_io_dump(void __iomem *addr, int size) +{ + char line_str[BUFF_SIZE_128], *p_str; + int i; + u32 *p = (u32 *) addr; + u32 data; + CDBG("%s: %p %d\n", __func__, addr, size); + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size/4; i++) { + if (i % 4 == 0) { + snprintf(p_str, 12, "0x%p: ", p); + p_str += 10; + } + data = readl_relaxed(p++); + snprintf(p_str, 12, "%d ", data); + p_str += 9; + if ((i + 1) % 4 == 0) { + CDBG("%s\n", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CDBG("%s\n", line_str); +} + +void msm_camera_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len); + msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4); + msm_camera_io_dump(dest_addr, len); +} + +void msm_camera_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + + for (i = 0; i < (len / 4); i++) + msm_camera_io_w_mb(*s++, d++); +} + +int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, + struct msm_cam_clk_info *clk_src_info, int num_clk) +{ + int i; + int rc = 0; + struct clk *mux_clk = NULL; + struct clk *src_clk = NULL; + + for (i = 0; i < num_clk; i++) { + if (clk_src_info[i].clk_name) { + mux_clk = clk_get(dev, clk_info[i].clk_name); + if (IS_ERR(mux_clk)) { + pr_err("%s get failed\n", + clk_info[i].clk_name); + continue; + } + src_clk = clk_get(dev, clk_src_info[i].clk_name); + if (IS_ERR(src_clk)) { + pr_err("%s get failed\n", + clk_src_info[i].clk_name); + continue; + } + clk_set_parent(mux_clk, src_clk); + } + } + return rc; +} + +int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, + struct clk **clk_ptr, int num_clk, int enable) +{ + int i; + int rc = 0; + long clk_rate; + if (enable) { + for (i = 0; i < num_clk; i++) { + CDBG("%s enable %s\n", __func__, + clk_info[i].clk_name); + clk_ptr[i] = clk_get(dev, clk_info[i].clk_name); + if (IS_ERR(clk_ptr[i])) { + pr_err("%s get failed\n", clk_info[i].clk_name); + rc = PTR_ERR(clk_ptr[i]); + goto cam_clk_get_err; + } + if (clk_info[i].clk_rate > 0) { + rc = clk_set_rate(clk_ptr[i], + clk_info[i].clk_rate); + if (rc < 0) { + pr_err("%s set failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + } else if (clk_info[i].clk_rate == INIT_RATE) { + clk_rate = clk_get_rate(clk_ptr[i]); + if (clk_rate == 0) { + clk_rate = + clk_round_rate(clk_ptr[i], 0); + if (clk_rate < 0) { + pr_err("%s round rate failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + rc = clk_set_rate(clk_ptr[i], + clk_rate); + if (rc < 0) { + pr_err("%s set rate failed\n", + clk_info[i].clk_name); + goto cam_clk_set_err; + } + } + } + rc = clk_prepare(clk_ptr[i]); + if (rc < 0) { + pr_err("%s prepare failed\n", + clk_info[i].clk_name); + goto cam_clk_prepare_err; + } + + rc = clk_enable(clk_ptr[i]); + if (rc < 0) { + pr_err("%s enable failed\n", + clk_info[i].clk_name); + goto cam_clk_enable_err; + } + if (clk_info[i].delay > 20) { + msleep(clk_info[i].delay); + } else if (clk_info[i].delay) { + usleep_range(clk_info[i].delay * 1000, + (clk_info[i].delay * 1000) + 1000); + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + if (clk_ptr[i] != NULL) { + CDBG("%s disable %s\n", __func__, + clk_info[i].clk_name); + clk_disable(clk_ptr[i]); + clk_unprepare(clk_ptr[i]); + clk_put(clk_ptr[i]); + } + } + } + return rc; + + +cam_clk_enable_err: + clk_unprepare(clk_ptr[i]); +cam_clk_prepare_err: +cam_clk_set_err: + clk_put(clk_ptr[i]); +cam_clk_get_err: + for (i--; i >= 0; i--) { + if (clk_ptr[i] != NULL) { + clk_disable(clk_ptr[i]); + clk_unprepare(clk_ptr[i]); + clk_put(clk_ptr[i]); + } + } + return rc; +} + +int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int config) +{ + int i = 0, j = 0; + int rc = 0; + struct camera_vreg_t *curr_vreg; + + if (num_vreg_seq > num_vreg) { + pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); + return -EINVAL; + } + if (!num_vreg_seq) + num_vreg_seq = num_vreg; + + if (config) { + for (i = 0; i < num_vreg_seq; i++) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + curr_vreg = &cam_vreg[j]; + reg_ptr[j] = regulator_get(dev, + curr_vreg->reg_name); + if (IS_ERR(reg_ptr[j])) { + pr_err("%s: %s get failed\n", + __func__, + curr_vreg->reg_name); + reg_ptr[j] = NULL; + goto vreg_get_fail; + } + if (curr_vreg->type == REG_LDO) { + rc = regulator_set_voltage( + reg_ptr[j], + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + pr_err("%s: %s set voltage failed\n", + __func__, + curr_vreg->reg_name); + goto vreg_set_voltage_fail; + } + if (curr_vreg->op_mode >= 0) { + rc = regulator_set_optimum_mode( + reg_ptr[j], + curr_vreg->op_mode); + if (rc < 0) { + pr_err( + "%s:%s set optimum mode fail\n", + __func__, + curr_vreg->reg_name); + goto vreg_set_opt_mode_fail; + } + } + } + } + } else { + for (i = num_vreg_seq-1; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + curr_vreg = &cam_vreg[j]; + if (reg_ptr[j]) { + if (curr_vreg->type == REG_LDO) { + if (curr_vreg->op_mode >= 0) { + regulator_set_optimum_mode( + reg_ptr[j], 0); + } + regulator_set_voltage( + reg_ptr[j], 0, curr_vreg-> + max_voltage); + } + regulator_put(reg_ptr[j]); + reg_ptr[j] = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (curr_vreg->type == REG_LDO) + regulator_set_optimum_mode(reg_ptr[j], 0); + +vreg_set_opt_mode_fail: +if (curr_vreg->type == REG_LDO) + regulator_set_voltage(reg_ptr[j], 0, + curr_vreg->max_voltage); + +vreg_set_voltage_fail: + regulator_put(reg_ptr[j]); + reg_ptr[j] = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + curr_vreg = &cam_vreg[j]; + goto vreg_unconfig; + } + return -ENODEV; +} + +int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int enable) +{ + int i = 0, j = 0, rc = 0; + + if (num_vreg_seq > num_vreg) { + pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__); + return -EINVAL; + } + if (!num_vreg_seq) + num_vreg_seq = num_vreg; + + if (enable) { + for (i = 0; i < num_vreg_seq; i++) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + if (IS_ERR(reg_ptr[j])) { + pr_err("%s: %s null regulator\n", + __func__, cam_vreg[j].reg_name); + goto disable_vreg; + } + rc = regulator_enable(reg_ptr[j]); + if (rc < 0) { + pr_err("%s: %s enable failed\n", + __func__, cam_vreg[j].reg_name); + goto disable_vreg; + } + if (cam_vreg[j].delay > 20) + msleep(cam_vreg[j].delay); + else if (cam_vreg[j].delay) + usleep_range(cam_vreg[j].delay * 1000, + (cam_vreg[j].delay * 1000) + 1000); + } + } else { + for (i = num_vreg_seq-1; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + regulator_disable(reg_ptr[j]); + if (cam_vreg[j].delay > 20) + msleep(cam_vreg[j].delay); + else if (cam_vreg[j].delay) + usleep_range(cam_vreg[j].delay * 1000, + (cam_vreg[j].delay * 1000) + 1000); + } + } + return rc; +disable_vreg: + for (i--; i >= 0; i--) { + if (vreg_seq) { + j = vreg_seq[i]; + if (j >= num_vreg) + continue; + } else + j = i; + regulator_disable(reg_ptr[j]); + if (cam_vreg[j].delay > 20) + msleep(cam_vreg[j].delay); + else if (cam_vreg[j].delay) + usleep_range(cam_vreg[j].delay * 1000, + (cam_vreg[j].delay * 1000) + 1000); + } + return rc; +} + +void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, + enum msm_bus_perf_setting perf_setting) +{ + int rc = 0; + if (!bus_perf_client) { + pr_err("%s: Bus Client NOT Registered!!!\n", __func__); + return; + } + + switch (perf_setting) { + case S_EXIT: + rc = msm_bus_scale_client_update_request(bus_perf_client, 1); + msm_bus_scale_unregister_client(bus_perf_client); + break; + case S_PREVIEW: + rc = msm_bus_scale_client_update_request(bus_perf_client, 1); + break; + case S_VIDEO: + rc = msm_bus_scale_client_update_request(bus_perf_client, 2); + break; + case S_CAPTURE: + rc = msm_bus_scale_client_update_request(bus_perf_client, 3); + break; + case S_ZSL: + rc = msm_bus_scale_client_update_request(bus_perf_client, 4); + break; + case S_LIVESHOT: + rc = msm_bus_scale_client_update_request(bus_perf_client, 5); + break; + case S_DEFAULT: + break; + default: + pr_warning("%s: INVALID CASE\n", __func__); + } +} + +int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, + uint8_t gpio_tbl_size, int gpio_en) +{ + int rc = 0, i; + + if (gpio_en) { + for (i = 0; i < gpio_tbl_size; i++) { + gpio_set_value_cansleep(gpio_tbl[i].gpio, + gpio_tbl[i].flags); + usleep_range(gpio_tbl[i].delay, + gpio_tbl[i].delay + 1000); + } + } else { + for (i = gpio_tbl_size - 1; i >= 0; i--) { + if (gpio_tbl[i].flags) + gpio_set_value_cansleep(gpio_tbl[i].gpio, + GPIOF_OUT_INIT_LOW); + } + } + return rc; +} + +int msm_camera_config_single_vreg(struct device *dev, + struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config) +{ + int rc = 0; +#ifdef CONFIG_MFD_RT5033_RESET_WA + int rt_rc = 0; +#endif + + if (config) { + if (!dev || !cam_vreg || !reg_ptr) { + pr_err("%s: get failed NULL parameter\n", __func__); + goto vreg_get_fail; + } + CDBG("%s enable %s\n", __func__, cam_vreg->reg_name); + if (!strncmp(cam_vreg->reg_name, "cam_vdig", 8)) { +#if defined(CONFIG_SEC_ROSSA_PROJECT) + *reg_ptr = regulator_get(dev, "CAM_SENSOR_IO_1.8V"); +#elif defined(CONFIG_SEC_NOVEL_PROJECT) + *reg_ptr = regulator_get(dev, "CAM_SENSOR_CORE_1.8V"); +#else + *reg_ptr = regulator_get(dev, "CAM_SENSOR_CORE_1.2V"); +#endif + if (IS_ERR(*reg_ptr)) { + pr_err("%s: %s get failed\n", __func__, + cam_vreg->reg_name); + *reg_ptr = NULL; + goto vreg_get_fail; + } +#if defined(CONFIG_SEC_NOVEL_PROJECT) + } else if (!strncmp(cam_vreg->reg_name, "cam_vana_vt", 11)) { + *reg_ptr = regulator_get(dev, "LDO3"); + if (IS_ERR(*reg_ptr)) { + pr_err("%s: %s get failed\n", __func__, + cam_vreg->reg_name); + *reg_ptr = NULL; + goto vreg_get_fail; + } +#endif + } else if (!strncmp(cam_vreg->reg_name, "cam_vana", 8)) { + *reg_ptr = regulator_get(dev, "CAM_SENSOR_A2.8V"); + if (IS_ERR(*reg_ptr)) { + pr_err("%s: %s get failed\n", __func__, + cam_vreg->reg_name); + *reg_ptr = NULL; + goto vreg_get_fail; + } +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) + } else if (!strncmp(cam_vreg->reg_name, "cam_vio_vt", 10)) { + pr_err("[cam_vio_vt]%s:%d system_rev:%d\n", __func__, __LINE__, system_rev); + if(system_rev == 0) { + *reg_ptr = regulator_get(dev, "LDO2"); + if (IS_ERR(*reg_ptr)) { + pr_err("%s: %s get failed\n", __func__, + cam_vreg->reg_name); + *reg_ptr = NULL; + goto vreg_get_fail; + } + } +#endif + } else { + *reg_ptr = regulator_get(dev, cam_vreg->reg_name); + if (IS_ERR_OR_NULL(*reg_ptr)) { + pr_err("%s: %s get failed\n", __func__, + cam_vreg->reg_name); + *reg_ptr = NULL; + goto vreg_get_fail; + } + if (cam_vreg->type == REG_LDO) { + rc = regulator_set_voltage( + *reg_ptr, cam_vreg->min_voltage, + cam_vreg->max_voltage); + if (rc < 0) { + pr_err("%s: %s set voltage failed\n", + __func__, cam_vreg->reg_name); + goto vreg_set_voltage_fail; + } + if (cam_vreg->op_mode >= 0) { + rc = regulator_set_optimum_mode(*reg_ptr, + cam_vreg->op_mode); + if (rc < 0) { + pr_err( + "%s: %s set optimum mode failed\n", + __func__, cam_vreg->reg_name); + goto vreg_set_opt_mode_fail; + } + } + } + } +#ifdef CONFIG_MFD_RT5033_RESET_WA + if (!strncmp(cam_vreg->reg_name, RT5033_RESET_WA_VREG_NAME, 8)){ + rt_rc = regulator_get_status(*reg_ptr); + if((rt_rc == 2) || (rt_rc == 8)){ + BUG_ON(1); + } else { + pr_err("[RT5033] result : 0x%x\n", rt_rc); + } + } +#endif + rc = regulator_enable(*reg_ptr); + if (rc < 0) { + pr_err("%s: %s enable failed\n", + __func__, cam_vreg->reg_name); + goto vreg_unconfig; + } + } else { + if (*reg_ptr) { + CDBG("%s disable %s\n", __func__, cam_vreg->reg_name); + regulator_disable(*reg_ptr); + if (cam_vreg->type == REG_LDO) { + if (cam_vreg->op_mode >= 0) + regulator_set_optimum_mode(*reg_ptr, 0); + regulator_set_voltage( + *reg_ptr, 0, cam_vreg->max_voltage); + } + regulator_put(*reg_ptr); + *reg_ptr = NULL; + } + } + return 0; + +vreg_unconfig: +if (cam_vreg->type == REG_LDO) + regulator_set_optimum_mode(*reg_ptr, 0); + +vreg_set_opt_mode_fail: +if (cam_vreg->type == REG_LDO) + regulator_set_voltage(*reg_ptr, 0, cam_vreg->max_voltage); + +vreg_set_voltage_fail: + regulator_put(*reg_ptr); + *reg_ptr = NULL; + +vreg_get_fail: + return -ENODEV; +} + +int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, + int gpio_en) +{ + int rc = 0, i = 0, err = 0; + + if (!gpio_tbl || !size) { + pr_err("%s:%d invalid gpio_tbl %p / size %d\n", __func__, + __LINE__, gpio_tbl, size); + return -EINVAL; + } + for (i = 0; i < size; i++) { + CDBG("%s:%d i %d, gpio %d dir %ld\n", __func__, __LINE__, i, + gpio_tbl[i].gpio, gpio_tbl[i].flags); + } + if (gpio_en) { + for (i = 0; i < size; i++) { + err = gpio_request_one(gpio_tbl[i].gpio, + gpio_tbl[i].flags, gpio_tbl[i].label); + if (err) { + /* + * After GPIO request fails, contine to + * apply new gpios, outout a error message + * for driver bringup debug + */ + pr_err("%s:%d gpio %d:%s request fails\n", + __func__, __LINE__, + gpio_tbl[i].gpio, gpio_tbl[i].label); + } + } + } else { + gpio_free_array(gpio_tbl, size); + } + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_io_util.h new file mode 100644 index 0000000000000000000000000000000000000000..04d34092b90b62a4b6276feb78a8d8f39215a51a --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_io_util.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2011-2014, The Linux Foundataion. 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 and + * only 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. + */ + +#ifndef __MSM_CAMERA_IO_UTIL_H +#define __MSM_CAMERA_IO_UTIL_H + +#include +#include +#include "../../include/soc/qcom/camera2.h" +#include "../../include/media/msm_cam_sensor.h" + +#define NO_SET_RATE -1 +#define INIT_RATE -2 + +void msm_camera_io_w(u32 data, void __iomem *addr); +void msm_camera_io_w_mb(u32 data, void __iomem *addr); +u32 msm_camera_io_r(void __iomem *addr); +u32 msm_camera_io_r_mb(void __iomem *addr); +void msm_camera_io_dump(void __iomem *addr, int size); +void msm_camera_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, u32 len); +void msm_camera_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, u32 len); +int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, + struct msm_cam_clk_info *clk_src_info, int num_clk); +int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, + struct clk **clk_ptr, int num_clk, int enable); + +int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int config); +int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg, + int num_vreg, enum msm_camera_vreg_name_t *vreg_seq, + int num_vreg_seq, struct regulator **reg_ptr, int enable); + +void msm_camera_bus_scale_cfg(uint32_t bus_perf_client, + enum msm_bus_perf_setting perf_setting); + +int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl, + uint8_t gpio_tbl_size, int gpio_en); + +void msm_camera_config_single_gpio(uint16_t gpio, unsigned long flags, + int gpio_en); + +int msm_camera_config_single_vreg(struct device *dev, + struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config); + +int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size, + int gpio_en); + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_qup_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..4e29f8b086aee454235e022423c19c5883fd5261 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_qup_i2c.c @@ -0,0 +1,546 @@ +/* Copyright (c) 2011, 2013-2014, The Linux Foundation. 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 and + * only 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 "../../include/soc/qcom/camera2.h" +#include "msm_camera_i2c.h" + +//#define CONFIG_MSMB_CAMERA_DEBUG 1 +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#define S_I2C_DBG(fmt, args...) do { } while (0) +#endif + +#define I2C_COMPARE_MATCH 0 +#define I2C_COMPARE_MISMATCH 1 +#define I2C_POLL_MAX_ITERATION 20 + +static int32_t msm_camera_qup_i2c_rxdata( + struct msm_camera_i2c_client *dev_client, unsigned char *rxdata, + int data_length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = dev_client->addr_type, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = data_length, + .buf = rxdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msgs, 2); + if (rc < 0) + S_I2C_DBG("msm_camera_qup_i2c_rxdata failed 0x%x\n", saddr); + return rc; +} + +static int32_t msm_camera_qup_i2c_txdata( + struct msm_camera_i2c_client *dev_client, unsigned char *txdata, + int length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msg, 1); + if (rc < 0) + S_I2C_DBG("msm_camera_qup_i2c_txdata faild 0x%x\n", saddr); + return rc; +} + +int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } + rc = msm_camera_qup_i2c_rxdata(client, buf, data_type); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); + return rc; + } + + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) + *data = buf[0]; + else + *data = buf[0] << 8 | buf[1]; + + S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); + return rc; +} + +int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+num_byte]; + int i; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } + rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte); + if (rc < 0) { + S_I2C_DBG("%s fail\n", __func__); + return rc; + } + + S_I2C_DBG("%s addr = 0x%x", __func__, addr); + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + return rc; +} + +int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+data_type]; + uint8_t len = 0; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (data_type != MSM_CAMERA_I2C_BYTE_DATA + && data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x data type: %d\n", + __func__, addr, data_type); + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + len = 1; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len+1, buf[len+1]); + len = 2; + } + S_I2C_DBG("Data: 0x%x\n", data); + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) { + buf[len] = data; + S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); + len += 1; + } else if (data_type == MSM_CAMERA_I2C_WORD_DATA) { + buf[len] = data >> BITS_PER_BYTE; + buf[len+1] = data; + S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]); + S_I2C_DBG("Byte %d: 0x%x\n", len+1, buf[len+1]); + len += 2; + } + rc = msm_camera_qup_i2c_txdata(client, buf, len); + if (rc < 0) + S_I2C_DBG("%s fail\n", __func__); + return rc; +} + +int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char buf[client->addr_type+num_byte]; + uint8_t len = 0, i = 0; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || num_byte == 0) + return rc; + + S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n", + __func__, addr, num_byte); + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { + buf[0] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + len = 1; + } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len, buf[len]); + S_I2C_DBG("%s byte %d: 0x%x\n", __func__, + len+1, buf[len+1]); + len = 2; + } + for (i = 0; i < num_byte; i++) { + buf[i+len] = data[i]; + S_I2C_DBG("Byte %d: 0x%x\n", i+len, buf[i+len]); + S_I2C_DBG("Data: 0x%x\n", data[i]); + } + rc = msm_camera_qup_i2c_txdata(client, buf, len+num_byte); + if (rc < 0) + S_I2C_DBG("%s fail\n", __func__); + return rc; +} + +int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_reg_array *reg_setting; + uint16_t client_addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + reg_setting = write_setting->reg_setting; + client_addr_type = client->addr_type; + client->addr_type = write_setting->addr_type; + + for (i = 0; i < write_setting->size; i++) { + CDBG("%s addr 0x%x data 0x%x\n", __func__, + reg_setting->reg_addr, reg_setting->reg_data); + + rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, + reg_setting->reg_data, write_setting->data_type); + if (rc < 0) + break; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + client->addr_type = client_addr_type; + return rc; +} + +int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client, + struct msm_camera_i2c_seq_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_seq_reg_array *reg_setting; + uint16_t client_addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) { + pr_err("%s Invalide addr type %d\n", __func__, + write_setting->addr_type); + return rc; + } + + reg_setting = write_setting->reg_setting; + client_addr_type = client->addr_type; + client->addr_type = write_setting->addr_type; + + for (i = 0; i < write_setting->size; i++) { + rc = msm_camera_qup_i2c_write_seq(client, reg_setting->reg_addr, + reg_setting->reg_data, reg_setting->reg_data_size); + if (rc < 0) + break; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + client->addr_type = client_addr_type; + return rc; +} + +int32_t msm_camera_qup_i2c_write_table_w_microdelay( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = -EFAULT; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (!client || !write_setting) + return rc; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR + && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA + && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + reg_setting = write_setting->reg_setting; + for (i = 0; i < write_setting->size; i++) { + rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr, + reg_setting->reg_data, write_setting->data_type); + if (rc < 0) + break; + if (reg_setting->delay) + usleep_range(reg_setting->delay, + reg_setting->delay + 1000); + reg_setting++; + } + return rc; +} + +static int32_t msm_camera_qup_i2c_compare(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data = 0; + int data_len = 0; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + data_len = data_type; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + data_len = MSM_CAMERA_I2C_BYTE_DATA; + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + data_len = MSM_CAMERA_I2C_WORD_DATA; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_len); + if (rc < 0) + return rc; + + rc = I2C_COMPARE_MISMATCH; + switch (data_type) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + if (data == reg_data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + case MSM_CAMERA_I2C_SET_WORD_MASK: + if ((reg_data & data) == data) + rc = I2C_COMPARE_MATCH; + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + if (!(reg_data & data)) + rc = I2C_COMPARE_MATCH; + break; + default: + pr_err("%s: Unsupport data type: %d\n", __func__, data_type); + break; + } + + S_I2C_DBG("%s: Register and data match result %d\n", __func__, + rc); + return rc; +} + +int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + int i; + S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n", + __func__, addr, data, data_type); + + for (i = 0; i < I2C_POLL_MAX_ITERATION; i++) { + rc = msm_camera_qup_i2c_compare(client, + addr, data, data_type); + if (rc == 0 || rc < 0) + break; + usleep_range(10000, 11000); + } + return rc; +} + +static int32_t msm_camera_qup_i2c_set_mask(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t mask, + enum msm_camera_i2c_data_type data_type, uint16_t set_mask) +{ + int32_t rc; + uint16_t reg_data; + + rc = msm_camera_qup_i2c_read(client, addr, ®_data, data_type); + if (rc < 0) { + S_I2C_DBG("%s read fail\n", __func__); + return rc; + } + S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n", + __func__, addr, reg_data, mask); + + if (set_mask) + reg_data |= mask; + else + reg_data &= ~mask; + S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data); + + rc = msm_camera_qup_i2c_write(client, addr, reg_data, data_type); + if (rc < 0) + S_I2C_DBG("%s write fail\n", __func__); + + return rc; +} + +static int32_t msm_camera_qup_i2c_set_write_mask_data( + struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t data, int16_t mask, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc; + uint16_t reg_data; + CDBG("%s\n", __func__); + if (mask == -1) + return 0; + if (mask == 0) { + rc = msm_camera_qup_i2c_write(client, addr, data, data_type); + } else { + rc = msm_camera_qup_i2c_read(client, addr, ®_data, + data_type); + if (rc < 0) { + CDBG("%s read fail\n", __func__); + return rc; + } + reg_data &= ~mask; + reg_data |= (data & mask); + rc = msm_camera_qup_i2c_write(client, addr, reg_data, + data_type); + if (rc < 0) + CDBG("%s write fail\n", __func__); + } + return rc; +} + + +int32_t msm_camera_qup_i2c_write_conf_tbl( + struct msm_camera_i2c_client *client, + struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size, + enum msm_camera_i2c_data_type data_type) +{ + int i; + int32_t rc = -EFAULT; + pr_err("%s, E. ", __func__); + for (i = 0; i < size; i++) { + enum msm_camera_i2c_data_type dt; + if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) { + rc = msm_camera_qup_i2c_poll(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->dt); + } else { + if (reg_conf_tbl->dt == 0) + dt = data_type; + else + dt = reg_conf_tbl->dt; + switch (dt) { + case MSM_CAMERA_I2C_BYTE_DATA: + case MSM_CAMERA_I2C_WORD_DATA: + rc = msm_camera_qup_i2c_write( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, dt); + break; + case MSM_CAMERA_I2C_SET_BYTE_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_BYTE_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_BYTE_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_WORD_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 1); + break; + case MSM_CAMERA_I2C_UNSET_WORD_MASK: + rc = msm_camera_qup_i2c_set_mask(client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + MSM_CAMERA_I2C_WORD_DATA, 0); + break; + case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA: + rc = msm_camera_qup_i2c_set_write_mask_data( + client, + reg_conf_tbl->reg_addr, + reg_conf_tbl->reg_data, + reg_conf_tbl->mask, + MSM_CAMERA_I2C_BYTE_DATA); + break; + default: + pr_err("%s: Unsupport data type: %d\n", + __func__, dt); + break; + } + } + if (rc < 0) + break; + reg_conf_tbl++; + } + return rc; +} + diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_spi.c b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..9fb1b7cf2c9fa39b1d176a5ffcc9b5f9c8fbebb0 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_spi.c @@ -0,0 +1,407 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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 "../../include/soc/qcom/camera2.h" +#include "msm_camera_spi.h" + +//#define CONFIG_MSMB_CAMERA_DEBUG 1 +#undef SPIDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define SPIDBG(fmt, args...) pr_debug(fmt, ##args) +#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args) +#else +#define SPIDBG(fmt, args...) do { } while (0) +#define S_I2C_DBG(fmt, args...) do { } while (0) +#endif + +static int msm_camera_spi_txfr(struct spi_device *spi, char *txbuf, + char *rxbuf, int num_byte) +{ + struct spi_transfer t; + struct spi_message m; + + memset(&t, 0, sizeof(t)); + t.tx_buf = txbuf; + t.rx_buf = rxbuf; + t.len = num_byte; + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + return spi_sync(spi, &m); +} + +/** + * msm_camera_set_addr() - helper function to set transfer address + * @addr: device address + * @addr_len: the addr field length of an instruction + * @type: type (i.e. byte-length) of @addr + * @str: shifted address output, must be zeroed when passed in + * + * This helper function sets @str based on the addr field length of an + * instruction and the data length. + */ +static void msm_camera_set_addr(uint32_t addr, uint8_t addr_len, + enum msm_camera_i2c_reg_addr_type type, + char *str) +{ + int i, len; + + if (addr_len < type) + SPIDBG("%s: omitting higher bits in address\n", __func__); + + /* only support transfer MSB first for now */ + len = addr_len - type; + for (i = len; i < addr_len; i++) { + if (i >= 0) + str[i] = (addr >> (BITS_PER_BYTE * (addr_len - i - 1))) + & 0xFF; + } + +} + +/** + * msm_camera_spi_tx_helper() - wrapper for SPI transaction + * @client: io client + * @inst: inst of this transaction + * @addr: device addr following the inst + * @data: output byte array (could be NULL) + * @num_byte: size of @data + * @tx, rx: optional transfer buffer. It must be at least header + * + @num_byte long. + * + * This is the core function for SPI transaction, except for writes. It first + * checks address type, then allocates required memory for tx/rx buffers. + * It sends out , and optionally receives @num_byte of response, + * if @data is not NULL. This function does not check for wait conditions, + * and will return immediately once bus transaction finishes. + * + * This function will allocate buffers of header + @num_byte long. For + * large transfers, the allocation could fail. External buffer @tx, @rx + * should be passed in to bypass allocation. The size of buffer should be + * at least header + num_byte long. Since buffer is managed externally, + * @data will be ignored, and read results will be in @rx. + * @tx, @rx also can be used for repeated transfers to improve performance. + */ +int32_t msm_camera_spi_tx_helper(struct msm_camera_i2c_client *client, + struct msm_camera_spi_inst *inst, uint32_t addr, uint8_t *data, + uint32_t num_byte, char *tx, char *rx) +{ + int32_t rc = -EINVAL; + struct spi_device *spi = client->spi_client->spi_master; + char *ctx = NULL, *crx = NULL; + uint32_t len, hlen; + uint8_t retries = client->spi_client->retries; + + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) + && (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) + return rc; + + hlen = msm_camera_spi_get_hlen(inst); + len = hlen + num_byte; + + if (tx) + ctx = tx; + else + ctx = kzalloc(len, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (num_byte) { + if (rx) + crx = rx; + else + crx = kzalloc(len, GFP_KERNEL); + if (!crx) { + if (!tx) + kfree(ctx); + return -ENOMEM; + } + } else { + crx = NULL; + } + + ctx[0] = inst->opcode; + msm_camera_set_addr(addr, inst->addr_len, client->addr_type, ctx + 1); + while ((rc = msm_camera_spi_txfr(spi, ctx, crx, len)) && retries) { + retries--; + msleep(client->spi_client->retry_delay); + } + if (rc < 0) { + SPIDBG("%s: failed %d\n", __func__, rc); + goto out; + } + if (data && num_byte && !rx) + memcpy(data, crx + hlen, num_byte); + +out: + if (!tx) + kfree(ctx); + if (!rx) + kfree(crx); + return rc; +} + +int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type) +{ + int32_t rc = -EINVAL; + uint8_t temp[2]; + + if ((data_type != MSM_CAMERA_I2C_BYTE_DATA) + && (data_type != MSM_CAMERA_I2C_WORD_DATA)) + return rc; + + rc = msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read, addr, &temp[0], + data_type, NULL, NULL); + if (rc < 0) + return rc; + + if (data_type == MSM_CAMERA_I2C_BYTE_DATA) + *data = temp[0]; + else + *data = (temp[0] << BITS_PER_BYTE) | temp[1]; + + SPIDBG("%s: addr 0x%x, data %u\n", __func__, addr, *data); + return rc; +} + +int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + return msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read_seq, addr, data, num_byte, + NULL, NULL); +} + +/** + * msm_camera_spi_read_seq_l()- function for large SPI reads + * @client: io client + * @addr: device address to read + * @num_byte: read length + * @tx,rx: pre-allocated SPI buffer. Its size must be at least + * header + num_byte + * + * This function is used for large transactions. Instead of allocating SPI + * buffer each time, caller is responsible for pre-allocating memory buffers. + * Memory buffer must be at least header + num_byte. Header length can be + * obtained by msm_camera_spi_get_hlen(). + */ +int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, + uint32_t addr, uint32_t num_byte, char *tx, char *rx) +{ + return msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read_seq, addr, NULL, num_byte, + tx, rx); +} + +int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + return msm_camera_spi_tx_helper(client, + &client->spi_client->cmd_tbl.query_id, addr, data, num_byte, + NULL, NULL); +} + +static int32_t msm_camera_spi_read_status_reg( + struct msm_camera_i2c_client *client, uint8_t *status) +{ + struct msm_camera_spi_inst *rs = + &client->spi_client->cmd_tbl.read_status; + if (rs->addr_len != 0) { + pr_err("%s: not implemented yet\n", __func__); + return -EINVAL; + } + return msm_camera_spi_tx_helper(client, rs, 0, status, 1, NULL, NULL); +} + +static int32_t msm_camera_spi_device_busy(struct msm_camera_i2c_client *client, + uint8_t *busy) +{ + int rc; + uint8_t st = 0; + rc = msm_camera_spi_read_status_reg(client, &st); + if (rc < 0) { + SPIDBG("%s: failed to read status reg\n", __func__); + return rc; + } + *busy = st & client->spi_client->busy_mask; + return 0; +} + +static int32_t msm_camera_spi_wait(struct msm_camera_i2c_client *client, + struct msm_camera_spi_inst *inst) +{ + uint8_t busy; + int i, rc; + SPIDBG("%s: op 0x%x wait start\n", __func__, inst->opcode); + for (i = 0; i <= inst->delay_count; i++) { + rc = msm_camera_spi_device_busy(client, &busy); + if (rc < 0) + return rc; + if (!busy) + break; + else + msleep(inst->delay_intv); + SPIDBG("%s: op 0x%x wait\n", __func__, inst->opcode); + } + if (i > inst->delay_count) { + SPIDBG("%s: op %x timed out\n", __func__, inst->opcode); + return -ETIMEDOUT; + } + SPIDBG("%s: op %x finished\n", __func__, inst->opcode); + return 0; +} + +static int32_t msm_camera_spi_write_enable( + struct msm_camera_i2c_client *client) +{ + struct msm_camera_spi_inst *we = + &client->spi_client->cmd_tbl.write_enable; + int rc; + if (we->addr_len != 0) { + pr_err("%s: not implemented yet\n", __func__); + return -EINVAL; + } + rc = msm_camera_spi_tx_helper(client, we, 0, NULL, 0, NULL, NULL); + if (rc < 0) + SPIDBG("%s: write enable failed\n", __func__); + return rc; +} + +int32_t msm_camera_spi_erase(struct msm_camera_i2c_client *client, + uint32_t addr, uint32_t size) +{ + struct msm_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase; + int rc = 0; + uint32_t cur; + uint32_t end = addr + size; + uint32_t erase_size = client->spi_client->erase_size; + end = addr + size; + for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) { + SPIDBG("%s: erasing 0x%x\n", __func__, cur); + rc = msm_camera_spi_write_enable(client); + if (rc < 0) + return rc; + rc = msm_camera_spi_tx_helper(client, se, cur, NULL, 0, + NULL, NULL); + if (rc < 0) { + SPIDBG("%s: erase failed\n", __func__); + return rc; + } + rc = msm_camera_spi_wait(client, se); + if (rc < 0) { + SPIDBG("%s: erase timedout\n", __func__); + return rc; + } + } + return rc; +} +/** + * msm_camera_spi_page_program() - core function to perform write + * @client: need for obtaining SPI device + * @addr: address to program on device + * @data: data to write + * @len: size of data + * @tx: tx buffer, size >= header + len + * + * This function performs SPI write, and has no boundary check. Writing range + * should not cross page boundary, or data will be corrupted. Transaction is + * guaranteed to be finished when it returns. This function should never be + * used outside msm_camera_spi_write_seq(). + */ +static int32_t msm_camera_spi_page_program(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint16_t len, uint8_t *tx) +{ + int rc; + struct msm_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + struct spi_device *spi = client->spi_client->spi_master; + uint8_t retries = client->spi_client->retries; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + SPIDBG("%s: addr 0x%x, size 0x%x\n", __func__, addr, len); + rc = msm_camera_spi_write_enable(client); + if (rc < 0) + return rc; + memset(tx, 0, header_len); + tx[0] = pg->opcode; + msm_camera_set_addr(addr, pg->addr_len, client->addr_type, tx + 1); + memcpy(tx + header_len, data, len); + SPIDBG("%s: tx(%u): %02x %02x %02x %02x\n", __func__, + len, tx[0], tx[1], tx[2], tx[3]); + while ((rc = spi_write(spi, tx, len + header_len)) && retries) { + rc = msm_camera_spi_wait(client, pg); + msleep(client->spi_client->retry_delay); + retries--; + } + if (rc < 0) { + SPIDBG("%s: failed %d\n", __func__, rc); + return rc; + } + rc = msm_camera_spi_wait(client, pg); + return rc; +} +int32_t msm_camera_spi_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte) +{ + struct msm_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + const uint32_t page_size = client->spi_client->page_size; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + uint16_t len; + uint32_t cur_len, end; + char *tx, *pdata = data; + int rc = -EINVAL; + if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR) + && (client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) + && (client->addr_type != MSM_CAMERA_I2C_3B_ADDR)) + return rc; + /* single page write */ + if ((addr % page_size) + num_byte <= page_size) { + len = header_len + num_byte; + tx = kmalloc(len, GFP_KERNEL); + if (!tx) + goto NOMEM; + rc = msm_camera_spi_page_program(client, addr, data, + num_byte, tx); + if (rc < 0) + goto ERROR; + goto OUT; + } + /* multi page write */ + len = header_len + page_size; + tx = kmalloc(len, GFP_KERNEL); + if (!tx) + goto NOMEM; + while (num_byte) { + end = min(page_size, (addr % page_size) + num_byte); + cur_len = end - (addr % page_size); + rc = msm_camera_spi_page_program(client, addr, pdata, + cur_len, tx); + if (rc < 0) + goto ERROR; + addr += cur_len; + pdata += cur_len; + num_byte -= cur_len; + } + goto OUT; +NOMEM: + SPIDBG("%s: memory allocation failed\n", __func__); + return -ENOMEM; +ERROR: + SPIDBG("%s: error write\n", __func__); +OUT: + kfree(tx); + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_spi.h b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_spi.h new file mode 100644 index 0000000000000000000000000000000000000000..0949667b3c727a069896c22294f4adcc21528f59 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/io/msm_camera_spi.h @@ -0,0 +1,85 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef __MSM_CAMERA_SPI_H +#define __MSM_CAMERA_SPI_H + +#include +#include "../../include/media/msm_cam_sensor.h" +#include "msm_camera_i2c.h" + +/** + * Common SPI communication scheme + * tx: [addr][wait][write buffer] + * rx: [read buffer] + * Some inst require polling busy reg until it's done + */ +struct msm_camera_spi_inst { + uint8_t opcode; /* one-byte opcode */ + uint8_t addr_len; /* addr len in bytes */ + uint8_t dummy_len; /* setup cycles */ + uint8_t delay_intv; /* delay intv for this inst (ms) */ + uint8_t delay_count; /* total delay count for this inst */ +}; + +struct msm_camera_spi_inst_tbl { + struct msm_camera_spi_inst read; + struct msm_camera_spi_inst read_seq; + struct msm_camera_spi_inst query_id; + struct msm_camera_spi_inst page_program; + struct msm_camera_spi_inst write_enable; + struct msm_camera_spi_inst read_status; + struct msm_camera_spi_inst erase; +}; + +struct msm_camera_spi_client { + struct spi_device *spi_master; + struct msm_camera_spi_inst_tbl cmd_tbl; + uint8_t device_id; + uint8_t device_id0; + uint8_t device_id1; + uint8_t device_id2; + uint8_t mfr_id; + uint8_t mfr_id0; + uint8_t mfr_id1; + uint8_t mfr_id2; + uint8_t retry_delay; /* ms */ + uint8_t retries; /* retry times upon failure */ + uint8_t busy_mask; /* busy bit in status reg */ + uint16_t page_size; /* page size for page program */ + uint32_t erase_size; /* minimal erase size */ +}; + +static __always_inline +uint16_t msm_camera_spi_get_hlen(struct msm_camera_spi_inst *inst) +{ + return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len; +} + +int32_t msm_camera_spi_read(struct msm_camera_i2c_client *client, + uint32_t addr, uint16_t *data, + enum msm_camera_i2c_data_type data_type); + +int32_t msm_camera_spi_read_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_spi_read_seq_l(struct msm_camera_i2c_client *client, + uint32_t addr, uint32_t num_byte, char *tx, char *rx); + +int32_t msm_camera_spi_query_id(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); + +int32_t msm_camera_spi_write_seq(struct msm_camera_i2c_client *client, + uint32_t addr, uint8_t *data, uint32_t num_byte); +int32_t msm_camera_spi_erase(struct msm_camera_i2c_client *client, + uint32_t addr, uint32_t size); +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor.c new file mode 100644 index 0000000000000000000000000000000000000000..4b33dd471e60d647c3a5119e2b703c25e57a3aed --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor.c @@ -0,0 +1,1728 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 +#include "msm_sensor.h" +#include "msm_sd.h" +#include "camera.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#include "msm_camera_i2c_mux.h" +#include +#include +#include + +//#define CONFIG_MSMB_CAMERA_DEBUG +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +extern unsigned int system_rev; + +#if defined(CONFIG_FLED_LM3632) +extern void ssflash_led_turn_on(void); +extern void ssflash_led_turn_off(void); +#endif +#if defined(CONFIG_FLED_KTD2692) +extern void ktd2692_flash_on(unsigned data); +#endif + +#if defined(CONFIG_FLED_LM3632) || defined(CONFIG_FLED_KTD2692) +int32_t msm_sensor_flash_native_control(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + + if(system_rev >= 5){ + struct ioctl_native_cmd *cam_info = (struct ioctl_native_cmd *)argp; + + if(s_ctrl->sensordata->slave_info->sensor_id == 0x5e30){ + if(cam_info->value_1 == 3) { + pr_err("%s : KTD Front LED turn on\n", __func__); + ktd2692_flash_on(1); + } else if(cam_info->value_1 == 0) { + pr_err("%s : KTD Front LED turn off\n", __func__); + ktd2692_flash_on(0); + }else{ + pr_err("%s : KTD Invalid LED value\n", __func__); + } + } + return 0; + }else{ + struct ioctl_native_cmd *cam_info = (struct ioctl_native_cmd *)argp; + + if(s_ctrl->sensordata->slave_info->sensor_id == 0x5e30){ + if(cam_info->value_1 == 3) { + pr_err("%s : Front LED turn on\n", __func__); + ssflash_led_turn_on(); + } else if(cam_info->value_1 == 0) { + pr_err("%s : Front LED turn off\n", __func__); + ssflash_led_turn_off(); + }else{ + pr_err("%s : Invalid LED value\n", __func__); + } + } + return 0; +} +} +#endif + +static void msm_sensor_adjust_mclk(struct msm_camera_power_ctrl_t *ctrl) +{ + int idx; + struct msm_sensor_power_setting *power_setting; + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + power_setting = &ctrl->power_setting[idx]; + if (power_setting->seq_type == SENSOR_CLK && + power_setting->seq_val == SENSOR_CAM_MCLK) { + if (power_setting->config_val == 24000000) { + power_setting->config_val = 23880000; + CDBG("%s MCLK request adjusted to 23.88MHz\n" + , __func__); + } + break; + } + } + + return; +} + +static int32_t msm_camera_get_power_settimgs_from_sensor_lib( + struct msm_camera_power_ctrl_t *power_info, + struct msm_sensor_power_setting_array *power_setting_array) +{ + int32_t rc = 0; + uint32_t size; + struct msm_sensor_power_setting *ps; + bool need_reverse = 0; + + if ((NULL == power_info->power_setting) || + (0 == power_info->power_setting_size)) { + + ps = power_setting_array->power_setting; + size = power_setting_array->size; + if ((NULL == ps) || (0 == size)) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -EINVAL; + goto FAILED_1; + } + + power_info->power_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + if (!power_info->power_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FAILED_1; + } + memcpy(power_info->power_setting, + power_setting_array->power_setting, + sizeof(*ps) * size); + power_info->power_setting_size = size; + } + + ps = power_setting_array->power_down_setting; + size = power_setting_array->size_down; + if (NULL == ps || 0 == size) { + ps = power_info->power_setting; + size = power_info->power_setting_size; + need_reverse = 1; + } + + power_info->power_down_setting = + kzalloc(sizeof(*ps) * size, GFP_KERNEL); + if (!power_info->power_down_setting) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_UP; + } + memcpy(power_info->power_down_setting, + ps, + sizeof(*ps) * size); + power_info->power_down_setting_size = size; + + if (need_reverse) { + int c, end = size - 1; + struct msm_sensor_power_setting power_down_setting_t; + for (c = 0; c < size/2; c++) { + power_down_setting_t = + power_info->power_down_setting[c]; + power_info->power_down_setting[c] = + power_info->power_down_setting[end]; + power_info->power_down_setting[end] = + power_down_setting_t; + end--; + } + } + + return 0; +FREE_UP: + kfree(power_info->power_setting); +FAILED_1: + return rc; +} + +static int32_t msm_sensor_get_dt_data(struct device_node *of_node, + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0, i = 0, ret = 0; + struct msm_camera_gpio_conf *gconf = NULL; + struct msm_camera_sensor_board_info *sensordata = NULL; + uint16_t *gpio_array = NULL; + uint16_t gpio_array_size = 0; + uint32_t id_info[3]; + + s_ctrl->sensordata = kzalloc(sizeof( + struct msm_camera_sensor_board_info), + GFP_KERNEL); + if (!s_ctrl->sensordata) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -ENOMEM; + } + + sensordata = s_ctrl->sensordata; + + rc = of_property_read_string(of_node, "qcom,sensor-name", + &sensordata->sensor_name); + CDBG("%s qcom,sensor-name %s, rc %d\n", __func__, + sensordata->sensor_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSORDATA; + } + + rc = of_property_read_u32(of_node, "qcom,cci-master", + &s_ctrl->cci_i2c_master); + CDBG("%s qcom,cci-master %d, rc %d\n", __func__, s_ctrl->cci_i2c_master, + rc); + if (rc < 0) { + /* Set default master 0 */ + s_ctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSORDATA; + } + + /* Get sensor mount angle */ + if (0 > of_property_read_u32(of_node, "qcom,mount-angle", + &sensordata->sensor_info->sensor_mount_angle)) { + /* Invalidate mount angle flag */ + CDBG("%s:%d Default sensor mount angle\n", + __func__, __LINE__); + sensordata->sensor_info->is_mount_angle_valid = 0; + sensordata->sensor_info->sensor_mount_angle = 0; + } else { + sensordata->sensor_info->is_mount_angle_valid = 1; + } + CDBG("%s qcom,mount-angle %d\n", __func__, + sensordata->sensor_info->sensor_mount_angle); + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", + &sensordata->sensor_info->position)) { + CDBG("%s:%d Default sensor position\n", __func__, __LINE__); + sensordata->sensor_info->position = 0; + } + CDBG("%s qcom,sensor-position %d\n", __func__, + sensordata->sensor_info->position); + if (0 > of_property_read_u32(of_node, "qcom,sensor-mode", + &sensordata->sensor_info->modes_supported)) { + CDBG("%s:%d Default sensor mode\n", __func__, __LINE__); + sensordata->sensor_info->modes_supported = 0; + } + CDBG("%s qcom,sensor-mode %d\n", __func__, + sensordata->sensor_info->modes_supported); + + s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node, + "qcom,mclk-23880000"); + + CDBG("%s qcom,mclk-23880000 %d\n", __func__, + s_ctrl->set_mclk_23880000); + + rc = msm_sensor_get_dt_csi_data(of_node, &sensordata->csi_lane_params); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SENSOR_INFO; + } + + rc = msm_camera_get_dt_vreg_data(of_node, + &sensordata->power_info.cam_vreg, + &sensordata->power_info.num_vreg); + if (rc < 0) + goto FREE_CSI; + + rc = msm_camera_get_dt_power_setting_data(of_node, + sensordata->power_info.cam_vreg, + sensordata->power_info.num_vreg, + &sensordata->power_info); + + + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_VREG; + } + + + rc = msm_camera_get_power_settimgs_from_sensor_lib( + &sensordata->power_info, + &s_ctrl->power_setting_array); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_VREG; + } + + sensordata->power_info.gpio_conf = kzalloc( + sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); + if (!sensordata->power_info.gpio_conf) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FREE_PS; + } + gconf = sensordata->power_info.gpio_conf; + + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size) { + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, + GFP_KERNEL); + if (!gpio_array) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_CONF; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_CONF; + } + + rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_REQ_TBL; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_SET_TBL; + } + } + rc = msm_sensor_get_dt_actuator_data(of_node, + &sensordata->actuator_info); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_GPIO_PIN_TBL; + } + + sensordata->slave_info = kzalloc(sizeof(struct msm_camera_slave_info), + GFP_KERNEL); + if (!sensordata->slave_info) { + pr_err("%s failed %d\n", __func__, __LINE__); + rc = -ENOMEM; + goto FREE_ACTUATOR_INFO; + } + + rc = of_property_read_u32_array(of_node, "qcom,slave-id", + id_info, 3); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_SLAVE_INFO; + } + + sensordata->slave_info->sensor_slave_addr = id_info[0]; + sensordata->slave_info->sensor_id_reg_addr = id_info[1]; + sensordata->slave_info->sensor_id = id_info[2]; + CDBG("%s:%d slave addr 0x%x sensor reg 0x%x id 0x%x\n", + __func__, __LINE__, + sensordata->slave_info->sensor_slave_addr, + sensordata->slave_info->sensor_id_reg_addr, + sensordata->slave_info->sensor_id); + + /*Optional property, don't return error if absent */ + ret = of_property_read_string(of_node, "qcom,vdd-cx-name", + &sensordata->misc_regulator); + CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__, + sensordata->misc_regulator, ret); + + kfree(gpio_array); + + return rc; + +FREE_SLAVE_INFO: + kfree(s_ctrl->sensordata->slave_info); +FREE_ACTUATOR_INFO: + kfree(s_ctrl->sensordata->actuator_info); +FREE_GPIO_PIN_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); +FREE_GPIO_SET_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); +FREE_GPIO_REQ_TBL: + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); +FREE_GPIO_CONF: + kfree(s_ctrl->sensordata->power_info.gpio_conf); +FREE_PS: + kfree(s_ctrl->sensordata->power_info.power_setting); + kfree(s_ctrl->sensordata->power_info.power_down_setting); +FREE_VREG: + kfree(s_ctrl->sensordata->power_info.cam_vreg); +FREE_CSI: + kfree(s_ctrl->sensordata->csi_lane_params); +FREE_SENSOR_INFO: + kfree(s_ctrl->sensordata->sensor_info); +FREE_SENSORDATA: + kfree(s_ctrl->sensordata); + kfree(gpio_array); + return rc; +} + +static void msm_sensor_misc_regulator( + struct msm_sensor_ctrl_t *sctrl, uint32_t enable) +{ + int32_t rc = 0; + if (enable) { + sctrl->misc_regulator = (void *)rpm_regulator_get( + &sctrl->pdev->dev, sctrl->sensordata->misc_regulator); + if (sctrl->misc_regulator) { + rc = rpm_regulator_set_mode(sctrl->misc_regulator, + RPM_REGULATOR_MODE_HPM); + if (rc < 0) { + pr_err("%s: Failed to set for rpm regulator on %s: %d\n", + __func__, + sctrl->sensordata->misc_regulator, rc); + rpm_regulator_put(sctrl->misc_regulator); + } + } else { + pr_err("%s: Failed to vote for rpm regulator on %s: %d\n", + __func__, + sctrl->sensordata->misc_regulator, rc); + } + } else { + if (sctrl->misc_regulator) { + rc = rpm_regulator_set_mode( + (struct rpm_regulator *)sctrl->misc_regulator, + RPM_REGULATOR_MODE_AUTO); + if (rc < 0) + pr_err("%s: Failed to set for rpm regulator on %s: %d\n", + __func__, + sctrl->sensordata->misc_regulator, rc); + rpm_regulator_put(sctrl->misc_regulator); + } + } +} + +int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl) +{ + if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client) + return 0; + kfree(s_ctrl->sensordata->slave_info); + kfree(s_ctrl->sensordata->cam_slave_info); + kfree(s_ctrl->sensordata->actuator_info); + kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl); + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); + kfree(s_ctrl->sensordata->power_info.gpio_conf); + kfree(s_ctrl->sensordata->power_info.cam_vreg); + kfree(s_ctrl->sensordata->power_info.power_setting); + kfree(s_ctrl->sensordata->csi_lane_params); + kfree(s_ctrl->sensordata->sensor_info); + kfree(s_ctrl->sensordata->power_info.clk_info); + kfree(s_ctrl->sensordata); + return 0; +} + +static struct msm_cam_clk_info cam_8960_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_clk", 24000000}, +}; + +static struct msm_cam_clk_info cam_8610_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, + [SENSOR_CAM_CLK] = {"cam_clk", 0}, +}; + +static struct msm_cam_clk_info cam_8974_clk_info[] = { + [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000}, + [SENSOR_CAM_CLK] = {"cam_clk", 0}, +}; + +int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl) +{ + struct msm_camera_power_ctrl_t *power_info; + enum msm_camera_device_type_t sensor_device_type; + struct msm_camera_i2c_client *sensor_i2c_client; + + if (!s_ctrl) { + pr_err("%s:%d failed: s_ctrl %p\n", + __func__, __LINE__, s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + sensor_device_type = s_ctrl->sensor_device_type; + sensor_i2c_client = s_ctrl->sensor_i2c_client; + +#if defined(CONFIG_FLED_LM3632) || defined(CONFIG_FLED_KTD2692) + if(s_ctrl->sensordata->slave_info->sensor_id == 0x5e30){ + pr_err("%s : Front LED turn off\n", __func__); + if(system_rev >= 5) + ktd2692_flash_on(0); + else + ssflash_led_turn_off(); + } +#endif + if (!power_info || !sensor_i2c_client) { + pr_err("%s:%d failed: power_info %p sensor_i2c_client %p\n", + __func__, __LINE__, power_info, sensor_i2c_client); + return -EINVAL; + } + return msm_camera_power_down(power_info, sensor_device_type, + sensor_i2c_client); +} + +int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc; + struct msm_camera_power_ctrl_t *power_info; + struct msm_camera_i2c_client *sensor_i2c_client; + struct msm_camera_slave_info *slave_info; + const char *sensor_name; + uint32_t retry = 0; + + if (!s_ctrl) { + pr_err("%s:%d failed: %p\n", + __func__, __LINE__, s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + sensor_i2c_client = s_ctrl->sensor_i2c_client; + slave_info = s_ctrl->sensordata->slave_info; + sensor_name = s_ctrl->sensordata->sensor_name; + + if (!power_info || !sensor_i2c_client || !slave_info || + !sensor_name) { + pr_err("%s:%d failed: %p %p %p %p\n", + __func__, __LINE__, power_info, + sensor_i2c_client, slave_info, sensor_name); + return -EINVAL; + } + + CDBG("set__mclk_23880000: %d", s_ctrl->set_mclk_23880000); + if (s_ctrl->set_mclk_23880000) + msm_sensor_adjust_mclk(power_info); + + for (retry = 0; retry < 3; retry++) { + rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type, + sensor_i2c_client); + if (rc < 0) + return rc; + rc = msm_sensor_check_id(s_ctrl); + if (rc < 0) { + msm_camera_power_down(power_info, + s_ctrl->sensor_device_type, sensor_i2c_client); + msleep(20); + continue; + } else { + break; + } + } + + return rc; +} + +int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t chipid = 0; + struct msm_camera_i2c_client *sensor_i2c_client; + struct msm_camera_slave_info *slave_info; + const char *sensor_name; +#if defined(CONFIG_SEC_ROSSA_PROJECT) + enum msm_camera_i2c_data_type data_type = MSM_CAMERA_I2C_WORD_DATA; +#endif + + if (!s_ctrl) { + pr_err("%s:%d failed: %p\n", + __func__, __LINE__, s_ctrl); + return -EINVAL; + } + sensor_i2c_client = s_ctrl->sensor_i2c_client; + slave_info = s_ctrl->sensordata->slave_info; + sensor_name = s_ctrl->sensordata->sensor_name; + + if (!sensor_i2c_client || !slave_info || !sensor_name) { + pr_err("%s:%d failed: %p %p %p\n", + __func__, __LINE__, sensor_i2c_client, slave_info, + sensor_name); + return -EINVAL; + } + +#if defined(CONFIG_SEC_ROSSA_PROJECT) + if (slave_info->sensor_id == 0xb4) + data_type = MSM_CAMERA_I2C_BYTE_DATA; + rc = sensor_i2c_client->i2c_func_tbl->i2c_read( + sensor_i2c_client, slave_info->sensor_id_reg_addr, + &chipid, data_type); + if (chipid != slave_info->sensor_id) { + if(slave_info->sensor_id== 0x4405) + { + uint16_t original_sid = 0; + chipid = 0; + original_sid = sensor_i2c_client->cci_client->sid; + s_ctrl->sensor_i2c_client->cci_client->sid = 0x50 >> 1; + rc = sensor_i2c_client->i2c_func_tbl->i2c_read( + sensor_i2c_client, slave_info->sensor_id_reg_addr,&chipid, data_type); + printk("%s: read id: %x expected id %x:\n", __func__, chipid, + s_ctrl->sensordata->slave_info->sensor_id); + if (chipid != slave_info->sensor_id) { + chipid = 0; + s_ctrl->sensor_i2c_client->cci_client->sid = 0x40 >> 1; + rc = sensor_i2c_client->i2c_func_tbl->i2c_read( + sensor_i2c_client, slave_info->sensor_id_reg_addr, &chipid, data_type); + printk("%s: read id: %x expected id %x:\n", __func__, chipid, + s_ctrl->sensordata->slave_info->sensor_id); + if (chipid != slave_info->sensor_id) { + // If sensor id not matched finally, restore sensor_id and sid to original values. + pr_err("msm_sensor_match_id chip id doesnot match\n"); + s_ctrl->sensor_i2c_client->cci_client->sid = original_sid; + return 0; + } + } + } + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return 0; + } +#else + + rc = sensor_i2c_client->i2c_func_tbl->i2c_read( + sensor_i2c_client, slave_info->sensor_id_reg_addr, + &chipid, MSM_CAMERA_I2C_WORD_DATA); +#endif + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x%x:\n", __func__, chipid, + slave_info->sensor_id); + if (chipid != slave_info->sensor_id) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return 0; //to pass DFMS with removing REAR cam + } + return rc; +} + +static struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd) +{ + return container_of(container_of(sd, struct msm_sd_subdev, sd), + struct msm_sensor_ctrl_t, msm_sd); +} + +static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl) +{ + mutex_lock(s_ctrl->msm_sensor_mutex); + if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting); + kfree(s_ctrl->stop_setting.reg_setting); + s_ctrl->stop_setting.reg_setting = NULL; + } + mutex_unlock(s_ctrl->msm_sensor_mutex); + return; +} + +static int msm_sensor_get_af_status(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + /* TO-DO: Need to set AF status register address and expected value + We need to check the AF status in the sensor register and + set the status in the *status variable accordingly*/ + return 0; +} + +static long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); + void __user *argp = (void __user *)arg; + if (!s_ctrl) { + pr_err("%s s_ctrl NULL\n", __func__); + return -EBADF; + } + switch (cmd) { + case VIDIOC_MSM_SENSOR_CFG: + return s_ctrl->func_tbl->sensor_config(s_ctrl, argp); + case VIDIOC_MSM_SENSOR_GET_AF_STATUS: + return msm_sensor_get_af_status(s_ctrl, argp); + case VIDIOC_MSM_SENSOR_RELEASE: + msm_sensor_stop_stream(s_ctrl); + return 0; + case MSM_SD_SHUTDOWN: + return 0; + case VIDIOC_MSM_SENSOR_NATIVE_CMD: + if( s_ctrl->func_tbl->sensor_native_control != NULL ) + return s_ctrl->func_tbl->sensor_native_control(s_ctrl, argp); + else + pr_err("s_ctrl->func_tbl->sensor_native_control is NULL\n"); + + default: + return -ENOIOCTLCMD; + } +} + +int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + pr_err("CFG_GET_SENSOR_INFO\n"); + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + cdata->cfg.sensor_info.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_info.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + pr_err("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int s_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + p_ctrl = &s_ctrl->sensordata->power_info; + + /* Update power up sequence */ + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + + + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(sensor_slave_info.power_setting_array. + power_setting); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (s_index = 0; s_index < + p_ctrl->power_setting_size; s_index++) { + CDBG("%s i %d power up setting %d %d %ld %d\n", + __func__, + s_index, + p_ctrl->power_setting[s_index].seq_type, + p_ctrl->power_setting[s_index].seq_val, + p_ctrl->power_setting[s_index].config_val, + p_ctrl->power_setting[s_index].delay); + } + + /* Update power down sequence */ + if (!sensor_slave_info.power_setting_array.power_down_setting || + 0 == size) { + pr_err("%s: Missing dedicated power down sequence\n", + __func__); + break; + } + size = sensor_slave_info.power_setting_array.size_down; + + if (p_ctrl->power_down_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_down_setting); + p_ctrl->power_down_setting = tmp; + } + p_ctrl->power_down_setting_size = size; + + + rc = copy_from_user(p_ctrl->power_down_setting, (void *) + sensor_slave_info.power_setting_array. + power_down_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(sensor_slave_info.power_setting_array. + power_down_setting); + rc = -EFAULT; + break; + } + for (s_index = 0; s_index < + p_ctrl->power_down_setting_size; s_index++) { + CDBG("%s i %d power DOWN setting %d %d %ld %d\n", + __func__, + s_index, + p_ctrl->power_down_setting[s_index].seq_type, + p_ctrl->power_down_setting[s_index].seq_val, + p_ctrl->power_down_setting[s_index].config_val, + p_ctrl->power_down_setting[s_index].delay); + } + + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + uint8_t *reg_data = NULL; + uint32_t i = 0, size = 0; + + CDBG("%s:%d CFG_WRITE_I2C_ARRAY\n", __func__, __LINE__); + + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + CDBG("%s:%d conf_array.size = %d,\n", __func__, __LINE__, conf_array.size); + if (!conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + if (conf_array.data_type == MSM_CAMERA_I2C_BURST_DATA) { + CDBG("%s:%d MSM_CAMERA_I2C_BURST_DATA\n", __func__, __LINE__); + + CDBG("%s:%d conf_array.size = %d,\n", __func__, __LINE__, conf_array.size); + if (!conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + reg_setting = (void *)kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user((void *)reg_setting, + (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + size = conf_array.size; + conf_array.size = 1; + + for (i = 0; i < size; i++) { + reg_data = kzalloc(reg_setting[i].delay * + (sizeof(uint8_t)), GFP_KERNEL); + if (!reg_data) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_data, + (void *)reg_setting[i].reg_burst_data, + reg_setting[i].delay * + (sizeof(uint8_t)))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_data); + continue; + } + + reg_setting[i].reg_burst_data = reg_data; + conf_array.reg_setting = ®_setting[i]; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_burst_table( + s_ctrl->sensor_i2c_client, &conf_array); + if (rc < 0) { + pr_err("%s:%d failed i2c_write_table rc %d\n", __func__, + __LINE__, rc); + } + kfree(reg_data); + } + + kfree(reg_setting); + }else { + CDBG("%s:%d CFG_WRITE_I2C_ARRAY\n", __func__, __LINE__); + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + } + break; + } + case CFG_SLAVE_READ_I2C: { + struct msm_camera_i2c_read_config read_config; + uint16_t local_data = 0; + uint16_t orig_slave_addr = 0, read_slave_addr = 0; + if (copy_from_user(&read_config, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_read_config))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + read_slave_addr = read_config.slave_addr; + CDBG("%s:CFG_SLAVE_READ_I2C:", __func__); + CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n", + __func__, read_config.slave_addr, + read_config.reg_addr, read_config.data_type); + if (s_ctrl->sensor_i2c_client->cci_client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->cci_client->sid; + s_ctrl->sensor_i2c_client->cci_client->sid = + read_slave_addr >> 1; + } else if (s_ctrl->sensor_i2c_client->client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->client->addr; + s_ctrl->sensor_i2c_client->client->addr = + read_slave_addr >> 1; + } else { + pr_err("%s: error: no i2c/cci client found.", __func__); + rc = -EFAULT; + break; + } + CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", + __func__, orig_slave_addr, + read_slave_addr >> 1); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + read_config.reg_addr, + &local_data, read_config.data_type); + if (rc < 0) { + pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__); + break; + } + if (copy_to_user((void __user *)read_config.data, + (void *)&local_data, sizeof(uint16_t))) { + pr_err("%s:%d copy failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + break; + } + case CFG_SLAVE_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_array_write_config write_config; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + uint16_t write_slave_addr = 0; + uint16_t orig_slave_addr = 0; + + if (copy_from_user(&write_config, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_array_write_config))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__); + CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__, + write_config.slave_addr, + write_config.conf_array.size); + + if (!write_config.conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + reg_setting = kzalloc(write_config.conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, + (void *)(write_config.conf_array.reg_setting), + write_config.conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + write_config.conf_array.reg_setting = reg_setting; + write_slave_addr = write_config.slave_addr; + if (s_ctrl->sensor_i2c_client->cci_client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->cci_client->sid; + s_ctrl->sensor_i2c_client->cci_client->sid = + write_slave_addr >> 1; + } else if (s_ctrl->sensor_i2c_client->client) { + orig_slave_addr = + s_ctrl->sensor_i2c_client->client->addr; + s_ctrl->sensor_i2c_client->client->addr = + write_slave_addr >> 1; + } else { + pr_err("%s: error: no i2c/cci client found.", __func__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x", + __func__, orig_slave_addr, + write_slave_addr >> 1); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &(write_config.conf_array)); + if (s_ctrl->sensor_i2c_client->cci_client) { + s_ctrl->sensor_i2c_client->cci_client->sid = + orig_slave_addr; + } else if (s_ctrl->sensor_i2c_client->client) { + s_ctrl->sensor_i2c_client->client->addr = + orig_slave_addr; + } else { + pr_err("%s: error: no i2c/cci client found.", __func__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + if (!conf_array.size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + if (s_ctrl->func_tbl->sensor_power_up) { + if (s_ctrl->sensordata->misc_regulator) + msm_sensor_misc_regulator(s_ctrl, 1); + + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + s_ctrl->sensor_state = MSM_SENSOR_POWER_UP; + pr_err("%s:%d sensor state %d\n", __func__, __LINE__, + s_ctrl->sensor_state); + } else { + rc = -EFAULT; + } + break; + + case CFG_POWER_DOWN: + kfree(s_ctrl->stop_setting.reg_setting); + s_ctrl->stop_setting.reg_setting = NULL; + if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) { + pr_err("%s:%d failed: invalid state %d\n", __func__, + __LINE__, s_ctrl->sensor_state); + rc = -EFAULT; + break; + } + if (s_ctrl->func_tbl->sensor_power_down) { + if (s_ctrl->sensordata->misc_regulator) + msm_sensor_misc_regulator(s_ctrl, 0); + + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; + pr_err("%s:%d sensor state %d\n", __func__, __LINE__, + s_ctrl->sensor_state); + } else { + rc = -EFAULT; + } + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + + if (!stop_setting->size) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, + stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + + case CFG_SET_SENSOR_OTP_CAL: { + const uint16_t otp_start = 0xa3d, otp_end = 0xa42; + uint16_t otp_cal_data[6], temp_data; + int idx = 0; + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + 0x0A02, 0x0F, // Set the PAGE15 of OTP set read mode of NVM controller Interface + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + 0x0A00, 0x01, // Set read mode of NVM controller Interface + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + for (i = otp_start; i <= otp_end; i++) { + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + i, &otp_cal_data[idx++], + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C read\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_err("%s: 0x%x, 0x%x\n", __func__, i, otp_cal_data[idx - 1]); + if ((i+1)%2) { + temp_data = ((otp_cal_data[idx - 2] << 8) & 0xFF00) | + (otp_cal_data[idx - 1] & 0xFF); + // Valid check : +-50% + if (temp_data > 0x180 || temp_data < 0x80) { + pr_err("%s: range over (0x%x)\n", __func__, temp_data); + rc = -EFAULT; + break; + } + } + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, + 0x0A00, 0x00, // Disable NVM controller + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + if (rc >= 0) { + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x020E, otp_cal_data[2], // G msb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x020F, otp_cal_data[3], // G lsb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x0210, otp_cal_data[0], // R msb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x0211, otp_cal_data[1], // R lsb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x0212, otp_cal_data[4], // B msb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x0213, otp_cal_data[5], // B lsb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x0214, otp_cal_data[2], // G msb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + if (s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write( + s_ctrl->sensor_i2c_client, 0x0215, otp_cal_data[3], // G lsb + MSM_CAMERA_I2C_BYTE_DATA) < 0) { + pr_err("%s:%d Failed I2C write\n", __func__, __LINE__); + } + } + break; + } + case CFG_SET_START_STREAM: { + rc = 0; + break; + } + case CFG_SET_STOP_STREAM: { + rc = 0; + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc; + + if (s_ctrl->func_tbl->sensor_match_id) + rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl); + else + rc = msm_sensor_match_id(s_ctrl); + if (rc < 0) + pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc); + rc = 0; + return rc; +} + +static int msm_sensor_power(struct v4l2_subdev *sd, int on) +{ + int rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); + mutex_lock(s_ctrl->msm_sensor_mutex); + if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) { + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN; + } + mutex_unlock(s_ctrl->msm_sensor_mutex); + return rc; +} + +static int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, + unsigned int index, enum v4l2_mbus_pixelcode *code) +{ + struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd); + + if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size) + return -EINVAL; + + *code = s_ctrl->sensor_v4l2_subdev_info[index].code; + return 0; +} + +static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = { + .ioctl = msm_sensor_subdev_ioctl, + .s_power = msm_sensor_power, +}; + +static struct v4l2_subdev_video_ops msm_sensor_subdev_video_ops = { + .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt, +}; + +static struct v4l2_subdev_ops msm_sensor_subdev_ops = { + .core = &msm_sensor_subdev_core_ops, + .video = &msm_sensor_subdev_video_ops, +}; + +static struct msm_sensor_fn_t msm_sensor_func_tbl = { + .sensor_config = msm_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_burst_table = msm_camera_cci_i2c_write_burst_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_write_conf_tbl = msm_camera_cci_i2c_write_conf_tbl, +}; + +static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = { + .i2c_read = msm_camera_qup_i2c_read, + .i2c_read_seq = msm_camera_qup_i2c_read_seq, + .i2c_write = msm_camera_qup_i2c_write, + .i2c_write_table = msm_camera_qup_i2c_write_table, + .i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_qup_i2c_write_table_w_microdelay, + .i2c_write_conf_tbl = msm_camera_qup_i2c_write_conf_tbl, +}; + +int32_t msm_sensor_platform_probe(struct platform_device *pdev, + const void *data) +{ + int rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = + (struct msm_sensor_ctrl_t *)data; + struct msm_camera_cci_client *cci_client = NULL; + uint32_t session_id; + unsigned long mount_pos = 0; + s_ctrl->pdev = pdev; + CDBG("%s called data %p\n", __func__, data); + CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name); + if (pdev->dev.of_node) { + rc = msm_sensor_get_dt_data(pdev->dev.of_node, s_ctrl); + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + } + s_ctrl->sensordata->power_info.dev = &pdev->dev; + s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE; + s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!s_ctrl->sensor_i2c_client->cci_client) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + /* TODO: get CCI subdev */ + cci_client = s_ctrl->sensor_i2c_client->cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = + s_ctrl->sensordata->slave_info->sensor_slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + if (!s_ctrl->func_tbl) + s_ctrl->func_tbl = &msm_sensor_func_tbl; + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; + if (!s_ctrl->sensor_v4l2_subdev_ops) + s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; + s_ctrl->sensordata->power_info.clk_info = + kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL); + if (!s_ctrl->sensordata->power_info.clk_info) { + pr_err("%s:%d failed nomem\n", __func__, __LINE__); + kfree(cci_client); + return -ENOMEM; + } + memcpy(s_ctrl->sensordata->power_info.clk_info, cam_8974_clk_info, + sizeof(cam_8974_clk_info)); + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8974_clk_info); + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s %s power up failed\n", __func__, + s_ctrl->sensordata->sensor_name); + kfree(s_ctrl->sensordata->power_info.clk_info); + kfree(cci_client); + return rc; + } + + pr_info("%s %s probe succeeded\n", __func__, + s_ctrl->sensordata->sensor_name); + v4l2_subdev_init(&s_ctrl->msm_sd.sd, + s_ctrl->sensor_v4l2_subdev_ops); + snprintf(s_ctrl->msm_sd.sd.name, + sizeof(s_ctrl->msm_sd.sd.name), "%s", + s_ctrl->sensordata->sensor_name); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, pdev); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = + s_ctrl->msm_sd.sd.name; + + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id); + CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); + s_ctrl->sensordata->sensor_info->session_id = session_id; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + CDBG("%s:%d\n", __func__, __LINE__); + + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + CDBG("%s:%d\n", __func__, __LINE__); + return rc; +} + +int msm_sensor_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint32_t session_id; + unsigned long mount_pos = 0; + CDBG("%s %s_i2c_probe called\n", __func__, client->name); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s %s i2c_check_functionality failed\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + if (!client->dev.of_node) { + CDBG("msm_sensor_i2c_probe: of_node is NULL"); + s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data); + if (!s_ctrl) { + pr_err("%s:%d sensor ctrl structure NULL\n", __func__, + __LINE__); + return -EINVAL; + } + s_ctrl->sensordata = client->dev.platform_data; + } else { + CDBG("msm_sensor_i2c_probe: of_node exisists"); + rc = msm_sensor_get_dt_data(client->dev.of_node, s_ctrl); + if (rc < 0) { + pr_err("%s failed line %d\n", __func__, __LINE__); + return rc; + } + } + + s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE; + if (s_ctrl->sensordata == NULL) { + pr_err("%s %s NULL sensor data\n", __func__, client->name); + return -EFAULT; + } + + if (s_ctrl->sensor_i2c_client != NULL) { + s_ctrl->sensor_i2c_client->client = client; + s_ctrl->sensordata->power_info.dev = &client->dev; + if (s_ctrl->sensordata->slave_info->sensor_slave_addr) + s_ctrl->sensor_i2c_client->client->addr = + s_ctrl->sensordata->slave_info-> + sensor_slave_addr; + } else { + pr_err("%s %s sensor_i2c_client NULL\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + if (!s_ctrl->func_tbl) + s_ctrl->func_tbl = &msm_sensor_func_tbl; + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_qup_func_tbl; + if (!s_ctrl->sensor_v4l2_subdev_ops) + s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; + + if (!client->dev.of_node) { + s_ctrl->sensordata->power_info.clk_info = + kzalloc(sizeof(cam_8960_clk_info), GFP_KERNEL); + if (!s_ctrl->sensordata->power_info.clk_info) { + pr_err("%s:%d failed nomem\n", __func__, __LINE__); + return -ENOMEM; + } + memcpy(s_ctrl->sensordata->power_info.clk_info, + cam_8960_clk_info, sizeof(cam_8960_clk_info)); + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8960_clk_info); + } else { + s_ctrl->sensordata->power_info.clk_info = + kzalloc(sizeof(cam_8610_clk_info), GFP_KERNEL); + if (!s_ctrl->sensordata->power_info.clk_info) { + pr_err("%s:%d failed nomem\n", __func__, __LINE__); + return -ENOMEM; + } + memcpy(s_ctrl->sensordata->power_info.clk_info, + cam_8610_clk_info, sizeof(cam_8610_clk_info)); + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8610_clk_info); + } + + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s %s power up failed\n", __func__, client->name); + kfree(s_ctrl->sensordata->power_info.clk_info); + return rc; + } + + CDBG("%s %s probe succeeded\n", __func__, client->name); + snprintf(s_ctrl->msm_sd.sd.name, + sizeof(s_ctrl->msm_sd.sd.name), "%s", id->name); + v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client, + s_ctrl->sensor_v4l2_subdev_ops); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = + s_ctrl->msm_sd.sd.name; + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + rc = camera_init_v4l2(&s_ctrl->sensor_i2c_client->client->dev, + &session_id); + CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); + s_ctrl->sensordata->sensor_info->session_id = session_id; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + CDBG("%s:%d\n", __func__, __LINE__); + + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + return rc; +} + +int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = -ENOMEM; + struct msm_camera_cci_client *cci_client = NULL; + struct msm_cam_clk_info *clk_info = NULL; + unsigned long mount_pos = 0; + + /* Validate input parameters */ + if (!s_ctrl) { + pr_err("%s:%d failed: invalid params s_ctrl %p\n", __func__, + __LINE__, s_ctrl); + return -EINVAL; + } + + if (!s_ctrl->sensor_i2c_client) { + pr_err("%s:%d failed: invalid params sensor_i2c_client %p\n", + __func__, __LINE__, s_ctrl->sensor_i2c_client); + return -EINVAL; + } + + /* Initialize cci_client */ + s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof( + struct msm_camera_cci_client), GFP_KERNEL); + if (!s_ctrl->sensor_i2c_client->cci_client) { + pr_err("%s:%d failed: no memory cci_client %p\n", __func__, + __LINE__, s_ctrl->sensor_i2c_client->cci_client); + return -ENOMEM; + } + + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + cci_client = s_ctrl->sensor_i2c_client->cci_client; + + /* Get CCI subdev */ + cci_client->cci_subdev = msm_cci_get_subdev(); + + /* Update CCI / I2C function table */ + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_cci_func_tbl; + } else { + if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) { + CDBG("%s:%d\n", __func__, __LINE__); + s_ctrl->sensor_i2c_client->i2c_func_tbl = + &msm_sensor_qup_func_tbl; + } + } + + /* Update function table driven by ioctl */ + if (!s_ctrl->func_tbl) + s_ctrl->func_tbl = &msm_sensor_func_tbl; + + /* Update v4l2 subdev ops table */ + if (!s_ctrl->sensor_v4l2_subdev_ops) + s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops; + + /* Initialize clock info */ + clk_info = kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL); + if (!clk_info) { + pr_err("%s:%d failed no memory clk_info %p\n", __func__, + __LINE__, clk_info); + rc = -ENOMEM; + goto FREE_CCI_CLIENT; + } + memcpy(clk_info, cam_8974_clk_info, sizeof(cam_8974_clk_info)); + s_ctrl->sensordata->power_info.clk_info = clk_info; + s_ctrl->sensordata->power_info.clk_info_size = + ARRAY_SIZE(cam_8974_clk_info); + + /* Update sensor mount angle and position in media entity flag */ + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + return 0; + +FREE_CCI_CLIENT: + kfree(cci_client); + return rc; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor.h new file mode 100755 index 0000000000000000000000000000000000000000..6329f5dc6e4a5325a3033e65a5f3557f98d09752 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_SENSOR_H +#define MSM_SENSOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/soc/qcom/camera2.h" +#include "../include/media/msm_cam_sensor.h" +#include +#include "msm_camera_i2c.h" +#include "msm_camera_dt_util.h" +#include "msm_sd.h" + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +struct msm_sensor_ctrl_t; + +enum msm_sensor_state_t { + MSM_SENSOR_POWER_DOWN, + MSM_SENSOR_POWER_UP, +}; + +struct msm_sensor_fn_t { + int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *); + int (*sensor_power_down) (struct msm_sensor_ctrl_t *); + int (*sensor_power_up) (struct msm_sensor_ctrl_t *); + int (*sensor_match_id) (struct msm_sensor_ctrl_t *); + int (*sensor_native_control) (struct msm_sensor_ctrl_t *, void __user *); +}; + + +struct msm_sensor_ctrl_t { + struct platform_device *pdev; + struct mutex *msm_sensor_mutex; + + enum msm_camera_device_type_t sensor_device_type; + struct msm_camera_sensor_board_info *sensordata; + struct msm_sensor_power_setting_array power_setting_array; + struct msm_sensor_packed_cfg_t *cfg_override; + struct msm_sd_subdev msm_sd; + enum cci_i2c_master_t cci_i2c_master; + + struct msm_camera_i2c_client *sensor_i2c_client; + struct v4l2_subdev_info *sensor_v4l2_subdev_info; + uint8_t sensor_v4l2_subdev_info_size; + struct v4l2_subdev_ops *sensor_v4l2_subdev_ops; + struct msm_sensor_fn_t *func_tbl; + struct msm_camera_i2c_reg_setting stop_setting; + void *misc_regulator; + enum msm_sensor_state_t sensor_state; + uint8_t is_probe_succeed; + uint32_t id; + struct device_node *of_node; + enum msm_camera_stream_type_t camera_stream_type; + uint32_t set_mclk_23880000; +}; + +int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp); + +int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl); + +int32_t msm_sensor_platform_probe(struct platform_device *pdev, + const void *data); +int msm_sensor_update_cfg(struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl); + +int msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl); + +int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl); + +int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); + +int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node, + struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size); +#if defined(CONFIG_FLED_LM3632) || defined(CONFIG_FLED_KTD2692) +int32_t msm_sensor_flash_native_control(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp); +#endif +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_driver.c new file mode 100644 index 0000000000000000000000000000000000000000..4b123aedd7fb522af40d43c89fa8f985d86d6ef8 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_driver.c @@ -0,0 +1,1292 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#define SENSOR_DRIVER_I2C "camera" +/* Header file declaration */ +#include "msm_sensor.h" +#include "msm_sd.h" +#include "camera.h" +#include "msm_cci.h" +#include "msm_camera_dt_util.h" + +#if defined CONFIG_SEC_CAMERA_TUNING +#include +#include +#include +#include +#include +static char *regs_table = NULL; +static int table_size; +#endif +#if defined(CONFIG_SR200PC20) +#include "sr200pc20.h" +#endif + +/* Logging macro */ +//#define MSM_SENSOR_DRIVER_DEBUG +#undef CDBG +#ifdef MSM_SENSOR_DRIVER_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define SENSOR_MAX_MOUNTANGLE (360) + +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) +extern unsigned int system_rev; +#endif + +#if defined (CONFIG_CAMERA_SYSFS_V2) +extern char rear_cam_info[100]; //camera_info +extern char front_cam_info[100]; //camera_info +#endif + +/* Static declaration */ +static struct msm_sensor_ctrl_t *g_sctrl[MAX_CAMERAS]; + +#if defined(CONFIG_SR200PC20) +static struct msm_sensor_fn_t sr200pc20_sensor_func_tbl = { + .sensor_config = sr200pc20_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, + .sensor_native_control = sr200pc20_sensor_native_control, +}; +#endif + +#if defined(CONFIG_FLED_LM3632) || defined(CONFIG_FLED_KTD2692) +static struct msm_sensor_fn_t front_flash_func_tbl = { + .sensor_config = msm_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, + .sensor_native_control = msm_sensor_flash_native_control, +}; +#endif + +int32_t msm_sensor_remove_dev_node_for_eeprom(int id,int remove); + +static int msm_sensor_platform_remove(struct platform_device *pdev) +{ + struct msm_sensor_ctrl_t *s_ctrl; + + pr_err("%s: sensor FREE\n", __func__); + + s_ctrl = g_sctrl[pdev->id]; + if (!s_ctrl) { + pr_err("%s: sensor device is NULL\n", __func__); + return 0; + } + + msm_sensor_free_sensor_data(s_ctrl); + kfree(s_ctrl->msm_sensor_mutex); + kfree(s_ctrl->sensor_i2c_client); + kfree(s_ctrl); + g_sctrl[pdev->id] = NULL; + + return 0; +} + + +static const struct of_device_id msm_sensor_driver_dt_match[] = { + {.compatible = "qcom,camera"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_sensor_driver_dt_match); + +static struct platform_driver msm_sensor_platform_driver = { + .driver = { + .name = "qcom,camera", + .owner = THIS_MODULE, + .of_match_table = msm_sensor_driver_dt_match, + }, + .remove = msm_sensor_platform_remove, +}; + +static struct v4l2_subdev_info msm_sensor_driver_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static int32_t msm_sensor_driver_create_i2c_v4l_subdev + (struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint32_t session_id = 0; + struct i2c_client *client = s_ctrl->sensor_i2c_client->client; + + CDBG("%s %s I2c probe succeeded\n", __func__, client->name); + rc = camera_init_v4l2(&client->dev, &session_id); + if (rc < 0) { + pr_err("failed: camera_init_i2c_v4l2 rc %d", rc); + return rc; + } + CDBG("%s rc %d session_id %d\n", __func__, rc, session_id); + snprintf(s_ctrl->msm_sd.sd.name, + sizeof(s_ctrl->msm_sd.sd.name), "%s", + s_ctrl->sensordata->sensor_name); + v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client, + s_ctrl->sensor_v4l2_subdev_ops); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; + s_ctrl->sensordata->sensor_info->session_id = session_id; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + CDBG("%s:%d\n", __func__, __LINE__); + return rc; +} + +static int32_t msm_sensor_driver_create_v4l_subdev + (struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint32_t session_id = 0; + + rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id); + if (rc < 0) { + pr_err("failed: camera_init_v4l2 rc %d", rc); + return rc; + } + CDBG("rc %d session_id %d", rc, session_id); + s_ctrl->sensordata->sensor_info->session_id = session_id; + + /* Create /dev/v4l-subdevX device */ + v4l2_subdev_init(&s_ctrl->msm_sd.sd, s_ctrl->sensor_v4l2_subdev_ops); + snprintf(s_ctrl->msm_sd.sd.name, sizeof(s_ctrl->msm_sd.sd.name), "%s", + s_ctrl->sensordata->sensor_name); + v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev); + s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0); + s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR; + s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name; + s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3; + msm_sd_register(&s_ctrl->msm_sd); + return rc; +} + +static int32_t msm_sensor_fill_eeprom_subdevid_by_name( + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + const char *eeprom_name; + struct device_node *src_node = NULL; + uint32_t val = 0, count = 0, eeprom_name_len; + int i; + int32_t *eeprom_subdev_id; + struct msm_sensor_info_t *sensor_info; + struct device_node *of_node = s_ctrl->of_node; + const void *p; + + if (!s_ctrl->sensordata->eeprom_name || !of_node) + return -EINVAL; + + eeprom_name_len = strlen(s_ctrl->sensordata->eeprom_name); + if (eeprom_name_len >= MAX_SENSOR_NAME) + return -EINVAL; + + sensor_info = s_ctrl->sensordata->sensor_info; + eeprom_subdev_id = &sensor_info->subdev_id[SUB_MODULE_EEPROM]; + /* + * string for eeprom name is valid, set sudev id to -1 + * and try to found new id + */ + *eeprom_subdev_id = -1; + + if (0 == eeprom_name_len) + return 0; + + CDBG("Try to find eeprom subdev for %s\n", + s_ctrl->sensordata->eeprom_name); + p = of_get_property(of_node, "qcom,eeprom-src", &count); + if (!p || !count) + return 0; + + count /= sizeof(uint32_t); + for (i = 0; i < count; i++) { + eeprom_name = NULL; + src_node = of_parse_phandle(of_node, "qcom,eeprom-src", i); + if (!src_node) { + pr_err("eeprom src node NULL\n"); + continue; + } + rc = of_property_read_string(src_node, "qcom,eeprom-name", + &eeprom_name); + if (rc < 0) { + pr_err("failed\n"); + of_node_put(src_node); + continue; + } + if (strcmp(eeprom_name, s_ctrl->sensordata->eeprom_name)) + continue; + + rc = of_property_read_u32(src_node, "cell-index", &val); + + CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("failed\n"); + of_node_put(src_node); + continue; + } + + *eeprom_subdev_id = val; + CDBG("Done. Eeprom subdevice id is %d\n", val); + of_node_put(src_node); + src_node = NULL; + break; + } + + return rc; +} + +static int32_t msm_sensor_fill_actuator_subdevid_by_name( + struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + struct device_node *src_node = NULL; + uint32_t val = 0, actuator_name_len; + int32_t *actuator_subdev_id; + struct msm_sensor_info_t *sensor_info; + struct device_node *of_node = s_ctrl->of_node; + + if (!s_ctrl->sensordata->actuator_name || !of_node) + return -EINVAL; + + actuator_name_len = strlen(s_ctrl->sensordata->actuator_name); + if (actuator_name_len >= MAX_SENSOR_NAME) { + pr_err("msm_sensor_fill_actuator_subdevid_by_name: actuator_name_len is greater than max len\n"); + return -EINVAL; + } + + sensor_info = s_ctrl->sensordata->sensor_info; + actuator_subdev_id = &sensor_info->subdev_id[SUB_MODULE_ACTUATOR]; + /* + * string for actuator name is valid, set sudev id to -1 + * and try to found new id + */ + *actuator_subdev_id = -1; + + if (0 == actuator_name_len) { + pr_err("msm_sensor_fill_actuator_subdevid_by_name: actuator_name_len is zero\n"); + return 0; + } + + src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0); + if (!src_node) { + pr_err("%s:%d src_node NULL\n", __func__, __LINE__); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + pr_err("%s qcom,actuator cell index %d, rc %d\n", __func__, + val, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + return -EINVAL; + } + *actuator_subdev_id = val; + of_node_put(src_node); + src_node = NULL; + } + + return rc; +} + +static int32_t msm_sensor_fill_slave_info_init_params( + struct msm_camera_sensor_slave_info *slave_info, + struct msm_sensor_info_t *sensor_info) +{ + struct msm_sensor_init_params *sensor_init_params; + if (!slave_info || !sensor_info) + return -EINVAL; + + if (!slave_info->is_init_params_valid) + return 0; + + sensor_init_params = &slave_info->sensor_init_params; + if (INVALID_CAMERA_B != sensor_init_params->position) + sensor_info->position = + sensor_init_params->position; + + if (SENSOR_MAX_MOUNTANGLE > sensor_init_params->sensor_mount_angle) { + sensor_info->sensor_mount_angle = + sensor_init_params->sensor_mount_angle; + sensor_info->is_mount_angle_valid = 1; + } + + if (CAMERA_MODE_INVALID != sensor_init_params->modes_supported) + sensor_info->modes_supported = + sensor_init_params->modes_supported; + + return 0; +} + + +static int32_t msm_sensor_validate_slave_info( + struct msm_sensor_info_t *sensor_info) +{ + if (INVALID_CAMERA_B == sensor_info->position) { + sensor_info->position = BACK_CAMERA_B; + CDBG("%s:%d Set default sensor position\n", + __func__, __LINE__); + } + if (CAMERA_MODE_INVALID == sensor_info->modes_supported) { + sensor_info->modes_supported = CAMERA_MODE_2D_B; + CDBG("%s:%d Set default sensor modes_supported\n", + __func__, __LINE__); + } + if (SENSOR_MAX_MOUNTANGLE <= sensor_info->sensor_mount_angle) { + sensor_info->sensor_mount_angle = 0; + CDBG("%s:%d Set default sensor mount angle\n", + __func__, __LINE__); + sensor_info->is_mount_angle_valid = 1; + } + return 0; +} + +/* static function definition */ +int32_t msm_sensor_driver_probe(void *setting) +{ + int32_t rc = 0; + uint16_t i = 0, size = 0, size_down = 0; + struct msm_sensor_ctrl_t *s_ctrl = NULL; + struct msm_camera_cci_client *cci_client = NULL; + struct msm_camera_sensor_slave_info *slave_info = NULL; + struct msm_sensor_power_setting *power_setting = NULL; + struct msm_sensor_power_setting *power_down_setting = NULL; + struct msm_camera_slave_info *camera_info = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + int c, end; + struct msm_sensor_power_setting power_down_setting_t; + unsigned long mount_pos = 0; + int probe_fail = 0; + + /* Validate input parameters */ + if (!setting) { + pr_err("failed: slave_info %p", setting); + return -EINVAL; + } + + /* Allocate memory for slave info */ + slave_info = kzalloc(sizeof(*slave_info), GFP_KERNEL); + if (!slave_info) { + pr_err("failed: no memory slave_info %p", slave_info); + return -ENOMEM; + } + + if (copy_from_user(slave_info, (void *)setting, sizeof(*slave_info))) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_SLAVE_INFO; + } + + /* Print slave info */ + CDBG("camera id %d, ", slave_info->camera_id); + CDBG("slave_addr 0x%x, ", slave_info->slave_addr); + CDBG("addr_type %d, ", slave_info->addr_type); + CDBG("sensor_id_reg_addr 0x%x, ", + slave_info->sensor_id_info.sensor_id_reg_addr); + CDBG("sensor_id 0x%x, ", slave_info->sensor_id_info.sensor_id); + CDBG("size %d, ", slave_info->power_setting_array.size); + CDBG("size down %d, ", slave_info->power_setting_array.size_down); + CDBG("sensor_name %s, ", slave_info->sensor_name); + + if (slave_info->is_init_params_valid) { + CDBG("position %d", + slave_info->sensor_init_params.position); + CDBG("mount %d", + slave_info->sensor_init_params.sensor_mount_angle); + } + + /* Validate camera id */ + if (slave_info->camera_id >= MAX_CAMERAS) { + pr_err("failed: invalid camera id %d max %d", + slave_info->camera_id, MAX_CAMERAS); + rc = -EINVAL; + goto FREE_SLAVE_INFO; + } + + /* Extract s_ctrl from camera id */ + s_ctrl = g_sctrl[slave_info->camera_id]; + if (!s_ctrl) { + pr_err("failed: s_ctrl %p for camera_id %d", s_ctrl, + slave_info->camera_id); + rc = -EINVAL; + goto FREE_SLAVE_INFO; + } +#if defined(CONFIG_SR200PC20) + if(slave_info->camera_id == CAMERA_2){ + s_ctrl->func_tbl = &sr200pc20_sensor_func_tbl ; + } +#elif defined(CONFIG_FLED_LM3632) || defined(CONFIG_FLED_KTD2692) + if(slave_info->camera_id == CAMERA_1){ + s_ctrl->func_tbl = &front_flash_func_tbl ; + } +#endif + + CDBG("s_ctrl[%d] %p", slave_info->camera_id, s_ctrl); + + if (s_ctrl->is_probe_succeed == 1) { + /* + * Different sensor on this camera slot has been connected + * and probe already succeeded for that sensor. Ignore this + * probe + */ + pr_err("slot %d has some other sensor", slave_info->camera_id); + rc = 0; + goto FREE_SLAVE_INFO; + } + + size = slave_info->power_setting_array.size; + /* Allocate memory for power up setting */ + power_setting = kzalloc(sizeof(*power_setting) * size, GFP_KERNEL); + if (!power_setting) { + pr_err("failed: no memory power_setting %p", power_setting); + rc = -ENOMEM; + goto FREE_SLAVE_INFO; + } + + if (copy_from_user(power_setting, + (void *)slave_info->power_setting_array.power_setting, + sizeof(*power_setting) * size)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_SETTING; + } + + /* Print power setting */ + for (i = 0; i < size; i++) { + CDBG("UP seq_type %d seq_val %d config_val %ld delay %d", + power_setting[i].seq_type, power_setting[i].seq_val, + power_setting[i].config_val, power_setting[i].delay); + } + /*DOWN*/ + size_down = slave_info->power_setting_array.size_down; + if (!size_down) + size_down = size; + /* Allocate memory for power down setting */ + power_down_setting = + kzalloc(sizeof(*power_setting) * size_down, GFP_KERNEL); + if (!power_down_setting) { + pr_err("failed: no memory power_setting %p", + power_down_setting); + rc = -ENOMEM; + goto FREE_POWER_SETTING; + } + + if (slave_info->power_setting_array.power_down_setting) { + if (copy_from_user(power_down_setting, + (void *)slave_info->power_setting_array. + power_down_setting, + sizeof(*power_down_setting) * size_down)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_DOWN_SETTING; + } + } else { + pr_err("failed: no power_down_setting"); + if (copy_from_user(power_down_setting, + (void *)slave_info->power_setting_array. + power_setting, + sizeof(*power_down_setting) * size_down)) { + pr_err("failed: copy_from_user"); + rc = -EFAULT; + goto FREE_POWER_DOWN_SETTING; + } + + /*reverce*/ + end = size_down - 1; + for (c = 0; c < size_down/2; c++) { + power_down_setting_t = power_down_setting[c]; + power_down_setting[c] = power_down_setting[end]; + power_down_setting[end] = power_down_setting_t; + end--; + } + + } + + /* Print power setting */ + for (i = 0; i < size_down; i++) { + CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d", + power_down_setting[i].seq_type, + power_down_setting[i].seq_val, + power_down_setting[i].config_val, + power_down_setting[i].delay); + } + + camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL); + if (!camera_info) { + pr_err("failed: no memory slave_info %p", camera_info); + goto FREE_POWER_DOWN_SETTING; + + } + + /* Fill power up setting and power up setting size */ + power_info = &s_ctrl->sensordata->power_info; + power_info->power_setting = power_setting; + power_info->power_setting_size = size; + power_info->power_down_setting = power_down_setting; + power_info->power_down_setting_size = size_down; + + s_ctrl->sensordata->slave_info = camera_info; + + /* Fill sensor slave info */ + camera_info->sensor_slave_addr = slave_info->slave_addr; + camera_info->sensor_id_reg_addr = + slave_info->sensor_id_info.sensor_id_reg_addr; + camera_info->sensor_id = slave_info->sensor_id_info.sensor_id; + + /* Fill CCI master, slave address and CCI default params */ + if (!s_ctrl->sensor_i2c_client) { + pr_err("failed: sensor_i2c_client %p", + s_ctrl->sensor_i2c_client); + rc = -EINVAL; + goto FREE_CAMERA_INFO; + } + /* Fill sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = slave_info->addr_type; + if (s_ctrl->sensor_i2c_client->client) + s_ctrl->sensor_i2c_client->client->addr = + camera_info->sensor_slave_addr; + + cci_client = s_ctrl->sensor_i2c_client->cci_client; + if (!cci_client) { + pr_err("failed: cci_client %p", cci_client); + goto FREE_CAMERA_INFO; + } + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = slave_info->slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = slave_info->i2c_freq_mode; + + /* Parse and fill vreg params for powerup settings */ + rc = msm_camera_fill_vreg_params( + power_info->cam_vreg, + power_info->num_vreg, + power_info->power_setting, + power_info->power_setting_size); + if (rc < 0) { + pr_err("failed: msm_camera_get_dt_power_setting_data rc %d", + rc); + goto FREE_CAMERA_INFO; + } + + /* Parse and fill vreg params for powerdown settings*/ + rc = msm_camera_fill_vreg_params( + power_info->cam_vreg, + power_info->num_vreg, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc < 0) { + pr_err("failed: msm_camera_fill_vreg_params for PDOWN rc %d", + rc); + goto FREE_CAMERA_INFO; + } + + /* Update sensor, actuator and eeprom name in + * sensor control structure */ + s_ctrl->sensordata->sensor_name = slave_info->sensor_name; + s_ctrl->sensordata->eeprom_name = slave_info->eeprom_name; + s_ctrl->sensordata->actuator_name = slave_info->actuator_name; + + /* + * Update eeporm subdevice Id by input eeprom name + */ + rc = msm_sensor_fill_eeprom_subdevid_by_name(s_ctrl); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_CAMERA_INFO; + } + /* + * Update actuator subdevice Id by input actuator name + */ + rc = msm_sensor_fill_actuator_subdevid_by_name(s_ctrl); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto FREE_CAMERA_INFO; + } + msm_sensor_remove_dev_node_for_eeprom(slave_info->camera_id, + s_ctrl->sensordata->sensor_info->subdev_id[SUB_MODULE_EEPROM]); + /* Power up and probe sensor */ + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + if (rc < 0) { + pr_err("%s power up failed", slave_info->sensor_name); + probe_fail = rc; +// goto FREE_CAMERA_INFO; + } + + pr_err("%s probe succeeded", slave_info->sensor_name); + + /* + Set probe succeeded flag to 1 so that no other camera shall + * probed on this slot + */ + s_ctrl->is_probe_succeed = 1; + + /* + * Create /dev/videoX node, comment for now until dummy /dev/videoX + * node is created and used by HAL + */ + +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) + pr_err("[Probe]%s:%d system_rev:%d\n", __func__, __LINE__, system_rev); + if(system_rev == 0) { + if(slave_info->camera_id == CAMERA_1){ + s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE; + rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl); + } else { + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = msm_sensor_driver_create_v4l_subdev(s_ctrl); + } else { + rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl); + } + } + if (rc < 0) { + pr_err("failed: camera creat v4l2 rc %d", rc); + goto CAMERA_POWER_DOWN; + } + } else { + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) + rc = msm_sensor_driver_create_v4l_subdev(s_ctrl); + else + rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl); + if (rc < 0) { + pr_err("failed: camera creat v4l2 rc %d", rc); + goto CAMERA_POWER_DOWN; + } + } +#else + if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) + rc = msm_sensor_driver_create_v4l_subdev(s_ctrl); + else + rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl); + if (rc < 0) { + pr_err("failed: camera creat v4l2 rc %d", rc); + goto CAMERA_POWER_DOWN; + } +#endif + + memcpy(slave_info->subdev_name, s_ctrl->msm_sd.sd.entity.name, + sizeof(slave_info->subdev_name)); + slave_info->is_probe_succeed = 1; + slave_info->sensor_info.session_id = s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) { + slave_info->sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + pr_err("sensor_subdev_id = %d i = %d\n",slave_info->sensor_info.subdev_id[i], i); + } + if (copy_to_user((void __user *)setting, + (void *)slave_info, sizeof(*slave_info))) { + pr_err("%s:%d copy failed\n", __func__, __LINE__); + rc = -EFAULT; + } + + /* Power down */ + s_ctrl->func_tbl->sensor_power_down(s_ctrl); + + rc = msm_sensor_fill_slave_info_init_params( + slave_info, + s_ctrl->sensordata->sensor_info); + if (rc < 0) { + pr_err("%s Fill slave info failed", slave_info->sensor_name); + goto FREE_CAMERA_INFO; + } + rc = msm_sensor_validate_slave_info(s_ctrl->sensordata->sensor_info); + if (rc < 0) { + pr_err("%s Validate slave info failed", + slave_info->sensor_name); + goto FREE_CAMERA_INFO; + } + /* Update sensor mount angle and position in media entity flag */ + mount_pos = s_ctrl->sensordata->sensor_info->position << 16; + mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info-> + sensor_mount_angle / 90) << 8); + s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT; + + /*Save sensor info*/ + s_ctrl->sensordata->cam_slave_info = slave_info; + + if(probe_fail) { + rc = probe_fail; + } + + return rc; + +CAMERA_POWER_DOWN: + s_ctrl->func_tbl->sensor_power_down(s_ctrl); +FREE_CAMERA_INFO: + kfree(camera_info); +FREE_POWER_DOWN_SETTING: + kfree(power_down_setting); +FREE_POWER_SETTING: + kfree(power_setting); +FREE_SLAVE_INFO: + kfree(slave_info); + return rc; +} + +static int32_t msm_sensor_driver_get_gpio_data( + struct msm_camera_sensor_board_info *sensordata, + struct device_node *of_node) +{ + int32_t rc = 0, i = 0; + struct msm_camera_gpio_conf *gconf = NULL; + uint16_t *gpio_array = NULL; + uint16_t gpio_array_size = 0; + + /* Validate input paramters */ + if (!sensordata || !of_node) { + pr_err("failed: invalid params sensordata %p of_node %p", + sensordata, of_node); + return -EINVAL; + } + + sensordata->power_info.gpio_conf = kzalloc( + sizeof(struct msm_camera_gpio_conf), GFP_KERNEL); + if (!sensordata->power_info.gpio_conf) { + pr_err("failed"); + return -ENOMEM; + } + gconf = sensordata->power_info.gpio_conf; + + gpio_array_size = of_gpio_count(of_node); + CDBG("gpio count %d", gpio_array_size); + if (!gpio_array_size) + return 0; + + gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, GFP_KERNEL); + if (!gpio_array) { + pr_err("failed"); + goto FREE_GPIO_CONF; + } + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("gpio_array[%d] = %d", i, gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc < 0) { + pr_err("failed"); + goto FREE_GPIO_CONF; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc < 0) { + pr_err("failed"); + goto FREE_GPIO_REQ_TBL; + } + + kfree(gpio_array); + return rc; + +FREE_GPIO_REQ_TBL: + kfree(sensordata->power_info.gpio_conf->cam_gpio_req_tbl); +FREE_GPIO_CONF: + kfree(sensordata->power_info.gpio_conf); + kfree(gpio_array); + return rc; +} + +static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + struct msm_camera_sensor_board_info *sensordata = NULL; + struct device_node *of_node = s_ctrl->of_node; + uint32_t cell_id; + + s_ctrl->sensordata = kzalloc(sizeof(*sensordata), GFP_KERNEL); + if (!s_ctrl->sensordata) { + pr_err("failed: no memory"); + return -ENOMEM; + } + + sensordata = s_ctrl->sensordata; + + /* + * Read cell index - this cell index will be the camera slot where + * this camera will be mounted + */ + rc = of_property_read_u32(of_node, "cell-index", &cell_id); + if (rc < 0) { + pr_err("failed: cell-index rc %d", rc); + goto FREE_SENSOR_DATA; + } + s_ctrl->id = cell_id; + + /* Validate cell_id */ + if (cell_id >= MAX_CAMERAS) { + pr_err("failed: invalid cell_id %d", cell_id); + rc = -EINVAL; + goto FREE_SENSOR_DATA; + } + + /* Check whether g_sctrl is already filled for this cell_id */ + if (g_sctrl[cell_id]) { + pr_err("failed: sctrl already filled for cell_id %d", cell_id); + rc = -EINVAL; + goto FREE_SENSOR_DATA; + } + + /* Read subdev info */ + rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info); + if (rc < 0) { + pr_err("failed"); + goto FREE_SENSOR_DATA; + } + + /* Read vreg information */ + rc = msm_camera_get_dt_vreg_data(of_node, + &sensordata->power_info.cam_vreg, + &sensordata->power_info.num_vreg); + if (rc < 0) { + pr_err("failed: msm_camera_get_dt_vreg_data rc %d", rc); + goto FREE_SUB_MODULE_DATA; + } + + /* Read gpio information */ + rc = msm_sensor_driver_get_gpio_data(sensordata, of_node); + if (rc < 0) { + pr_err("failed: msm_sensor_driver_get_gpio_data rc %d", rc); + goto FREE_VREG_DATA; + } + + /* Get CCI master */ + rc = of_property_read_u32(of_node, "qcom,cci-master", + &s_ctrl->cci_i2c_master); + CDBG("qcom,cci-master %d, rc %d", s_ctrl->cci_i2c_master, rc); + if (rc < 0) { + /* Set default master 0 */ + s_ctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + /* Get mount angle */ + if (0 > of_property_read_u32(of_node, "qcom,mount-angle", + &sensordata->sensor_info->sensor_mount_angle)) { + /* Invalidate mount angle flag */ + sensordata->sensor_info->is_mount_angle_valid = 0; + sensordata->sensor_info->sensor_mount_angle = 0; + } else { + sensordata->sensor_info->is_mount_angle_valid = 1; + } + CDBG("%s qcom,mount-angle %d\n", __func__, + sensordata->sensor_info->sensor_mount_angle); + if (0 > of_property_read_u32(of_node, "qcom,sensor-position", + &sensordata->sensor_info->position)) { + CDBG("%s:%d Invalid sensor position\n", __func__, __LINE__); + sensordata->sensor_info->position = INVALID_CAMERA_B; + } + if (0 > of_property_read_u32(of_node, "qcom,sensor-mode", + &sensordata->sensor_info->modes_supported)) { + CDBG("%s:%d Invalid sensor mode supported\n", + __func__, __LINE__); + sensordata->sensor_info->modes_supported = CAMERA_MODE_INVALID; + } + /* Get vdd-cx regulator */ + /*Optional property, don't return error if absent */ + of_property_read_string(of_node, "qcom,vdd-cx-name", + &sensordata->misc_regulator); + CDBG("qcom,misc_regulator %s", sensordata->misc_regulator); + + s_ctrl->set_mclk_23880000 = of_property_read_bool(of_node, + "qcom,mclk-23880000"); + + CDBG("%s qcom,mclk-23880000 = %d\n", __func__, + s_ctrl->set_mclk_23880000); + +#if defined (CONFIG_CAMERA_SYSFS_V2) + /* camera information */ + if (cell_id == 0) { + rc = msm_camera_get_dt_camera_info(of_node, rear_cam_info); + if (rc < 0) { + pr_err("failed: msm_camera_get_dt_camera_info rc %d", rc); + goto FREE_VREG_DATA; + } + } else { + rc = msm_camera_get_dt_camera_info(of_node, front_cam_info); + if (rc < 0) { + pr_err("failed: msm_camera_get_dt_camera_info rc %d", rc); + goto FREE_VREG_DATA; + } + } +#endif + return rc; + +FREE_VREG_DATA: + kfree(sensordata->power_info.cam_vreg); +FREE_SUB_MODULE_DATA: + kfree(sensordata->sensor_info); +FREE_SENSOR_DATA: + kfree(sensordata); + return rc; +} + +static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + + CDBG("Enter"); + /* Validate input parameters */ + + + /* Allocate memory for sensor_i2c_client */ + s_ctrl->sensor_i2c_client = kzalloc(sizeof(*s_ctrl->sensor_i2c_client), + GFP_KERNEL); + if (!s_ctrl->sensor_i2c_client) { + pr_err("failed: no memory sensor_i2c_client %p", + s_ctrl->sensor_i2c_client); + return -ENOMEM; + } + + /* Allocate memory for mutex */ + s_ctrl->msm_sensor_mutex = kzalloc(sizeof(*s_ctrl->msm_sensor_mutex), + GFP_KERNEL); + if (!s_ctrl->msm_sensor_mutex) { + pr_err("failed: no memory msm_sensor_mutex %p", + s_ctrl->msm_sensor_mutex); + goto FREE_SENSOR_I2C_CLIENT; + } + + /* Parse dt information and store in sensor control structure */ + rc = msm_sensor_driver_get_dt_data(s_ctrl); + if (rc < 0) { + pr_err("failed: rc %d", rc); + goto FREE_MUTEX; + } + + /* Initialize mutex */ + mutex_init(s_ctrl->msm_sensor_mutex); + + /* Initilize v4l2 subdev info */ + s_ctrl->sensor_v4l2_subdev_info = msm_sensor_driver_subdev_info; + s_ctrl->sensor_v4l2_subdev_info_size = + ARRAY_SIZE(msm_sensor_driver_subdev_info); + + /* Initialize default parameters */ + rc = msm_sensor_init_default_params(s_ctrl); + if (rc < 0) { + pr_err("failed: msm_sensor_init_default_params rc %d", rc); + goto FREE_DT_DATA; + } + + /* Store sensor control structure in static database */ + g_sctrl[s_ctrl->id] = s_ctrl; + pr_err("g_sctrl[%d] %p", s_ctrl->id, g_sctrl[s_ctrl->id]); + + return rc; + +FREE_DT_DATA: + kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info); + kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl); + kfree(s_ctrl->sensordata->power_info.gpio_conf); + kfree(s_ctrl->sensordata->power_info.cam_vreg); + kfree(s_ctrl->sensordata); +FREE_MUTEX: + kfree(s_ctrl->msm_sensor_mutex); +FREE_SENSOR_I2C_CLIENT: + kfree(s_ctrl->sensor_i2c_client); + return rc; +} + +static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct msm_sensor_ctrl_t *s_ctrl = NULL; + + + /* Create sensor control structure */ + s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); + if (!s_ctrl) { + pr_err("failed: no memory s_ctrl %p", s_ctrl); + return -ENOMEM; + } + + platform_set_drvdata(pdev, s_ctrl); + + /* Initialize sensor device type */ + s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE; + s_ctrl->of_node = pdev->dev.of_node; + + rc = msm_sensor_driver_parse(s_ctrl); + if (rc < 0) { + pr_err("failed: msm_sensor_driver_parse rc %d", rc); + goto FREE_S_CTRL; + } + + /* Fill platform device */ + pdev->id = s_ctrl->id; + s_ctrl->pdev = pdev; + + /* Fill device in power info */ + s_ctrl->sensordata->power_info.dev = &pdev->dev; + + return rc; +FREE_S_CTRL: + kfree(s_ctrl); + return rc; +} + +static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0; + struct msm_sensor_ctrl_t *s_ctrl; + + CDBG("\n\nEnter: msm_sensor_driver_i2c_probe"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s %s i2c_check_functionality failed\n", + __func__, client->name); + rc = -EFAULT; + return rc; + } + + /* Create sensor control structure */ + s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); + if (!s_ctrl) { + pr_err("failed: no memory s_ctrl %p", s_ctrl); + return -ENOMEM; + } + + i2c_set_clientdata(client, s_ctrl); + + /* Initialize sensor device type */ + s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE; + s_ctrl->of_node = client->dev.of_node; + + rc = msm_sensor_driver_parse(s_ctrl); + if (rc < 0) { + pr_err("failed: msm_sensor_driver_parse rc %d", rc); + goto FREE_S_CTRL; + } + + if (s_ctrl->sensor_i2c_client != NULL) { + s_ctrl->sensor_i2c_client->client = client; + s_ctrl->sensordata->power_info.dev = &client->dev; + + } + + return rc; +FREE_S_CTRL: + kfree(s_ctrl); + return rc; +} + +static int msm_sensor_driver_i2c_remove(struct i2c_client *client) +{ + struct msm_sensor_ctrl_t *s_ctrl = i2c_get_clientdata(client); + + pr_err("%s: sensor FREE\n", __func__); + + if (!s_ctrl) { + pr_err("%s: sensor device is NULL\n", __func__); + return 0; + } + + g_sctrl[s_ctrl->id] = NULL; + msm_sensor_free_sensor_data(s_ctrl); + kfree(s_ctrl->msm_sensor_mutex); + kfree(s_ctrl->sensor_i2c_client); + kfree(s_ctrl); + + return 0; +} + +static const struct i2c_device_id i2c_id[] = { + {SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver msm_sensor_driver_i2c = { + .id_table = i2c_id, + .probe = msm_sensor_driver_i2c_probe, + .remove = msm_sensor_driver_i2c_remove, + .driver = { + .name = SENSOR_DRIVER_I2C, + }, +}; + +static int __init msm_sensor_driver_init(void) +{ + int32_t rc = 0; + + CDBG("Enter"); + rc = platform_driver_probe(&msm_sensor_platform_driver, + msm_sensor_driver_platform_probe); + if (!rc) { + CDBG("probe success"); + +#if defined(CONFIG_SEC_NOVEL_PROJECT) && defined(CONFIG_CAM_USE_GPIO_I2C) + pr_err("[msm_sensor_driver_init]%s:%d system_rev:%d\n", __func__, __LINE__, system_rev); + if(system_rev == 0) { + rc = i2c_add_driver(&msm_sensor_driver_i2c); + } +#endif + return rc; + } else { + CDBG("probe i2c"); + rc = i2c_add_driver(&msm_sensor_driver_i2c); + } + + return rc; +} + + +static void __exit msm_sensor_driver_exit(void) +{ + CDBG("Enter"); + platform_driver_unregister(&msm_sensor_platform_driver); + i2c_del_driver(&msm_sensor_driver_i2c); + return; +} + +#if defined CONFIG_SEC_CAMERA_TUNING +int register_table_init(char *filename) { + struct file *filp; + char *dp; + long lsize; + loff_t pos; + int ret; + /*Get the current address space */ + mm_segment_t fs = get_fs(); + pr_err("%s %d", __func__, __LINE__); + /*Set the current segment to kernel data segment */ + set_fs(get_ds()); + filp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR_OR_NULL(filp)) { + pr_err("file open error %ld",(long) filp); + return -1; + } + lsize = filp->f_path.dentry->d_inode->i_size; + pr_err("size : %ld", lsize); + dp = vmalloc(lsize); + if (dp == NULL) { + pr_err("Out of Memory"); + filp_close(filp, current->files); + return -1; + } + pos = 0; + memset(dp, 0, lsize); + ret = vfs_read(filp, (char __user *)dp, lsize, &pos); + if (ret != lsize) { + pr_err("Failed to read file ret = %d\n", ret); + vfree(dp); + filp_close(filp, current->files); + return -1; + } + /*close the file*/ + filp_close(filp, current->files); + /*restore the previous address space*/ + set_fs(fs); + pr_err("coming to if part of string compare sr352_regs_table"); + regs_table = dp; + table_size = lsize; + *((regs_table+ table_size) - 1) = '\0'; + return 0; +} + +void register_table_exit(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (regs_table) { + vfree(regs_table); + regs_table = NULL; + } +} + +int register_read_from_sdcard (struct msm_camera_i2c_reg_conf *settings, + struct msm_sensor_ctrl_t *s_ctrl, + enum msm_camera_i2c_data_type data_type, + char *name) { + char *start, *end, *reg,reg_buf[7], data_buf[7]; + int rc,addr,value; + addr=0; + rc=0; + value=0; + + if(data_type == MSM_CAMERA_I2C_BYTE_DATA) { + *(reg_buf + 4) = '\0'; + *(data_buf + 4) = '\0'; + } else { + *(reg_buf + 6) = '\0'; + *(data_buf + 6) = '\0'; + } + if(regs_table == NULL) { + pr_err("regs_table is null "); + return -1; + } + pr_err("@@@ %s",name); + start = strstr(regs_table, name); + if (start == NULL){ + return -1; + } + end = strstr(start, "};"); + while (1) { + /* Find Address */ + reg = strstr(start, "{0x"); + if ((reg == NULL) || (reg > end)) + break; + /* Write Value to Address */ + if (reg != NULL) { + if(data_type == MSM_CAMERA_I2C_BYTE_DATA) { + memcpy(reg_buf, (reg + 1), 4); + memcpy(data_buf, (reg + 7), 4); + } else { + memcpy(reg_buf, (reg + 1), 6); + memcpy(data_buf, (reg + 9), 6); + } + if(kstrtoint(reg_buf, 16, &addr)) + pr_err("kstrtoint error .Please Align contents of the Header file!!") ; + if(kstrtoint(data_buf, 16, &value)) + pr_err("kstrtoint error .Please Align contents of the Header file!!"); + if(data_type == MSM_CAMERA_I2C_BYTE_DATA) { + start = (reg + 14); + if (addr == 0xff){ + msleep(value); + } else { + rc=s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write(s_ctrl->sensor_i2c_client, addr, + value,MSM_CAMERA_I2C_BYTE_DATA); + } + } else { + start = (reg + 18); + if (addr == 0xff){ + msleep(value); + } else { + rc=s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write(s_ctrl->sensor_i2c_client, addr, + value,MSM_CAMERA_I2C_WORD_DATA); + } + } + } + } + pr_err("register_read_from_sdcard end!"); + return rc; +} + +#endif + +module_init(msm_sensor_driver_init); +module_exit(msm_sensor_driver_exit); +MODULE_DESCRIPTION("msm_sensor_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_driver.h b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_driver.h new file mode 100644 index 0000000000000000000000000000000000000000..a0aaa38183099d3d06bed1dd15855b35c30ee3b8 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_driver.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_SENSOR_DRIVER_H +#define MSM_SENSOR_DRIVER_H + +#include "msm_sensor.h" + +int32_t msm_sensor_driver_probe(void *setting); +int32_t msm_sensor_remove_dev_node_for_eeprom(int id,int remove); +struct yuv_userset { + unsigned int metering; + unsigned int exposure; + unsigned int wb; + unsigned int iso; + unsigned int effect; + unsigned int scenemode; + unsigned int aeawblock; + unsigned int resolution; + unsigned int prev_resolution; +}; + +struct yuv_ctrl { + struct yuv_userset settings; + int op_mode; + int prev_mode; + int streamon; + int vtcall_mode; + int exif_iso; + int exif_shutterspeed; +}; + + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_init.c new file mode 100644 index 0000000000000000000000000000000000000000..bcfaa1804e7242710052c73aaa31e4ef4a5652d5 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_init.c @@ -0,0 +1,622 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. 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 and + * only 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. + */ + +#define pr_fmt(fmt) "MSM-SENSOR-INIT %s:%d " fmt "\n", __func__, __LINE__ + +/* Header files */ +#include +#include "msm_sensor_init.h" +#include "msm_sensor_driver.h" +#include "msm_sensor.h" +#include "msm_sd.h" + +/* Logging macro */ +//#define CONFIG_MSMB_CAMERA_DEBUG +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +struct class *camera_class = NULL; +struct device *cam_dev_back = NULL; +struct device *cam_dev_front = NULL; + +uint16_t rear_vendor_id = 0; + +static struct msm_sensor_init_t *s_init; + +/* Static function declaration */ +static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg); + +/* Static structure declaration */ +static struct v4l2_subdev_core_ops msm_sensor_init_subdev_core_ops = { + .ioctl = msm_sensor_init_subdev_ioctl, +}; + +static struct v4l2_subdev_ops msm_sensor_init_subdev_ops = { + .core = &msm_sensor_init_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_sensor_init_internal_ops; + +static int msm_sensor_wait_for_probe_done(struct msm_sensor_init_t *s_init) +{ + int rc; + int tm = 10000; + + if (s_init->module_init_status == 1) { + pr_err("msm_cam_get_module_init_status -2\n"); + return 0; + } + rc = wait_event_interruptible_timeout(s_init->state_wait, + (s_init->module_init_status == 1), msecs_to_jiffies(tm)); + if (rc < 0) + pr_err("%s:%d wait failed\n", __func__, __LINE__); + else if (rc == 0) + pr_err("%s:%d wait timeout\n", __func__, __LINE__); + + return rc; +} + +/* Static function definition */ +static int32_t msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init, + void *arg) +{ + int32_t rc = 0; + struct sensor_init_cfg_data *cfg = (struct sensor_init_cfg_data *)arg; + + /* Validate input parameters */ + if (!s_init || !cfg) { + pr_err("failed: s_init %p cfg %p", s_init, cfg); + return -EINVAL; + } + + switch (cfg->cfgtype) { + case CFG_SINIT_PROBE: + mutex_lock(&s_init->imutex); + s_init->module_init_status = 0; + rc = msm_sensor_driver_probe(cfg->cfg.setting); + mutex_unlock(&s_init->imutex); + if (rc < 0) + pr_err("failed: msm_sensor_driver_probe rc %d", rc); + break; + + case CFG_SINIT_PROBE_DONE: + s_init->module_init_status = 1; + wake_up(&s_init->state_wait); + break; + + case CFG_SINIT_PROBE_WAIT_DONE: + msm_sensor_wait_for_probe_done(s_init); + break; + + default: + pr_err("default"); + break; + } + + return rc; +} + +static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + struct msm_sensor_init_t *s_init = v4l2_get_subdevdata(sd); + CDBG("Enter"); + + /* Validate input parameters */ + if (!s_init) { + pr_err("failed: s_init %p", s_init); + return -EINVAL; + } + + switch (cmd) { + case VIDIOC_MSM_SENSOR_INIT_CFG: + rc = msm_sensor_driver_cmd(s_init, arg); + break; + + default: + pr_err_ratelimited("default\n"); + break; + } + + return rc; +} + + +static ssize_t back_camera_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + +#if defined(CONFIG_IMX219) + char type[] = "SONY_IMX219\n"; +#elif defined(CONFIG_S5K4H5YB) + char type[] = "SLSI_S5K4H5YB\n"; +#elif defined(CONFIG_S5K3L2XX) + char type[] = "SLSI_S5K3L2XX\n"; +#elif defined(CONFIG_S5K4ECGX) + char type[] = "SLSI_S5K4ECGX\n"; +#elif defined(CONFIG_IMX135) + char type[] = "SONY_IMX135\n"; +#elif defined(CONFIG_SR544) + char type[] = "SILICONFILE_SR544\n"; +#else + char type[] = "NULL\n"; +#endif + + return snprintf(buf, sizeof(type), "%s", type); +} + +static ssize_t front_camera_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_S5K6A3YX) + char cam_type[] = "SLSI_S5K6A3YX\n"; +#elif defined(CONFIG_S5K5E3YX) + char cam_type[] = "SLSI_S5K5E3YX\n"; +#elif defined(CONFIG_SR200PC20) + char cam_type[] = "SILICONFILE_SR200PC20\n"; +#elif defined(CONFIG_S5K6B2YX) + char cam_type[] = "SLSI_S5K6B2YX\n"; +#else + char cam_type[] = "NULL\n"; +#endif + + return snprintf(buf, sizeof(cam_type), "%s", cam_type); +} + +char cam_fw_ver[25] = "NULL NULL\n"; +static ssize_t back_camera_firmware_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_S5K4ECGX) + char cam_fw[] = "S5K4ECGX N\n"; + return snprintf(buf, sizeof(cam_fw), "%s", cam_fw); +#else + CDBG("[FW_DBG] cam_fw_ver : %s\n", cam_fw_ver); + return snprintf(buf, sizeof(cam_fw_ver), "%s", cam_fw_ver); +#endif +} + +static ssize_t back_camera_firmware_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(cam_fw_ver, sizeof(cam_fw_ver), "%s", buf); + + return size; +} + +char cam_load_fw[25] = "NULL\n"; +static ssize_t back_camera_firmware_load_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_load_fw : %s\n", cam_load_fw); + return snprintf(buf, sizeof(cam_load_fw), "%s", cam_load_fw); +} + +static ssize_t back_camera_firmware_load_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(cam_load_fw, sizeof(cam_load_fw), "%s\n", buf); + return size; +} + +char cam_fw_full_ver[40] = "NULL NULL NULL\n";//multi module +static ssize_t back_camera_firmware_full_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_fw_ver : %s\n", cam_fw_full_ver); + return snprintf(buf, sizeof(cam_fw_full_ver), "%s", cam_fw_full_ver); +} + +static ssize_t back_camera_firmware_full_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(cam_fw_full_ver, sizeof(cam_fw_full_ver), "%s", buf); + return size; +} + +static ssize_t rear_camera_isp_core_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char isp_core[] = "0.9000\n"; + return snprintf(buf, sizeof(isp_core), "%s", isp_core); +} +static ssize_t rear_camera_vendorid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char vendor_id[16] = {0}; + if (rear_vendor_id) + sprintf(vendor_id, "0x0%x\n", rear_vendor_id); + else + strncpy(vendor_id, "NULL\n", sizeof(vendor_id)); + + return snprintf(buf, sizeof(vendor_id), "%s", vendor_id); +} + +char cam_fw_user_ver[40] = "NULL NULL\n";//multi module +static ssize_t back_camera_firmware_user_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_fw_ver : %s\n", cam_fw_user_ver); + return snprintf(buf, sizeof(cam_fw_user_ver), "%s", cam_fw_user_ver); +} + +static ssize_t back_camera_firmware_user_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(cam_fw_user_ver, sizeof(cam_fw_user_ver), "%s", buf); + + return size; +} + +char cam_fw_factory_ver[40] = "NULL NULL\n";//multi module +static ssize_t back_camera_firmware_factory_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_fw_ver : %s\n", cam_fw_factory_ver); + return snprintf(buf, sizeof(cam_fw_factory_ver), "%s", cam_fw_factory_ver); +} + +static ssize_t back_camera_firmware_factory_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(cam_fw_factory_ver, sizeof(cam_fw_factory_ver), "%s", buf); + + return size; +} + +#if defined(CONFIG_S5K5E3YX) && !defined(CONFIG_MSM_FRONT_EEPROM) +char front_cam_fw_ver[25] = "S5K5E3YX N\n"; +#elif defined(CONFIG_S5K6A3YX) +char front_cam_fw_ver[25] = "S5K6A3YX N\n"; +#elif defined(CONFIG_SR200PC20) + char front_cam_fw_ver[25] = "SR200PC20M N\n"; +#else +char front_cam_fw_ver[25] = "NULL NULL\n"; +#endif +static ssize_t front_camera_firmware_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] front_cam_fw_ver : %s\n", front_cam_fw_ver); + return snprintf(buf, sizeof(front_cam_fw_ver), "%s", front_cam_fw_ver); +} + +static ssize_t front_camera_firmware_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(front_cam_fw_ver, sizeof(front_cam_fw_ver), "%s", buf); + + return size; +} + +#if defined(CONFIG_S5K5E3YX) && !defined(CONFIG_MSM_FRONT_EEPROM) +char front_cam_load_fw[25] = "S5K5E3YX\n"; +static ssize_t front_camera_firmware_load_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_load_fw : %s\n", front_cam_load_fw); + return snprintf(buf, sizeof(front_cam_load_fw), "%s", front_cam_load_fw); +} +static ssize_t front_camera_firmware_load_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + //snprintf(front_cam_load_fw, sizeof(front_cam_load_fw), "%s\n", buf); + return size; +} + +char front_cam_fw_full_ver[40] = "S5K5E3YX N N\n";//multi module +static ssize_t front_camera_firmware_full_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] front_cam_fw_full_ver : %s\n", front_cam_fw_full_ver); + return snprintf(buf, sizeof(front_cam_fw_full_ver), "%s", front_cam_fw_full_ver); +} +static ssize_t front_camera_firmware_full_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + //snprintf(front_cam_fw_full_ver, sizeof(front_cam_fw_full_ver), "%s", buf); + return size; +} +#else +char front_cam_load_fw[25] = "NULL\n"; +static ssize_t front_camera_firmware_load_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_load_fw : %s\n", front_cam_load_fw); + return snprintf(buf, sizeof(front_cam_load_fw), "%s", front_cam_load_fw); +} +static ssize_t front_camera_firmware_load_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(front_cam_load_fw, sizeof(front_cam_load_fw), "%s\n", buf); + return size; +} + +char front_cam_fw_full_ver[40] = "NULL NULL NULL\n";//multi module +static ssize_t front_camera_firmware_full_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] front_cam_fw_full_ver : %s\n", front_cam_fw_full_ver); + return snprintf(buf, sizeof(front_cam_fw_full_ver), "%s", front_cam_fw_full_ver); +} +static ssize_t front_camera_firmware_full_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); + snprintf(front_cam_fw_full_ver, sizeof(front_cam_fw_full_ver), "%s", buf); + return size; +} +#endif + +#if defined (CONFIG_CAMERA_SYSFS_V2) +char rear_cam_info[100] = "NULL\n"; //camera_info +static ssize_t rear_camera_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_info : %s\n", rear_cam_info); + return snprintf(buf, sizeof(rear_cam_info), "%s", rear_cam_info); +} + +static ssize_t rear_camera_info_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); +// snprintf(rear_cam_info, sizeof(rear_cam_info), "%s", buf); + + return size; +} + +char front_cam_info[100] = "NULL\n"; //camera_info +static ssize_t front_camera_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CDBG("[FW_DBG] cam_info : %s\n", front_cam_info); + return snprintf(buf, sizeof(front_cam_info), "%s", front_cam_info); +} + +static ssize_t front_camera_info_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + CDBG("[FW_DBG] buf : %s\n", buf); +// snprintf(front_cam_info, sizeof(front_cam_info), "%s", buf); + + return size; +} +#endif + +static DEVICE_ATTR(rear_camtype, S_IRUGO, back_camera_type_show, NULL); +static DEVICE_ATTR(rear_camfw, S_IRUGO|S_IWUSR|S_IWGRP, + back_camera_firmware_show, back_camera_firmware_store); +static DEVICE_ATTR(rear_checkfw_user, S_IRUGO|S_IWUSR|S_IWGRP, + back_camera_firmware_user_show, back_camera_firmware_user_store); +static DEVICE_ATTR(rear_checkfw_factory, S_IRUGO|S_IWUSR|S_IWGRP, + back_camera_firmware_factory_show, back_camera_firmware_factory_store); +static DEVICE_ATTR(rear_camfw_load, S_IRUGO|S_IWUSR|S_IWGRP, + back_camera_firmware_load_show, back_camera_firmware_load_store); +static DEVICE_ATTR(rear_camfw_full, S_IRUGO | S_IWUSR | S_IWGRP, + back_camera_firmware_full_show, back_camera_firmware_full_store); +static DEVICE_ATTR(isp_core, S_IRUGO, rear_camera_isp_core_show, NULL); +static DEVICE_ATTR(front_camtype, S_IRUGO, front_camera_type_show, NULL); +static DEVICE_ATTR(front_camfw, S_IRUGO|S_IWUSR|S_IWGRP, + front_camera_firmware_show, front_camera_firmware_store); +static DEVICE_ATTR(front_camfw_load, S_IRUGO|S_IWUSR|S_IWGRP, + front_camera_firmware_load_show, front_camera_firmware_load_store); +#if defined (CONFIG_CAMERA_SYSFS_V2) +static DEVICE_ATTR(rear_caminfo, S_IRUGO|S_IWUSR|S_IWGRP, + rear_camera_info_show, rear_camera_info_store); +static DEVICE_ATTR(front_caminfo, S_IRUGO|S_IWUSR|S_IWGRP, + front_camera_info_show, front_camera_info_store); +#endif + + +static DEVICE_ATTR(front_camfw_full, S_IRUGO | S_IWUSR | S_IWGRP, + front_camera_firmware_full_show, front_camera_firmware_full_store); + +static DEVICE_ATTR(rear_vendorid, S_IRUGO, rear_camera_vendorid_show, NULL); + +int32_t msm_sensor_remove_dev_node_for_eeprom(int id, int remove) +{ + if(id == CAMERA_0) { + if(remove == -1) { + device_remove_file(cam_dev_back, &dev_attr_rear_camfw_full); + pr_err("[CAM][Rear] EEPROM node removed\n"); + } + } else { + if(remove == -1) { + device_remove_file(cam_dev_front, &dev_attr_front_camfw_full); + pr_err("[CAM][Front] EEPROM node removed\n"); + } + } + return 0; +} +static int __init msm_sensor_init_module(void) +{ + struct msm_sensor_init_t *s_init = NULL; + int rc = 0; + + if (camera_class == NULL){ + camera_class = class_create(THIS_MODULE, "camera"); + if (IS_ERR(camera_class)) + pr_err("failed to create device cam_dev_rear!\n"); + } + /* Allocate memory for msm_sensor_init control structure */ + s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL); + if (!s_init) { + class_destroy(camera_class); + pr_err("failed: no memory s_init %p", NULL); + return -ENOMEM; + } + + pr_err("MSM_SENSOR_INIT_MODULE %p", NULL); + + /* Initialize mutex */ + mutex_init(&s_init->imutex); + + /* Create /dev/v4l-subdevX for msm_sensor_init */ + v4l2_subdev_init(&s_init->msm_sd.sd, &msm_sensor_init_subdev_ops); + snprintf(s_init->msm_sd.sd.name, sizeof(s_init->msm_sd.sd.name), "%s", + "msm_sensor_init"); + v4l2_set_subdevdata(&s_init->msm_sd.sd, s_init); + s_init->msm_sd.sd.internal_ops = &msm_sensor_init_internal_ops; + s_init->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + rc = media_entity_init(&s_init->msm_sd.sd.entity, 0, NULL, 0); + if (rc < 0) + goto entity_fail; + s_init->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + s_init->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR_INIT; + s_init->msm_sd.sd.entity.name = s_init->msm_sd.sd.name; + s_init->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6; + rc = msm_sd_register(&s_init->msm_sd); + if (rc < 0) + goto msm_sd_register_fail; + + cam_dev_back = device_create(camera_class, NULL, + 1, NULL, "rear"); + if (IS_ERR(cam_dev_back)) { + printk("Failed to create cam_dev_back device!\n"); + goto device_create_fail; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_camtype) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_camtype.attr.name); + goto device_create_fail; + } + if (device_create_file(cam_dev_back, &dev_attr_rear_camfw) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_camfw.attr.name); + goto device_create_fail; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_checkfw_user) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_checkfw_user.attr.name); + rc = -ENODEV; + goto device_create_fail; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_checkfw_factory) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_checkfw_factory.attr.name); + rc = -ENODEV; + goto device_create_fail; + } + + if (device_create_file(cam_dev_back, &dev_attr_isp_core) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_isp_core.attr.name); + goto device_create_fail; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_camfw_load) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_camfw_load.attr.name); + goto device_create_fail; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_camfw_full) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_camfw_full.attr.name); + goto device_create_fail; + } + + if (device_create_file(cam_dev_back, &dev_attr_rear_vendorid) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_vendorid.attr.name); + goto device_create_fail; + } + +#if defined (CONFIG_CAMERA_SYSFS_V2) + if (device_create_file(cam_dev_back, &dev_attr_rear_caminfo) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_caminfo.attr.name); + goto device_create_fail; + } +#endif + + cam_dev_front = device_create(camera_class, NULL, + 2, NULL, "front"); + if (IS_ERR(cam_dev_front)) { + printk("Failed to create cam_dev_front device!"); + goto device_create_fail; + } + + if (device_create_file(cam_dev_front, &dev_attr_front_camtype) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_front_camtype.attr.name); + goto device_create_fail; + } + if (device_create_file(cam_dev_front, &dev_attr_front_camfw) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_front_camfw.attr.name); + goto device_create_fail; + } + if (device_create_file(cam_dev_front, &dev_attr_front_camfw_load) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_camfw_load.attr.name); + goto device_create_fail; + } + + if (device_create_file(cam_dev_front, &dev_attr_front_camfw_full) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_rear_camfw_full.attr.name); + goto device_create_fail; + } + +#if defined (CONFIG_CAMERA_SYSFS_V2) + if (device_create_file(cam_dev_front, &dev_attr_front_caminfo) < 0) { + printk("Failed to create device file!(%s)!\n", + dev_attr_front_caminfo.attr.name); + goto device_create_fail; + } +#endif + + init_waitqueue_head(&s_init->state_wait); + + return 0; +device_create_fail: + msm_sd_unregister(&s_init->msm_sd); +msm_sd_register_fail: + media_entity_cleanup(&s_init->msm_sd.sd.entity); +entity_fail: + mutex_destroy(&s_init->imutex); + kfree(s_init); + class_destroy(camera_class); + return rc; +} + +static void __exit msm_sensor_exit_module(void) +{ + msm_sd_unregister(&s_init->msm_sd); + mutex_destroy(&s_init->imutex); + kfree(s_init); + return; +} + +module_init(msm_sensor_init_module); +module_exit(msm_sensor_exit_module); +MODULE_DESCRIPTION("msm_sensor_init"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_init.h b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_init.h new file mode 100644 index 0000000000000000000000000000000000000000..a9700ec94d43b8767f9c231f4347530b1e7bebad --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/msm_sensor_init.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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. + */ + +#ifndef MSM_SENSOR_INIT_H +#define MSM_SENSOR_INIT_H + +#include "msm_sensor.h" + +struct msm_sensor_init_t { + struct mutex imutex; + struct msm_sd_subdev msm_sd; + int module_init_status; + wait_queue_head_t state_wait; +}; + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/mt9m114.c b/drivers/media/platform/msm/camera_v2_j5/sensor/mt9m114.c new file mode 100644 index 0000000000000000000000000000000000000000..97feef3d945c9798e2faaabd6ef537104930debc --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/mt9m114.c @@ -0,0 +1,1510 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#define MT9M114_SENSOR_NAME "mt9m114" +#define PLATFORM_DRIVER_NAME "msm_camera_mt9m114" +#define mt9m114_obj mt9m114_##obj + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +/* Sysctl registers */ +#define MT9M114_COMMAND_REGISTER 0x0080 +#define MT9M114_COMMAND_REGISTER_APPLY_PATCH (1 << 0) +#define MT9M114_COMMAND_REGISTER_SET_STATE (1 << 1) +#define MT9M114_COMMAND_REGISTER_REFRESH (1 << 2) +#define MT9M114_COMMAND_REGISTER_WAIT_FOR_EVENT (1 << 3) +#define MT9M114_COMMAND_REGISTER_OK (1 << 15) + +DEFINE_MSM_MUTEX(mt9m114_mut); +static struct msm_sensor_ctrl_t mt9m114_s_ctrl; + +static struct msm_sensor_power_setting mt9m114_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 100, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf mt9m114_720p_settings[] = { + {0xdc00, 0x50, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {0xDC01, 0x52, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_POLL}, + + {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC800, 0x007C,},/*y_addr_start = 124*/ + {0xC802, 0x0004,},/*x_addr_start = 4*/ + {0xC804, 0x0353,},/*y_addr_end = 851*/ + {0xC806, 0x050B,},/*x_addr_end = 1291*/ + {0xC808, 0x02DC,},/*pixclk = 48000000*/ + {0xC80A, 0x6C00,},/*pixclk = 48000000*/ + {0xC80C, 0x0001,},/*row_speed = 1*/ + {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ + {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ + {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ + {0xC814, 0x0640,},/*line_length_pck = 1600*/ + {0xC816, 0x0060,},/*fine_correction = 96*/ + {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ + {0xC826, 0x0020,},/*reg_0_data = 32*/ + {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ + {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ + {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ + {0xC858, 0x0500,},/*crop_window_width = 1280*/ + {0xC85A, 0x02D0,},/*crop_window_height = 720*/ + {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ + {0xC868, 0x0500,},/*output_width = 1280*/ + {0xC86A, 0x02D0,},/*output_height = 720*/ + {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ + {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ + {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ + {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ + {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ + {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ + {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ + {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ + {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ + {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ + {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ +}; + +static struct msm_camera_i2c_reg_conf mt9m114_recommend_settings[] = { + {0x301A, 0x0200, MSM_CAMERA_I2C_SET_WORD_MASK}, + {0x098E, 0, MSM_CAMERA_I2C_BYTE_DATA}, + /*cam_sysctl_pll_enable = 1*/ + {0xC97E, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + /*cam_sysctl_pll_divider_m_n = 288*/ + {0xC980, 0x0120,}, + /*cam_sysctl_pll_divider_p = 1792*/ + {0xC982, 0x0700,}, + /*output_control = 32769*/ + {0xC984, 0x8001,}, + /*mipi_timing_t_hs_zero = 3840*/ + {0xC988, 0x0F00,}, + /*mipi_timing_t_hs_exit_hs_trail = 2823*/ + {0xC98A, 0x0B07,}, + /*mipi_timing_t_clk_post_clk_pre = 3329*/ + {0xC98C, 0x0D01,}, + /*mipi_timing_t_clk_trail_clk_zero = 1821*/ + {0xC98E, 0x071D,}, + /*mipi_timing_t_lpx = 6*/ + {0xC990, 0x0006,}, + /*mipi_timing_init_timing = 2572*/ + {0xC992, 0x0A0C,}, + {0xC800, 0x007C,},/*y_addr_start = 124*/ + {0xC802, 0x0004,},/*x_addr_start = 4*/ + {0xC804, 0x0353,},/*y_addr_end = 851*/ + {0xC806, 0x050B,},/*x_addr_end = 1291*/ + {0xC808, 0x02DC,},/*pixclk = 48000000*/ + {0xC80A, 0x6C00,},/*pixclk = 48000000*/ + {0xC80C, 0x0001,},/*row_speed = 1*/ + {0xC80E, 0x00DB,},/*fine_integ_time_min = 219*/ + {0xC810, 0x05BD,},/*fine_integ_time_max = 1469*/ + {0xC812, 0x03E8,},/*frame_length_lines = 1000*/ + {0xC814, 0x0640,},/*line_length_pck = 1600*/ + {0xC816, 0x0060,},/*fine_correction = 96*/ + {0xC818, 0x02D3,},/*cpipe_last_row = 723*/ + {0xC826, 0x0020,},/*reg_0_data = 32*/ + {0xC834, 0x0000,},/*sensor_control_read_mode = 0*/ + {0xC854, 0x0000,},/*crop_window_xoffset = 0*/ + {0xC856, 0x0000,},/*crop_window_yoffset = 0*/ + {0xC858, 0x0500,},/*crop_window_width = 1280*/ + {0xC85A, 0x02D0,},/*crop_window_height = 720*/ + {0xC85C, 0x03, MSM_CAMERA_I2C_BYTE_DATA}, /*crop_cropmode = 3*/ + {0xC868, 0x0500,},/*output_width = 1280*/ + {0xC86A, 0x02D0,},/*output_height = 720*/ + {0xC878, 0x00, MSM_CAMERA_I2C_BYTE_DATA}, /*aet_aemode = 0*/ + {0xC88C, 0x1E00,},/*aet_max_frame_rate = 7680*/ + {0xC88E, 0x1E00,},/*aet_min_frame_rate = 7680*/ + {0xC914, 0x0000,},/*stat_awb_window_xstart = 0*/ + {0xC916, 0x0000,},/*stat_awb_window_ystart = 0*/ + {0xC918, 0x04FF,},/*stat_awb_window_xend = 1279*/ + {0xC91A, 0x02CF,},/*stat_awb_window_yend = 719*/ + {0xC91C, 0x0000,},/*stat_ae_window_xstart = 0*/ + {0xC91E, 0x0000,},/*stat_ae_window_ystart = 0*/ + {0xC920, 0x00FF,},/*stat_ae_window_xend = 255*/ + {0xC922, 0x008F,},/*stat_ae_window_yend = 143*/ + + /*Sensor optimization*/ + {0x316A, 0x8270,}, + {0x316C, 0x8270,}, + {0x3ED0, 0x2305,}, + {0x3ED2, 0x77CF,}, + {0x316E, 0x8202,}, + {0x3180, 0x87FF,}, + {0x30D4, 0x6080,}, + {0xA802, 0x0008,},/*AE_TRACK_MODE*/ + {0x3E14, 0xFF39,}, + {0x0982, 0x0001,},/*ACCESS_CTL_STAT*/ + {0x098A, 0x5000,},/*PHYSICAL_ADDRESS_ACCESS*/ + {0xD000, 0x70CF,}, + {0xD002, 0xFFFF,}, + {0xD004, 0xC5D4,}, + {0xD006, 0x903A,}, + {0xD008, 0x2144,}, + {0xD00A, 0x0C00,}, + {0xD00C, 0x2186,}, + {0xD00E, 0x0FF3,}, + {0xD010, 0xB844,}, + {0xD012, 0xB948,}, + {0xD014, 0xE082,}, + {0xD016, 0x20CC,}, + {0xD018, 0x80E2,}, + {0xD01A, 0x21CC,}, + {0xD01C, 0x80A2,}, + {0xD01E, 0x21CC,}, + {0xD020, 0x80E2,}, + {0xD022, 0xF404,}, + {0xD024, 0xD801,}, + {0xD026, 0xF003,}, + {0xD028, 0xD800,}, + {0xD02A, 0x7EE0,}, + {0xD02C, 0xC0F1,}, + {0xD02E, 0x08BA,}, + {0xD030, 0x0600,}, + {0xD032, 0xC1A1,}, + {0xD034, 0x76CF,}, + {0xD036, 0xFFFF,}, + {0xD038, 0xC130,}, + {0xD03A, 0x6E04,}, + {0xD03C, 0xC040,}, + {0xD03E, 0x71CF,}, + {0xD040, 0xFFFF,}, + {0xD042, 0xC790,}, + {0xD044, 0x8103,}, + {0xD046, 0x77CF,}, + {0xD048, 0xFFFF,}, + {0xD04A, 0xC7C0,}, + {0xD04C, 0xE001,}, + {0xD04E, 0xA103,}, + {0xD050, 0xD800,}, + {0xD052, 0x0C6A,}, + {0xD054, 0x04E0,}, + {0xD056, 0xB89E,}, + {0xD058, 0x7508,}, + {0xD05A, 0x8E1C,}, + {0xD05C, 0x0809,}, + {0xD05E, 0x0191,}, + {0xD060, 0xD801,}, + {0xD062, 0xAE1D,}, + {0xD064, 0xE580,}, + {0xD066, 0x20CA,}, + {0xD068, 0x0022,}, + {0xD06A, 0x20CF,}, + {0xD06C, 0x0522,}, + {0xD06E, 0x0C5C,}, + {0xD070, 0x04E2,}, + {0xD072, 0x21CA,}, + {0xD074, 0x0062,}, + {0xD076, 0xE580,}, + {0xD078, 0xD901,}, + {0xD07A, 0x79C0,}, + {0xD07C, 0xD800,}, + {0xD07E, 0x0BE6,}, + {0xD080, 0x04E0,}, + {0xD082, 0xB89E,}, + {0xD084, 0x70CF,}, + {0xD086, 0xFFFF,}, + {0xD088, 0xC8D4,}, + {0xD08A, 0x9002,}, + {0xD08C, 0x0857,}, + {0xD08E, 0x025E,}, + {0xD090, 0xFFDC,}, + {0xD092, 0xE080,}, + {0xD094, 0x25CC,}, + {0xD096, 0x9022,}, + {0xD098, 0xF225,}, + {0xD09A, 0x1700,}, + {0xD09C, 0x108A,}, + {0xD09E, 0x73CF,}, + {0xD0A0, 0xFF00,}, + {0xD0A2, 0x3174,}, + {0xD0A4, 0x9307,}, + {0xD0A6, 0x2A04,}, + {0xD0A8, 0x103E,}, + {0xD0AA, 0x9328,}, + {0xD0AC, 0x2942,}, + {0xD0AE, 0x7140,}, + {0xD0B0, 0x2A04,}, + {0xD0B2, 0x107E,}, + {0xD0B4, 0x9349,}, + {0xD0B6, 0x2942,}, + {0xD0B8, 0x7141,}, + {0xD0BA, 0x2A04,}, + {0xD0BC, 0x10BE,}, + {0xD0BE, 0x934A,}, + {0xD0C0, 0x2942,}, + {0xD0C2, 0x714B,}, + {0xD0C4, 0x2A04,}, + {0xD0C6, 0x10BE,}, + {0xD0C8, 0x130C,}, + {0xD0CA, 0x010A,}, + {0xD0CC, 0x2942,}, + {0xD0CE, 0x7142,}, + {0xD0D0, 0x2250,}, + {0xD0D2, 0x13CA,}, + {0xD0D4, 0x1B0C,}, + {0xD0D6, 0x0284,}, + {0xD0D8, 0xB307,}, + {0xD0DA, 0xB328,}, + {0xD0DC, 0x1B12,}, + {0xD0DE, 0x02C4,}, + {0xD0E0, 0xB34A,}, + {0xD0E2, 0xED88,}, + {0xD0E4, 0x71CF,}, + {0xD0E6, 0xFF00,}, + {0xD0E8, 0x3174,}, + {0xD0EA, 0x9106,}, + {0xD0EC, 0xB88F,}, + {0xD0EE, 0xB106,}, + {0xD0F0, 0x210A,}, + {0xD0F2, 0x8340,}, + {0xD0F4, 0xC000,}, + {0xD0F6, 0x21CA,}, + {0xD0F8, 0x0062,}, + {0xD0FA, 0x20F0,}, + {0xD0FC, 0x0040,}, + {0xD0FE, 0x0B02,}, + {0xD100, 0x0320,}, + {0xD102, 0xD901,}, + {0xD104, 0x07F1,}, + {0xD106, 0x05E0,}, + {0xD108, 0xC0A1,}, + {0xD10A, 0x78E0,}, + {0xD10C, 0xC0F1,}, + {0xD10E, 0x71CF,}, + {0xD110, 0xFFFF,}, + {0xD112, 0xC7C0,}, + {0xD114, 0xD840,}, + {0xD116, 0xA900,}, + {0xD118, 0x71CF,}, + {0xD11A, 0xFFFF,}, + {0xD11C, 0xD02C,}, + {0xD11E, 0xD81E,}, + {0xD120, 0x0A5A,}, + {0xD122, 0x04E0,}, + {0xD124, 0xDA00,}, + {0xD126, 0xD800,}, + {0xD128, 0xC0D1,}, + {0xD12A, 0x7EE0,}, + {0x098E, 0x0000,}, + + {0x0982, 0x0001,}, + {0x098A, 0x5C10,}, + {0xDC10, 0xC0F1,}, + {0xDC12, 0x0CDA,}, + {0xDC14, 0x0580,}, + {0xDC16, 0x76CF,}, + {0xDC18, 0xFF00,}, + {0xDC1A, 0x2184,}, + {0xDC1C, 0x9624,}, + {0xDC1E, 0x218C,}, + {0xDC20, 0x8FC3,}, + {0xDC22, 0x75CF,}, + {0xDC24, 0xFFFF,}, + {0xDC26, 0xE058,}, + {0xDC28, 0xF686,}, + {0xDC2A, 0x1550,}, + {0xDC2C, 0x1080,}, + {0xDC2E, 0xE001,}, + {0xDC30, 0x1D50,}, + {0xDC32, 0x1002,}, + {0xDC34, 0x1552,}, + {0xDC36, 0x1100,}, + {0xDC38, 0x6038,}, + {0xDC3A, 0x1D52,}, + {0xDC3C, 0x1004,}, + {0xDC3E, 0x1540,}, + {0xDC40, 0x1080,}, + {0xDC42, 0x081B,}, + {0xDC44, 0x00D1,}, + {0xDC46, 0x8512,}, + {0xDC48, 0x1000,}, + {0xDC4A, 0x00C0,}, + {0xDC4C, 0x7822,}, + {0xDC4E, 0x2089,}, + {0xDC50, 0x0FC1,}, + {0xDC52, 0x2008,}, + {0xDC54, 0x0F81,}, + {0xDC56, 0xFFFF,}, + {0xDC58, 0xFF80,}, + {0xDC5A, 0x8512,}, + {0xDC5C, 0x1801,}, + {0xDC5E, 0x0052,}, + {0xDC60, 0xA512,}, + {0xDC62, 0x1544,}, + {0xDC64, 0x1080,}, + {0xDC66, 0xB861,}, + {0xDC68, 0x262F,}, + {0xDC6A, 0xF007,}, + {0xDC6C, 0x1D44,}, + {0xDC6E, 0x1002,}, + {0xDC70, 0x20CA,}, + {0xDC72, 0x0021,}, + {0xDC74, 0x20CF,}, + {0xDC76, 0x04E1,}, + {0xDC78, 0x0850,}, + {0xDC7A, 0x04A1,}, + {0xDC7C, 0x21CA,}, + {0xDC7E, 0x0021,}, + {0xDC80, 0x1542,}, + {0xDC82, 0x1140,}, + {0xDC84, 0x8D2C,}, + {0xDC86, 0x6038,}, + {0xDC88, 0x1D42,}, + {0xDC8A, 0x1004,}, + {0xDC8C, 0x1542,}, + {0xDC8E, 0x1140,}, + {0xDC90, 0xB601,}, + {0xDC92, 0x046D,}, + {0xDC94, 0x0580,}, + {0xDC96, 0x78E0,}, + {0xDC98, 0xD800,}, + {0xDC9A, 0xB893,}, + {0xDC9C, 0x002D,}, + {0xDC9E, 0x04A0,}, + {0xDCA0, 0xD900,}, + {0xDCA2, 0x78E0,}, + {0xDCA4, 0x72CF,}, + {0xDCA6, 0xFFFF,}, + {0xDCA8, 0xE058,}, + {0xDCAA, 0x2240,}, + {0xDCAC, 0x0340,}, + {0xDCAE, 0xA212,}, + {0xDCB0, 0x208A,}, + {0xDCB2, 0x0FFF,}, + {0xDCB4, 0x1A42,}, + {0xDCB6, 0x0004,}, + {0xDCB8, 0xD830,}, + {0xDCBA, 0x1A44,}, + {0xDCBC, 0x0002,}, + {0xDCBE, 0xD800,}, + {0xDCC0, 0x1A50,}, + {0xDCC2, 0x0002,}, + {0xDCC4, 0x1A52,}, + {0xDCC6, 0x0004,}, + {0xDCC8, 0x1242,}, + {0xDCCA, 0x0140,}, + {0xDCCC, 0x8A2C,}, + {0xDCCE, 0x6038,}, + {0xDCD0, 0x1A42,}, + {0xDCD2, 0x0004,}, + {0xDCD4, 0x1242,}, + {0xDCD6, 0x0141,}, + {0xDCD8, 0x70CF,}, + {0xDCDA, 0xFF00,}, + {0xDCDC, 0x2184,}, + {0xDCDE, 0xB021,}, + {0xDCE0, 0xD800,}, + {0xDCE2, 0xB893,}, + {0xDCE4, 0x07E5,}, + {0xDCE6, 0x0460,}, + {0xDCE8, 0xD901,}, + {0xDCEA, 0x78E0,}, + {0xDCEC, 0xC0F1,}, + {0xDCEE, 0x0BFA,}, + {0xDCF0, 0x05A0,}, + {0xDCF2, 0x216F,}, + {0xDCF4, 0x0043,}, + {0xDCF6, 0xC1A4,}, + {0xDCF8, 0x220A,}, + {0xDCFA, 0x1F80,}, + {0xDCFC, 0xFFFF,}, + {0xDCFE, 0xE058,}, + {0xDD00, 0x2240,}, + {0xDD02, 0x134F,}, + {0xDD04, 0x1A48,}, + {0xDD06, 0x13C0,}, + {0xDD08, 0x1248,}, + {0xDD0A, 0x1002,}, + {0xDD0C, 0x70CF,}, + {0xDD0E, 0x7FFF,}, + {0xDD10, 0xFFFF,}, + {0xDD12, 0xE230,}, + {0xDD14, 0xC240,}, + {0xDD16, 0xDA00,}, + {0xDD18, 0xF00C,}, + {0xDD1A, 0x1248,}, + {0xDD1C, 0x1003,}, + {0xDD1E, 0x1301,}, + {0xDD20, 0x04CB,}, + {0xDD22, 0x7261,}, + {0xDD24, 0x2108,}, + {0xDD26, 0x0081,}, + {0xDD28, 0x2009,}, + {0xDD2A, 0x0080,}, + {0xDD2C, 0x1A48,}, + {0xDD2E, 0x10C0,}, + {0xDD30, 0x1248,}, + {0xDD32, 0x100B,}, + {0xDD34, 0xC300,}, + {0xDD36, 0x0BE7,}, + {0xDD38, 0x90C4,}, + {0xDD3A, 0x2102,}, + {0xDD3C, 0x0003,}, + {0xDD3E, 0x238C,}, + {0xDD40, 0x8FC3,}, + {0xDD42, 0xF6C7,}, + {0xDD44, 0xDAFF,}, + {0xDD46, 0x1A05,}, + {0xDD48, 0x1082,}, + {0xDD4A, 0xC241,}, + {0xDD4C, 0xF005,}, + {0xDD4E, 0x7A6F,}, + {0xDD50, 0xC241,}, + {0xDD52, 0x1A05,}, + {0xDD54, 0x10C2,}, + {0xDD56, 0x2000,}, + {0xDD58, 0x8040,}, + {0xDD5A, 0xDA00,}, + {0xDD5C, 0x20C0,}, + {0xDD5E, 0x0064,}, + {0xDD60, 0x781C,}, + {0xDD62, 0xC042,}, + {0xDD64, 0x1C0E,}, + {0xDD66, 0x3082,}, + {0xDD68, 0x1A48,}, + {0xDD6A, 0x13C0,}, + {0xDD6C, 0x7548,}, + {0xDD6E, 0x7348,}, + {0xDD70, 0x7148,}, + {0xDD72, 0x7648,}, + {0xDD74, 0xF002,}, + {0xDD76, 0x7608,}, + {0xDD78, 0x1248,}, + {0xDD7A, 0x1000,}, + {0xDD7C, 0x1400,}, + {0xDD7E, 0x300B,}, + {0xDD80, 0x084D,}, + {0xDD82, 0x02C5,}, + {0xDD84, 0x1248,}, + {0xDD86, 0x1000,}, + {0xDD88, 0xE101,}, + {0xDD8A, 0x1001,}, + {0xDD8C, 0x04CB,}, + {0xDD8E, 0x1A48,}, + {0xDD90, 0x1000,}, + {0xDD92, 0x7361,}, + {0xDD94, 0x1408,}, + {0xDD96, 0x300B,}, + {0xDD98, 0x2302,}, + {0xDD9A, 0x02C0,}, + {0xDD9C, 0x780D,}, + {0xDD9E, 0x2607,}, + {0xDDA0, 0x903E,}, + {0xDDA2, 0x07D6,}, + {0xDDA4, 0xFFE3,}, + {0xDDA6, 0x792F,}, + {0xDDA8, 0x09CF,}, + {0xDDAA, 0x8152,}, + {0xDDAC, 0x1248,}, + {0xDDAE, 0x100E,}, + {0xDDB0, 0x2400,}, + {0xDDB2, 0x334B,}, + {0xDDB4, 0xE501,}, + {0xDDB6, 0x7EE2,}, + {0xDDB8, 0x0DBF,}, + {0xDDBA, 0x90F2,}, + {0xDDBC, 0x1B0C,}, + {0xDDBE, 0x1382,}, + {0xDDC0, 0xC123,}, + {0xDDC2, 0x140E,}, + {0xDDC4, 0x3080,}, + {0xDDC6, 0x7822,}, + {0xDDC8, 0x1A07,}, + {0xDDCA, 0x1002,}, + {0xDDCC, 0x124C,}, + {0xDDCE, 0x1000,}, + {0xDDD0, 0x120B,}, + {0xDDD2, 0x1081,}, + {0xDDD4, 0x1207,}, + {0xDDD6, 0x1083,}, + {0xDDD8, 0x2142,}, + {0xDDDA, 0x004B,}, + {0xDDDC, 0x781B,}, + {0xDDDE, 0x0B21,}, + {0xDDE0, 0x02E2,}, + {0xDDE2, 0x1A4C,}, + {0xDDE4, 0x1000,}, + {0xDDE6, 0xE101,}, + {0xDDE8, 0x0915,}, + {0xDDEA, 0x00C2,}, + {0xDDEC, 0xC101,}, + {0xDDEE, 0x1204,}, + {0xDDF0, 0x1083,}, + {0xDDF2, 0x090D,}, + {0xDDF4, 0x00C2,}, + {0xDDF6, 0xE001,}, + {0xDDF8, 0x1A4C,}, + {0xDDFA, 0x1000,}, + {0xDDFC, 0x1A06,}, + {0xDDFE, 0x1002,}, + {0xDE00, 0x234A,}, + {0xDE02, 0x1000,}, + {0xDE04, 0x7169,}, + {0xDE06, 0xF008,}, + {0xDE08, 0x2053,}, + {0xDE0A, 0x0003,}, + {0xDE0C, 0x6179,}, + {0xDE0E, 0x781C,}, + {0xDE10, 0x2340,}, + {0xDE12, 0x104B,}, + {0xDE14, 0x1203,}, + {0xDE16, 0x1083,}, + {0xDE18, 0x0BF1,}, + {0xDE1A, 0x90C2,}, + {0xDE1C, 0x1202,}, + {0xDE1E, 0x1080,}, + {0xDE20, 0x091D,}, + {0xDE22, 0x0004,}, + {0xDE24, 0x70CF,}, + {0xDE26, 0xFFFF,}, + {0xDE28, 0xC644,}, + {0xDE2A, 0x881B,}, + {0xDE2C, 0xE0B2,}, + {0xDE2E, 0xD83C,}, + {0xDE30, 0x20CA,}, + {0xDE32, 0x0CA2,}, + {0xDE34, 0x1A01,}, + {0xDE36, 0x1002,}, + {0xDE38, 0x1A4C,}, + {0xDE3A, 0x1080,}, + {0xDE3C, 0x02B9,}, + {0xDE3E, 0x05A0,}, + {0xDE40, 0xC0A4,}, + {0xDE42, 0x78E0,}, + {0xDE44, 0xC0F1,}, + {0xDE46, 0xFF95,}, + {0xDE48, 0xD800,}, + {0xDE4A, 0x71CF,}, + {0xDE4C, 0xFF00,}, + {0xDE4E, 0x1FE0,}, + {0xDE50, 0x19D0,}, + {0xDE52, 0x001C,}, + {0xDE54, 0x19D1,}, + {0xDE56, 0x001C,}, + {0xDE58, 0x70CF,}, + {0xDE5A, 0xFFFF,}, + {0xDE5C, 0xE058,}, + {0xDE5E, 0x901F,}, + {0xDE60, 0xB861,}, + {0xDE62, 0x19D2,}, + {0xDE64, 0x001C,}, + {0xDE66, 0xC0D1,}, + {0xDE68, 0x7EE0,}, + {0xDE6A, 0x78E0,}, + {0xDE6C, 0xC0F1,}, + {0xDE6E, 0x0A7A,}, + {0xDE70, 0x0580,}, + {0xDE72, 0x70CF,}, + {0xDE74, 0xFFFF,}, + {0xDE76, 0xC5D4,}, + {0xDE78, 0x9041,}, + {0xDE7A, 0x9023,}, + {0xDE7C, 0x75CF,}, + {0xDE7E, 0xFFFF,}, + {0xDE80, 0xE058,}, + {0xDE82, 0x7942,}, + {0xDE84, 0xB967,}, + {0xDE86, 0x7F30,}, + {0xDE88, 0xB53F,}, + {0xDE8A, 0x71CF,}, + {0xDE8C, 0xFFFF,}, + {0xDE8E, 0xC84C,}, + {0xDE90, 0x91D3,}, + {0xDE92, 0x108B,}, + {0xDE94, 0x0081,}, + {0xDE96, 0x2615,}, + {0xDE98, 0x1380,}, + {0xDE9A, 0x090F,}, + {0xDE9C, 0x0C91,}, + {0xDE9E, 0x0A8E,}, + {0xDEA0, 0x05A0,}, + {0xDEA2, 0xD906,}, + {0xDEA4, 0x7E10,}, + {0xDEA6, 0x2615,}, + {0xDEA8, 0x1380,}, + {0xDEAA, 0x0A82,}, + {0xDEAC, 0x05A0,}, + {0xDEAE, 0xD960,}, + {0xDEB0, 0x790F,}, + {0xDEB2, 0x090D,}, + {0xDEB4, 0x0133,}, + {0xDEB6, 0xAD0C,}, + {0xDEB8, 0xD904,}, + {0xDEBA, 0xAD2C,}, + {0xDEBC, 0x79EC,}, + {0xDEBE, 0x2941,}, + {0xDEC0, 0x7402,}, + {0xDEC2, 0x71CF,}, + {0xDEC4, 0xFF00,}, + {0xDEC6, 0x2184,}, + {0xDEC8, 0xB142,}, + {0xDECA, 0x1906,}, + {0xDECC, 0x0E44,}, + {0xDECE, 0xFFDE,}, + {0xDED0, 0x70C9,}, + {0xDED2, 0x0A5A,}, + {0xDED4, 0x05A0,}, + {0xDED6, 0x8D2C,}, + {0xDED8, 0xAD0B,}, + {0xDEDA, 0xD800,}, + {0xDEDC, 0xAD01,}, + {0xDEDE, 0x0219,}, + {0xDEE0, 0x05A0,}, + {0xDEE2, 0xA513,}, + {0xDEE4, 0xC0F1,}, + {0xDEE6, 0x71CF,}, + {0xDEE8, 0xFFFF,}, + {0xDEEA, 0xC644,}, + {0xDEEC, 0xA91B,}, + {0xDEEE, 0xD902,}, + {0xDEF0, 0x70CF,}, + {0xDEF2, 0xFFFF,}, + {0xDEF4, 0xC84C,}, + {0xDEF6, 0x093E,}, + {0xDEF8, 0x03A0,}, + {0xDEFA, 0xA826,}, + {0xDEFC, 0xFFDC,}, + {0xDEFE, 0xF1B5,}, + {0xDF00, 0xC0F1,}, + {0xDF02, 0x09EA,}, + {0xDF04, 0x0580,}, + {0xDF06, 0x75CF,}, + {0xDF08, 0xFFFF,}, + {0xDF0A, 0xE058,}, + {0xDF0C, 0x1540,}, + {0xDF0E, 0x1080,}, + {0xDF10, 0x08A7,}, + {0xDF12, 0x0010,}, + {0xDF14, 0x8D00,}, + {0xDF16, 0x0813,}, + {0xDF18, 0x009E,}, + {0xDF1A, 0x1540,}, + {0xDF1C, 0x1081,}, + {0xDF1E, 0xE181,}, + {0xDF20, 0x20CA,}, + {0xDF22, 0x00A1,}, + {0xDF24, 0xF24B,}, + {0xDF26, 0x1540,}, + {0xDF28, 0x1081,}, + {0xDF2A, 0x090F,}, + {0xDF2C, 0x0050,}, + {0xDF2E, 0x1540,}, + {0xDF30, 0x1081,}, + {0xDF32, 0x0927,}, + {0xDF34, 0x0091,}, + {0xDF36, 0x1550,}, + {0xDF38, 0x1081,}, + {0xDF3A, 0xDE00,}, + {0xDF3C, 0xAD2A,}, + {0xDF3E, 0x1D50,}, + {0xDF40, 0x1382,}, + {0xDF42, 0x1552,}, + {0xDF44, 0x1101,}, + {0xDF46, 0x1D52,}, + {0xDF48, 0x1384,}, + {0xDF4A, 0xB524,}, + {0xDF4C, 0x082D,}, + {0xDF4E, 0x015F,}, + {0xDF50, 0xFF55,}, + {0xDF52, 0xD803,}, + {0xDF54, 0xF033,}, + {0xDF56, 0x1540,}, + {0xDF58, 0x1081,}, + {0xDF5A, 0x0967,}, + {0xDF5C, 0x00D1,}, + {0xDF5E, 0x1550,}, + {0xDF60, 0x1081,}, + {0xDF62, 0xDE00,}, + {0xDF64, 0xAD2A,}, + {0xDF66, 0x1D50,}, + {0xDF68, 0x1382,}, + {0xDF6A, 0x1552,}, + {0xDF6C, 0x1101,}, + {0xDF6E, 0x1D52,}, + {0xDF70, 0x1384,}, + {0xDF72, 0xB524,}, + {0xDF74, 0x0811,}, + {0xDF76, 0x019E,}, + {0xDF78, 0xB8A0,}, + {0xDF7A, 0xAD00,}, + {0xDF7C, 0xFF47,}, + {0xDF7E, 0x1D40,}, + {0xDF80, 0x1382,}, + {0xDF82, 0xF01F,}, + {0xDF84, 0xFF5A,}, + {0xDF86, 0x8D01,}, + {0xDF88, 0x8D40,}, + {0xDF8A, 0xE812,}, + {0xDF8C, 0x71CF,}, + {0xDF8E, 0xFFFF,}, + {0xDF90, 0xC644,}, + {0xDF92, 0x893B,}, + {0xDF94, 0x7030,}, + {0xDF96, 0x22D1,}, + {0xDF98, 0x8062,}, + {0xDF9A, 0xF20A,}, + {0xDF9C, 0x0A0F,}, + {0xDF9E, 0x009E,}, + {0xDFA0, 0x71CF,}, + {0xDFA2, 0xFFFF,}, + {0xDFA4, 0xC84C,}, + {0xDFA6, 0x893B,}, + {0xDFA8, 0xE902,}, + {0xDFAA, 0xFFCF,}, + {0xDFAC, 0x8D00,}, + {0xDFAE, 0xB8E7,}, + {0xDFB0, 0x26CA,}, + {0xDFB2, 0x1022,}, + {0xDFB4, 0xF5E2,}, + {0xDFB6, 0xFF3C,}, + {0xDFB8, 0xD801,}, + {0xDFBA, 0x1D40,}, + {0xDFBC, 0x1002,}, + {0xDFBE, 0x0141,}, + {0xDFC0, 0x0580,}, + {0xDFC2, 0x78E0,}, + {0xDFC4, 0xC0F1,}, + {0xDFC6, 0xC5E1,}, + {0xDFC8, 0xFF34,}, + {0xDFCA, 0xDD00,}, + {0xDFCC, 0x70CF,}, + {0xDFCE, 0xFFFF,}, + {0xDFD0, 0xE090,}, + {0xDFD2, 0xA8A8,}, + {0xDFD4, 0xD800,}, + {0xDFD6, 0xB893,}, + {0xDFD8, 0x0C8A,}, + {0xDFDA, 0x0460,}, + {0xDFDC, 0xD901,}, + {0xDFDE, 0x71CF,}, + {0xDFE0, 0xFFFF,}, + {0xDFE2, 0xDC10,}, + {0xDFE4, 0xD813,}, + {0xDFE6, 0x0B96,}, + {0xDFE8, 0x0460,}, + {0xDFEA, 0x72A9,}, + {0xDFEC, 0x0119,}, + {0xDFEE, 0x0580,}, + {0xDFF0, 0xC0F1,}, + {0xDFF2, 0x71CF,}, + {0xDFF4, 0x0000,}, + {0xDFF6, 0x5BAE,}, + {0xDFF8, 0x7940,}, + {0xDFFA, 0xFF9D,}, + {0xDFFC, 0xF135,}, + {0xDFFE, 0x78E0,}, + {0xE000, 0xC0F1,}, + {0xE002, 0x70CF,}, + {0xE004, 0x0000,}, + {0xE006, 0x5CBA,}, + {0xE008, 0x7840,}, + {0xE00A, 0x70CF,}, + {0xE00C, 0xFFFF,}, + {0xE00E, 0xE058,}, + {0xE010, 0x8800,}, + {0xE012, 0x0815,}, + {0xE014, 0x001E,}, + {0xE016, 0x70CF,}, + {0xE018, 0xFFFF,}, + {0xE01A, 0xC84C,}, + {0xE01C, 0x881A,}, + {0xE01E, 0xE080,}, + {0xE020, 0x0EE0,}, + {0xE022, 0xFFC1,}, + {0xE024, 0xF121,}, + {0xE026, 0x78E0,}, + {0xE028, 0xC0F1,}, + {0xE02A, 0xD900,}, + {0xE02C, 0xF009,}, + {0xE02E, 0x70CF,}, + {0xE030, 0xFFFF,}, + {0xE032, 0xE0AC,}, + {0xE034, 0x7835,}, + {0xE036, 0x8041,}, + {0xE038, 0x8000,}, + {0xE03A, 0xE102,}, + {0xE03C, 0xA040,}, + {0xE03E, 0x09F3,}, + {0xE040, 0x8114,}, + {0xE042, 0x71CF,}, + {0xE044, 0xFFFF,}, + {0xE046, 0xE058,}, + {0xE048, 0x70CF,}, + {0xE04A, 0xFFFF,}, + {0xE04C, 0xC594,}, + {0xE04E, 0xB030,}, + {0xE050, 0xFFDD,}, + {0xE052, 0xD800,}, + {0xE054, 0xF109,}, + {0xE056, 0x0000,}, + {0xE058, 0x0300,}, + {0xE05A, 0x0204,}, + {0xE05C, 0x0700,}, + {0xE05E, 0x0000,}, + {0xE060, 0x0000,}, + {0xE062, 0x0000,}, + {0xE064, 0x0000,}, + {0xE066, 0x0000,}, + {0xE068, 0x0000,}, + {0xE06A, 0x0000,}, + {0xE06C, 0x0000,}, + {0xE06E, 0x0000,}, + {0xE070, 0x0000,}, + {0xE072, 0x0000,}, + {0xE074, 0x0000,}, + {0xE076, 0x0000,}, + {0xE078, 0x0000,}, + {0xE07A, 0x0000,}, + {0xE07C, 0x0000,}, + {0xE07E, 0x0000,}, + {0xE080, 0x0000,}, + {0xE082, 0x0000,}, + {0xE084, 0x0000,}, + {0xE086, 0x0000,}, + {0xE088, 0x0000,}, + {0xE08A, 0x0000,}, + {0xE08C, 0x0000,}, + {0xE08E, 0x0000,}, + {0xE090, 0x0000,}, + {0xE092, 0x0000,}, + {0xE094, 0x0000,}, + {0xE096, 0x0000,}, + {0xE098, 0x0000,}, + {0xE09A, 0x0000,}, + {0xE09C, 0x0000,}, + {0xE09E, 0x0000,}, + {0xE0A0, 0x0000,}, + {0xE0A2, 0x0000,}, + {0xE0A4, 0x0000,}, + {0xE0A6, 0x0000,}, + {0xE0A8, 0x0000,}, + {0xE0AA, 0x0000,}, + {0xE0AC, 0xFFFF,}, + {0xE0AE, 0xCB68,}, + {0xE0B0, 0xFFFF,}, + {0xE0B2, 0xDFF0,}, + {0xE0B4, 0xFFFF,}, + {0xE0B6, 0xCB6C,}, + {0xE0B8, 0xFFFF,}, + {0xE0BA, 0xE000,}, + {0x098E, 0x0000,}, + + /*MIPI setting for SOC1040*/ + {0x3C5A, 0x0009,}, + {0x3C44, 0x0080,},/*MIPI_CUSTOM_SHORT_PKT*/ + + /*[Tuning_settings]*/ + + /*[CCM]*/ + {0xC892, 0x0267,},/*CAM_AWB_CCM_L_0*/ + {0xC894, 0xFF1A,},/*CAM_AWB_CCM_L_1*/ + {0xC896, 0xFFB3,},/*CAM_AWB_CCM_L_2*/ + {0xC898, 0xFF80,},/*CAM_AWB_CCM_L_3*/ + {0xC89A, 0x0166,},/*CAM_AWB_CCM_L_4*/ + {0xC89C, 0x0003,},/*CAM_AWB_CCM_L_5*/ + {0xC89E, 0xFF9A,},/*CAM_AWB_CCM_L_6*/ + {0xC8A0, 0xFEB4,},/*CAM_AWB_CCM_L_7*/ + {0xC8A2, 0x024D,},/*CAM_AWB_CCM_L_8*/ + {0xC8A4, 0x01BF,},/*CAM_AWB_CCM_M_0*/ + {0xC8A6, 0xFF01,},/*CAM_AWB_CCM_M_1*/ + {0xC8A8, 0xFFF3,},/*CAM_AWB_CCM_M_2*/ + {0xC8AA, 0xFF75,},/*CAM_AWB_CCM_M_3*/ + {0xC8AC, 0x0198,},/*CAM_AWB_CCM_M_4*/ + {0xC8AE, 0xFFFD,},/*CAM_AWB_CCM_M_5*/ + {0xC8B0, 0xFF9A,},/*CAM_AWB_CCM_M_6*/ + {0xC8B2, 0xFEE7,},/*CAM_AWB_CCM_M_7*/ + {0xC8B4, 0x02A8,},/*CAM_AWB_CCM_M_8*/ + {0xC8B6, 0x01D9,},/*CAM_AWB_CCM_R_0*/ + {0xC8B8, 0xFF26,},/*CAM_AWB_CCM_R_1*/ + {0xC8BA, 0xFFF3,},/*CAM_AWB_CCM_R_2*/ + {0xC8BC, 0xFFB3,},/*CAM_AWB_CCM_R_3*/ + {0xC8BE, 0x0132,},/*CAM_AWB_CCM_R_4*/ + {0xC8C0, 0xFFE8,},/*CAM_AWB_CCM_R_5*/ + {0xC8C2, 0xFFDA,},/*CAM_AWB_CCM_R_6*/ + {0xC8C4, 0xFECD,},/*CAM_AWB_CCM_R_7*/ + {0xC8C6, 0x02C2,},/*CAM_AWB_CCM_R_8*/ + {0xC8C8, 0x0075,},/*CAM_AWB_CCM_L_RG_GAIN*/ + {0xC8CA, 0x011C,},/*CAM_AWB_CCM_L_BG_GAIN*/ + {0xC8CC, 0x009A,},/*CAM_AWB_CCM_M_RG_GAIN*/ + {0xC8CE, 0x0105,},/*CAM_AWB_CCM_M_BG_GAIN*/ + {0xC8D0, 0x00A4,},/*CAM_AWB_CCM_R_RG_GAIN*/ + {0xC8D2, 0x00AC,},/*CAM_AWB_CCM_R_BG_GAIN*/ + {0xC8D4, 0x0A8C,},/*CAM_AWB_CCM_L_CTEMP*/ + {0xC8D6, 0x0F0A,},/*CAM_AWB_CCM_M_CTEMP*/ + {0xC8D8, 0x1964,},/*CAM_AWB_CCM_R_CTEMP*/ + + /*[AWB]*/ + {0xC914, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_XSTART*/ + {0xC916, 0x0000,},/*CAM_STAT_AWB_CLIP_WINDOW_YSTART*/ + {0xC918, 0x04FF,},/*CAM_STAT_AWB_CLIP_WINDOW_XEND*/ + {0xC91A, 0x02CF,},/*CAM_STAT_AWB_CLIP_WINDOW_YEND*/ + {0xC904, 0x0033,},/*CAM_AWB_AWB_XSHIFT_PRE_ADJ*/ + {0xC906, 0x0040,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ + {0xC8F2, 0x03, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_XSCALE*/ + {0xC8F3, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_AWB_YSCALE*/ + {0xC906, 0x003C,},/*CAM_AWB_AWB_YSHIFT_PRE_ADJ*/ + {0xC8F4, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_0*/ + {0xC8F6, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_1*/ + {0xC8F8, 0x0000,},/*CAM_AWB_AWB_WEIGHTS_2*/ + {0xC8FA, 0xE724,},/*CAM_AWB_AWB_WEIGHTS_3*/ + {0xC8FC, 0x1583,},/*CAM_AWB_AWB_WEIGHTS_4*/ + {0xC8FE, 0x2045,},/*CAM_AWB_AWB_WEIGHTS_5*/ + {0xC900, 0x03FF,},/*CAM_AWB_AWB_WEIGHTS_6*/ + {0xC902, 0x007C,},/*CAM_AWB_AWB_WEIGHTS_7*/ + {0xC90C, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_L*/ + {0xC90D, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_L*/ + {0xC90E, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_L*/ + {0xC90F, 0x88, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_R_R*/ + {0xC910, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_G_R*/ + {0xC911, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AWB_K_B_R*/ + + /*[Step7-CPIPE_Preference]*/ + {0xC926, 0x0020,},/*CAM_LL_START_BRIGHTNESS*/ + {0xC928, 0x009A,},/*CAM_LL_STOP_BRIGHTNESS*/ + {0xC946, 0x0070,},/*CAM_LL_START_GAIN_METRIC*/ + {0xC948, 0x00F3,},/*CAM_LL_STOP_GAIN_METRIC*/ + {0xC952, 0x0020,},/*CAM_LL_START_TARGET_LUMA_BM*/ + {0xC954, 0x009A,},/*CAM_LL_STOP_TARGET_LUMA_BM*/ + {0xC92A, 0x80, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_SATURATION*/ + {0xC92B, 0x4B, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_SATURATION*/ + {0xC92C, 0x00, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DESATURATION*/ + {0xC92D, 0xFF, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_END_DESATURATION*/ + {0xC92E, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_DEMOSAIC*/ + {0xC92F, 0x02, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_GAIN*/ + {0xC930, 0x06, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_AP_THRESH*/ + {0xC931, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_DEMOSAIC*/ + {0xC932, 0x01, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_GAIN*/ + {0xC933, 0x0C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_AP_THRESH*/ + {0xC934, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_RED*/ + {0xC935, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_GREEN*/ + {0xC936, 0x3C, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_BLUE*/ + {0xC937, 0x0F, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_NR_THRESH*/ + {0xC938, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_RED*/ + {0xC939, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_GREEN*/ + {0xC93A, 0x64, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_BLUE*/ + {0xC93B, 0x32, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_NR_THRESH*/ + {0xC93C, 0x0020,},/*CAM_LL_START_CONTRAST_BM*/ + {0xC93E, 0x009A,},/*CAM_LL_STOP_CONTRAST_BM*/ + {0xC940, 0x00DC,},/*CAM_LL_GAMMA*/ + /*CAM_LL_START_CONTRAST_GRADIENT*/ + {0xC942, 0x38, MSM_CAMERA_I2C_BYTE_DATA}, + /*CAM_LL_STOP_CONTRAST_GRADIENT*/ + {0xC943, 0x30, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC944, 0x50, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_START_CONTRAST_LUMA*/ + {0xC945, 0x19, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_STOP_CONTRAST_LUMA*/ + {0xC94A, 0x0230,},/*CAM_LL_START_FADE_TO_BLACK_LUMA*/ + {0xC94C, 0x0010,},/*CAM_LL_STOP_FADE_TO_BLACK_LUMA*/ + {0xC94E, 0x01CD,},/*CAM_LL_CLUSTER_DC_TH_BM*/ + {0xC950, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_CLUSTER_DC_GATE*/ + {0xC951, 0x40, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_LL_SUMMING_SENSITIVITY*/ + /*CAM_AET_TARGET_AVERAGE_LUMA_DARK*/ + {0xC87B, 0x1B, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC878, 0x0E, MSM_CAMERA_I2C_BYTE_DATA},/*CAM_AET_AEMODE*/ + {0xC890, 0x0080,},/*CAM_AET_TARGET_GAIN*/ + {0xC886, 0x0100,},/*CAM_AET_AE_MAX_VIRT_AGAIN*/ + {0xC87C, 0x005A,},/*CAM_AET_BLACK_CLIPPING_TARGET*/ + {0xB42A, 0x05, MSM_CAMERA_I2C_BYTE_DATA},/*CCM_DELTA_GAIN*/ + /*AE_TRACK_AE_TRACKING_DAMPENING*/ + {0xA80A, 0x20, MSM_CAMERA_I2C_BYTE_DATA}, + {0x3C44, 0x0080,}, + {0x3C40, 0x0004, MSM_CAMERA_I2C_UNSET_WORD_MASK}, + {0xA802, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, + {0xC908, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC879, 0x01, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC909, 0x01, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, + {0xA80A, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xA80B, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xAC16, 0x18, MSM_CAMERA_I2C_BYTE_DATA}, + {0xC878, 0x08, MSM_CAMERA_I2C_SET_BYTE_MASK}, + {0xBC02, 0x08, MSM_CAMERA_I2C_UNSET_BYTE_MASK}, +}; + +static struct v4l2_subdev_info mt9m114_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf mt9m114_config_change_settings[] = { + {0xdc00, 0x28, MSM_CAMERA_I2C_BYTE_DATA, MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {MT9M114_COMMAND_REGISTER, (MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE), MSM_CAMERA_I2C_WORD_DATA, + MSM_CAMERA_I2C_CMD_WRITE}, + {MT9M114_COMMAND_REGISTER, MT9M114_COMMAND_REGISTER_SET_STATE, + MSM_CAMERA_I2C_UNSET_WORD_MASK, MSM_CAMERA_I2C_CMD_POLL}, + {0xDC01, 0x31, MSM_CAMERA_I2C_BYTE_DATA}, +}; + +static const struct i2c_device_id mt9m114_i2c_id[] = { + {MT9M114_SENSOR_NAME, (kernel_ulong_t)&mt9m114_s_ctrl}, + { } +}; + +static int32_t msm_mt9m114_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &mt9m114_s_ctrl); +} + +static struct i2c_driver mt9m114_i2c_driver = { + .id_table = mt9m114_i2c_id, + .probe = msm_mt9m114_i2c_probe, + .driver = { + .name = MT9M114_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client mt9m114_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id mt9m114_dt_match[] = { + {.compatible = "qcom,mt9m114", .data = &mt9m114_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, mt9m114_dt_match); + +static struct platform_driver mt9m114_platform_driver = { + .driver = { + .name = "qcom,mt9m114", + .owner = THIS_MODULE, + .of_match_table = mt9m114_dt_match, + }, +}; + +static int32_t mt9m114_platform_probe(struct platform_device *pdev) +{ + int32_t rc; + const struct of_device_id *match; + match = of_match_device(mt9m114_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init mt9m114_init_module(void) +{ + int32_t rc; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&mt9m114_platform_driver, + mt9m114_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&mt9m114_i2c_driver); +} + +static void __exit mt9m114_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (mt9m114_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&mt9m114_s_ctrl); + platform_driver_unregister(&mt9m114_platform_driver); + } else + i2c_del_driver(&mt9m114_i2c_driver); + return; +} + +int32_t mt9m114_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + /* 1. Write Recommend settings */ + /* 2. Write change settings */ + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, mt9m114_recommend_settings, + ARRAY_SIZE(mt9m114_recommend_settings), + MSM_CAMERA_I2C_WORD_DATA); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, + mt9m114_config_change_settings, + ARRAY_SIZE(mt9m114_config_change_settings), + MSM_CAMERA_I2C_WORD_DATA); + break; + case CFG_SET_RESOLUTION: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, mt9m114_720p_settings, + ARRAY_SIZE(mt9m114_720p_settings), + MSM_CAMERA_I2C_WORD_DATA); + break; + case CFG_SET_STOP_STREAM: + break; + case CFG_SET_START_STREAM: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, + mt9m114_config_change_settings, + ARRAY_SIZE(mt9m114_config_change_settings), + MSM_CAMERA_I2C_WORD_DATA); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + p_ctrl = &s_ctrl->sensordata->power_info; + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(struct msm_sensor_power_setting) + * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id 0x%x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + p_ctrl->power_setting_size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + p_ctrl->power_setting[slave_index].seq_type, + p_ctrl->power_setting[slave_index].seq_val, + p_ctrl->power_setting[slave_index].config_val, + p_ctrl->power_setting[slave_index].delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_SATURATION: { + int32_t sat_lev; + if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Saturation Value is %d", __func__, sat_lev); + break; + } + case CFG_SET_CONTRAST: { + int32_t con_lev; + if (copy_from_user(&con_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Contrast Value is %d", __func__, con_lev); + break; + } + case CFG_SET_SHARPNESS: { + int32_t shp_lev; + if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting, + sizeof(int32_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + pr_debug("%s: Sharpness Value is %d", __func__, shp_lev); + break; + } + case CFG_SET_AUTOFOCUS: { + /* TO-DO: set the Auto Focus */ + pr_debug("%s: Setting Auto Focus", __func__); + break; + } + case CFG_CANCEL_AUTOFOCUS: { + /* TO-DO: Cancel the Auto Focus */ + pr_debug("%s: Cancelling Auto Focus", __func__); + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +static struct msm_sensor_fn_t mt9m114_sensor_func_tbl = { + .sensor_config = mt9m114_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, +}; + +static struct msm_sensor_ctrl_t mt9m114_s_ctrl = { + .sensor_i2c_client = &mt9m114_sensor_i2c_client, + .power_setting_array.power_setting = mt9m114_power_setting, + .power_setting_array.size = ARRAY_SIZE(mt9m114_power_setting), + .msm_sensor_mutex = &mt9m114_mut, + .sensor_v4l2_subdev_info = mt9m114_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(mt9m114_subdev_info), + .func_tbl = &mt9m114_sensor_func_tbl, +}; + +module_init(mt9m114_init_module); +module_exit(mt9m114_exit_module); +MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/ov12830.c b/drivers/media/platform/msm/camera_v2_j5/sensor/ov12830.c new file mode 100755 index 0000000000000000000000000000000000000000..fb6d548f1f225bce42e8da787faf413606c620d3 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/ov12830.c @@ -0,0 +1,197 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define OV12830_SENSOR_NAME "ov12830" +DEFINE_MSM_MUTEX(ov12830_mut); + +static struct msm_sensor_ctrl_t ov12830_s_ctrl; + +static struct msm_sensor_power_setting ov12830_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov12830_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov12830_i2c_id[] = { + {OV12830_SENSOR_NAME, + (kernel_ulong_t)&ov12830_s_ctrl}, + { } +}; + +static int msm_ov12830_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov12830_s_ctrl); +} + +static struct i2c_driver ov12830_i2c_driver = { + .id_table = ov12830_i2c_id, + .probe = msm_ov12830_i2c_probe, + .driver = { + .name = OV12830_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov12830_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov12830_dt_match[] = { + {.compatible = "qcom,ov12830", + .data = &ov12830_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov12830_dt_match); + +static struct platform_driver ov12830_platform_driver = { + .driver = { + .name = "qcom,ov12830", + .owner = THIS_MODULE, + .of_match_table = ov12830_dt_match, + }, +}; + +static int32_t ov12830_platform_probe + (struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov12830_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov12830_init_module(void) +{ + int32_t rc = 0; + pr_debug("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov12830_platform_driver, + ov12830_platform_probe); + if (!rc) + return rc; + pr_debug("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov12830_i2c_driver); +} + +static void __exit ov12830_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov12830_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov12830_s_ctrl); + platform_driver_unregister + (&ov12830_platform_driver); + } else { + i2c_del_driver(&ov12830_i2c_driver); + } +} + +static struct msm_sensor_ctrl_t ov12830_s_ctrl = { + .sensor_i2c_client = &ov12830_sensor_i2c_client, + .power_setting_array.power_setting = ov12830_power_setting, + .power_setting_array.size = + ARRAY_SIZE(ov12830_power_setting), + .msm_sensor_mutex = &ov12830_mut, + .sensor_v4l2_subdev_info = ov12830_subdev_info, + .sensor_v4l2_subdev_info_size = + ARRAY_SIZE(ov12830_subdev_info), +}; + +module_init(ov12830_init_module); +module_exit(ov12830_exit_module); +MODULE_DESCRIPTION("ov12830"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/ov2720.c b/drivers/media/platform/msm/camera_v2_j5/sensor/ov2720.c new file mode 100755 index 0000000000000000000000000000000000000000..397564b3ef629c64012f0bce55cf2aeeb0f9bf46 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/ov2720.c @@ -0,0 +1,155 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define OV2720_SENSOR_NAME "ov2720" +DEFINE_MSM_MUTEX(ov2720_mut); + +static struct msm_sensor_ctrl_t ov2720_s_ctrl; + +static struct msm_sensor_power_setting ov2720_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov2720_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov2720_i2c_id[] = { + {OV2720_SENSOR_NAME, (kernel_ulong_t)&ov2720_s_ctrl}, + { } +}; + +static int32_t msm_ov2720_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov2720_s_ctrl); +} + +static struct i2c_driver ov2720_i2c_driver = { + .id_table = ov2720_i2c_id, + .probe = msm_ov2720_i2c_probe, + .driver = { + .name = OV2720_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov2720_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov2720_dt_match[] = { + {.compatible = "qcom,ov2720", .data = &ov2720_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov2720_dt_match); + +static struct platform_driver ov2720_platform_driver = { + .driver = { + .name = "qcom,ov2720", + .owner = THIS_MODULE, + .of_match_table = ov2720_dt_match, + }, +}; + +static int32_t ov2720_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov2720_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov2720_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov2720_platform_driver, + ov2720_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov2720_i2c_driver); +} + +static void __exit ov2720_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov2720_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov2720_s_ctrl); + platform_driver_unregister(&ov2720_platform_driver); + } else + i2c_del_driver(&ov2720_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t ov2720_s_ctrl = { + .sensor_i2c_client = &ov2720_sensor_i2c_client, + .power_setting_array.power_setting = ov2720_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov2720_power_setting), + .msm_sensor_mutex = &ov2720_mut, + .sensor_v4l2_subdev_info = ov2720_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov2720_subdev_info), +}; + +module_init(ov2720_init_module); +module_exit(ov2720_exit_module); +MODULE_DESCRIPTION("ov2720"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/ov5645.c b/drivers/media/platform/msm/camera_v2_j5/sensor/ov5645.c new file mode 100755 index 0000000000000000000000000000000000000000..7b84d8392571b435844a6360aa60dd94f8bb07c4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/ov5645.c @@ -0,0 +1,958 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" +#define OV5645_SENSOR_NAME "ov5645" +#define PLATFORM_DRIVER_NAME "msm_camera_ov5645" +#define ov5645_obj ov5645_##obj + +/*#define CONFIG_MSMB_CAMERA_DEBUG*/ +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + + +DEFINE_MSM_MUTEX(ov5645_mut); +static struct msm_sensor_ctrl_t ov5645_s_ctrl; + +static struct msm_sensor_power_setting ov5645_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, + +}; + +static struct msm_camera_i2c_reg_conf ov5645_sxga_settings[] = { + {0x3612, 0xa9,}, + {0x3614, 0x50,}, + {0x3618, 0x00,}, + {0x3034, 0x18,}, + {0x3035, 0x21,}, + {0x3036, 0x70,}, + {0x3600, 0x09,}, + {0x3601, 0x43,}, + {0x3708, 0x66,}, + {0x370c, 0xc3,}, + {0x3800, 0x00,}, + {0x3801, 0x00,}, + {0x3802, 0x00,}, + {0x3803, 0x06,}, + {0x3804, 0x0a,}, + {0x3805, 0x3f,}, + {0x3806, 0x07,}, + {0x3807, 0x9d,}, + {0x3808, 0x05,}, + {0x3809, 0x00,}, + {0x380a, 0x03,}, + {0x380b, 0xc0,}, + {0x380c, 0x07,}, + {0x380d, 0x68,}, + {0x380e, 0x03,}, + {0x380f, 0xd8,}, + {0x3813, 0x06,}, + {0x3814, 0x31,}, + {0x3815, 0x31,}, + {0x3820, 0x47,}, + {0x3a02, 0x03,}, + {0x3a03, 0xd8,}, + {0x3a08, 0x01,}, + {0x3a09, 0xf8,}, + {0x3a0a, 0x01,}, + {0x3a0b, 0xa4,}, + {0x3a0e, 0x02,}, + {0x3a0d, 0x02,}, + {0x3a14, 0x03,}, + {0x3a15, 0xd8,}, + {0x3a18, 0x00,}, + {0x4004, 0x02,}, + {0x4005, 0x18,}, + {0x4300, 0x30,}, + {0x4202, 0x00,}, + +}; + +static struct msm_camera_i2c_reg_conf ov5645_full_settings[] = { + {0x3612, 0xab,}, + {0x3614, 0x50,}, + {0x3618, 0x04,}, + {0x3034, 0x18,}, + {0x3035, 0x11,}, + {0x3036, 0x54,}, + {0x3600, 0x08,}, + {0x3601, 0x33,}, + {0x3708, 0x63,}, + {0x370c, 0xc0,}, + {0x3800, 0x00,}, + {0x3801, 0x00,}, + {0x3802, 0x00,}, + {0x3803, 0x00,}, + {0x3804, 0x0a,}, + {0x3805, 0x3f,}, + {0x3806, 0x07,}, + {0x3807, 0x9f,}, + {0x3808, 0x0a,}, + {0x3809, 0x20,}, + {0x380a, 0x07,}, + {0x380b, 0x98,}, + {0x380c, 0x0b,}, + {0x380d, 0x1c,}, + {0x380e, 0x07,}, + {0x380f, 0xb0,}, + {0x3813, 0x06,}, + {0x3814, 0x11,}, + {0x3815, 0x11,}, + {0x3820, 0x47,}, + {0x4514, 0x88,}, + {0x3a02, 0x07,}, + {0x3a03, 0xb0,}, + {0x3a08, 0x01,}, + {0x3a09, 0x27,}, + {0x3a0a, 0x00,}, + {0x3a0b, 0xf6,}, + {0x3a0e, 0x06,}, + {0x3a0d, 0x08,}, + {0x3a14, 0x07,}, + {0x3a15, 0xb0,}, + {0x3a18, 0x01,}, + {0x4004, 0x06,}, + {0x4005, 0x18,}, + {0x4300, 0x30,}, + {0x4837, 0x0b,}, + {0x4202, 0x00,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_1080P_settings[] = { + {0x3612, 0xab,}, + {0x3614, 0x50,}, + {0x3618, 0x04,}, + {0x3034, 0x18,}, + {0x3035, 0x11,}, + {0x3036, 0x54,}, + {0x3600, 0x08,}, + {0x3601, 0x33,}, + {0x3708, 0x63,}, + {0x370c, 0xc0,}, + {0x3800, 0x01,}, + {0x3801, 0x50,}, + {0x3802, 0x01,}, + {0x3803, 0xb2,}, + {0x3804, 0x08,}, + {0x3805, 0xef,}, + {0x3806, 0x05,}, + {0x3807, 0xf1,}, + {0x3808, 0x07,}, + {0x3809, 0x80,}, + {0x380a, 0x04,}, + {0x380b, 0x38,}, + {0x380c, 0x09,}, + {0x380d, 0xc4,}, + {0x380e, 0x04,}, + {0x380f, 0x60,}, + {0x3813, 0x04,}, + {0x3814, 0x11,}, + {0x3815, 0x11,}, + {0x3820, 0x47,}, + {0x4514, 0x88,}, + {0x3a02, 0x04,}, + {0x3a03, 0x60,}, + {0x3a08, 0x01,}, + {0x3a09, 0x50,}, + {0x3a0a, 0x01,}, + {0x3a0b, 0x18,}, + {0x3a0e, 0x03,}, + {0x3a0d, 0x04,}, + {0x3a14, 0x04,}, + {0x3a15, 0x60,}, + {0x3a18, 0x00,}, + {0x4004, 0x06,}, + {0x4005, 0x18,}, + {0x4300, 0x30,}, + {0x4202, 0x00,}, + {0x4837, 0x0b,}, +}; + + +static struct msm_camera_i2c_reg_conf ov5645_recommend_settings[] = { + {0x3103, 0x11,}, + {0x3008, 0x82,}, + {0x3008, 0x42,}, + {0x3103, 0x03,}, + {0x3503, 0x07,}, + {0x3002, 0x1c,}, + {0x3006, 0xc3,}, + {0x300e, 0x45,}, + {0x3017, 0x00,}, + {0x3018, 0x00,}, + {0x302e, 0x0b,}, + {0x3037, 0x13,}, + {0x3108, 0x01,}, + {0x3611, 0x06,}, + {0x3500, 0x00,}, + {0x3501, 0x01,}, + {0x3502, 0x00,}, + {0x350a, 0x00,}, + {0x350b, 0x3f,}, + {0x3620, 0x33,}, + {0x3621, 0xe0,}, + {0x3622, 0x01,}, + {0x3630, 0x2e,}, + {0x3631, 0x00,}, + {0x3632, 0x32,}, + {0x3633, 0x52,}, + {0x3634, 0x70,}, + {0x3635, 0x13,}, + {0x3636, 0x03,}, + {0x3703, 0x5a,}, + {0x3704, 0xa0,}, + {0x3705, 0x1a,}, + {0x3709, 0x12,}, + {0x370b, 0x61,}, + {0x370f, 0x10,}, + {0x3715, 0x78,}, + {0x3717, 0x01,}, + {0x371b, 0x20,}, + {0x3731, 0x12,}, + {0x3901, 0x0a,}, + {0x3905, 0x02,}, + {0x3906, 0x10,}, + {0x3719, 0x86,}, + {0x3810, 0x00,}, + {0x3811, 0x10,}, + {0x3812, 0x00,}, + {0x3821, 0x01,}, + {0x3824, 0x01,}, + {0x3826, 0x03,}, + {0x3828, 0x08,}, + {0x3a19, 0xf8,}, + {0x3c01, 0x34,}, + {0x3c04, 0x28,}, + {0x3c05, 0x98,}, + {0x3c07, 0x07,}, + {0x3c09, 0xc2,}, + {0x3c0a, 0x9c,}, + {0x3c0b, 0x40,}, + {0x3c01, 0x34,}, + {0x4001, 0x02,}, + {0x4514, 0x00,}, + {0x4520, 0xb0,}, + {0x460b, 0x37,}, + {0x460c, 0x20,}, + {0x4818, 0x01,}, + {0x481d, 0xf0,}, + {0x481f, 0x50,}, + {0x4823, 0x70,}, + {0x4831, 0x14,}, + {0x5000, 0xa7,}, + {0x5001, 0x83,}, + {0x501d, 0x00,}, + {0x501f, 0x00,}, + {0x503d, 0x00,}, + {0x505c, 0x30,}, + {0x5181, 0x59,}, + {0x5183, 0x00,}, + {0x5191, 0xf0,}, + {0x5192, 0x03,}, + {0x5684, 0x10,}, + {0x5685, 0xa0,}, + {0x5686, 0x0c,}, + {0x5687, 0x78,}, + {0x5a00, 0x08,}, + {0x5a21, 0x00,}, + {0x5a24, 0x00,}, + {0x3008, 0x02,}, + {0x3503, 0x00,}, + {0x5180, 0xff,}, + {0x5181, 0xf2,}, + {0x5182, 0x00,}, + {0x5183, 0x14,}, + {0x5184, 0x25,}, + {0x5185, 0x24,}, + {0x5186, 0x09,}, + {0x5187, 0x09,}, + {0x5188, 0x0a,}, + {0x5189, 0x75,}, + {0x518a, 0x52,}, + {0x518b, 0xea,}, + {0x518c, 0xa8,}, + {0x518d, 0x42,}, + {0x518e, 0x38,}, + {0x518f, 0x56,}, + {0x5190, 0x42,}, + {0x5191, 0xf8,}, + {0x5192, 0x04,}, + {0x5193, 0x70,}, + {0x5194, 0xf0,}, + {0x5195, 0xf0,}, + {0x5196, 0x03,}, + {0x5197, 0x01,}, + {0x5198, 0x04,}, + {0x5199, 0x12,}, + {0x519a, 0x04,}, + {0x519b, 0x00,}, + {0x519c, 0x06,}, + {0x519d, 0x82,}, + {0x519e, 0x38,}, + {0x5381, 0x1e,}, + {0x5382, 0x5b,}, + {0x5383, 0x08,}, + {0x5384, 0x0a,}, + {0x5385, 0x7e,}, + {0x5386, 0x88,}, + {0x5387, 0x7c,}, + {0x5388, 0x6c,}, + {0x5389, 0x10,}, + {0x538a, 0x01,}, + {0x538b, 0x98,}, + {0x5300, 0x08,}, + {0x5301, 0x30,}, + {0x5302, 0x10,}, + {0x5303, 0x00,}, + {0x5304, 0x08,}, + {0x5305, 0x30,}, + {0x5306, 0x08,}, + {0x5307, 0x16,}, + {0x5309, 0x08,}, + {0x530a, 0x30,}, + {0x530b, 0x04,}, + {0x530c, 0x06,}, + {0x5480, 0x01,}, + {0x5481, 0x08,}, + {0x5482, 0x14,}, + {0x5483, 0x28,}, + {0x5484, 0x51,}, + {0x5485, 0x65,}, + {0x5486, 0x71,}, + {0x5487, 0x7d,}, + {0x5488, 0x87,}, + {0x5489, 0x91,}, + {0x548a, 0x9a,}, + {0x548b, 0xaa,}, + {0x548c, 0xb8,}, + {0x548d, 0xcd,}, + {0x548e, 0xdd,}, + {0x548f, 0xea,}, + {0x5490, 0x1d,}, + {0x5580, 0x02,}, + {0x5583, 0x40,}, + {0x5584, 0x10,}, + {0x5589, 0x10,}, + {0x558a, 0x00,}, + {0x558b, 0xf8,}, + {0x5800, 0x3f,}, + {0x5801, 0x16,}, + {0x5802, 0x0e,}, + {0x5803, 0x0d,}, + {0x5804, 0x17,}, + {0x5805, 0x3f,}, + {0x5806, 0x0b,}, + {0x5807, 0x06,}, + {0x5808, 0x04,}, + {0x5809, 0x04,}, + {0x580a, 0x06,}, + {0x580b, 0x0b,}, + {0x580c, 0x09,}, + {0x580d, 0x03,}, + {0x580e, 0x00,}, + {0x580f, 0x00,}, + {0x5810, 0x03,}, + {0x5811, 0x08,}, + {0x5812, 0x0a,}, + {0x5813, 0x03,}, + {0x5814, 0x00,}, + {0x5815, 0x00,}, + {0x5816, 0x04,}, + {0x5817, 0x09,}, + {0x5818, 0x0f,}, + {0x5819, 0x08,}, + {0x581a, 0x06,}, + {0x581b, 0x06,}, + {0x581c, 0x08,}, + {0x581d, 0x0c,}, + {0x581e, 0x3f,}, + {0x581f, 0x1e,}, + {0x5820, 0x12,}, + {0x5821, 0x13,}, + {0x5822, 0x21,}, + {0x5823, 0x3f,}, + {0x5824, 0x68,}, + {0x5825, 0x28,}, + {0x5826, 0x2c,}, + {0x5827, 0x28,}, + {0x5828, 0x08,}, + {0x5829, 0x48,}, + {0x582a, 0x64,}, + {0x582b, 0x62,}, + {0x582c, 0x64,}, + {0x582d, 0x28,}, + {0x582e, 0x46,}, + {0x582f, 0x62,}, + {0x5830, 0x60,}, + {0x5831, 0x62,}, + {0x5832, 0x26,}, + {0x5833, 0x48,}, + {0x5834, 0x66,}, + {0x5835, 0x44,}, + {0x5836, 0x64,}, + {0x5837, 0x28,}, + {0x5838, 0x66,}, + {0x5839, 0x48,}, + {0x583a, 0x2c,}, + {0x583b, 0x28,}, + {0x583c, 0x26,}, + {0x583d, 0xae,}, + {0x5025, 0x00,}, + {0x3a0f, 0x30,}, + {0x3a10, 0x28,}, + {0x3a1b, 0x30,}, + {0x3a1e, 0x26,}, + {0x3a11, 0x60,}, + {0x3a1f, 0x14,}, + {0x0601, 0x02,}, + {0x3008, 0x42,}, + +}; + +static struct v4l2_subdev_info ov5645_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static struct msm_camera_i2c_reg_conf ov5645_start_settings[] = { + {0x3008, 0x02,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_stop_settings[] = { + {0x3008, 0x42,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_enable_aec_settings[] = { + {0x3503, 0x00,}, + {0x3406, 0x00,}, +}; + +static struct msm_camera_i2c_reg_conf ov5645_disable_aec_settings[] = { + {0x3503, 0x07,}, + {0x3406, 0x01,}, +}; + +static const struct i2c_device_id ov5645_i2c_id[] = { + {OV5645_SENSOR_NAME, (kernel_ulong_t)&ov5645_s_ctrl}, + { } +}; + +static int32_t msm_ov5645_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov5645_s_ctrl); +} + +static struct i2c_driver ov5645_i2c_driver = { + .id_table = ov5645_i2c_id, + .probe = msm_ov5645_i2c_probe, + .driver = { + .name = OV5645_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov5645_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov5645_dt_match[] = { + {.compatible = "ovti,ov5645", .data = &ov5645_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov5645_dt_match); + +static int32_t ov5645_platform_probe(struct platform_device *pdev) +{ + int32_t rc; + const struct of_device_id *match; + match = of_match_device(ov5645_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static struct platform_driver ov5645_platform_driver = { + .driver = { + .name = "ovti,ov5645", + .owner = THIS_MODULE, + .of_match_table = ov5645_dt_match, + }, + .probe = ov5645_platform_probe, +}; + +static int __init ov5645_init_module(void) +{ + int32_t rc; + pr_err("%s:%d\n", __func__, __LINE__); + rc = platform_driver_register(&ov5645_platform_driver); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov5645_i2c_driver); +} + +static void __exit ov5645_exit_module(void) +{ + pr_err("%s:%d\n", __func__, __LINE__); + if (ov5645_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov5645_s_ctrl); + platform_driver_unregister(&ov5645_platform_driver); + } else + i2c_del_driver(&ov5645_i2c_driver); + return; +} + +int32_t ov5645_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + long rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + /* 1. Write Recommend settings */ + /* 2. Write change settings */ + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_recommend_settings, + ARRAY_SIZE(ov5645_recommend_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + + case CFG_SET_RESOLUTION: { + /*copy from user the desired resoltuion*/ + enum msm_sensor_resolution_t res = MSM_SENSOR_INVALID_RES; + if (copy_from_user(&res, (void *)cdata->cfg.setting, + sizeof(enum msm_sensor_resolution_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + pr_err("%s:%d res =%d\n", __func__, __LINE__, res); + + if (res == MSM_SENSOR_RES_FULL) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_full_settings, + ARRAY_SIZE(ov5645_full_settings), + MSM_CAMERA_I2C_BYTE_DATA); + pr_err("%s:%d res =%d\n ov5645_full_settings ", + __func__, __LINE__, res); + } else if (res == MSM_SENSOR_RES_QTR) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_sxga_settings, + ARRAY_SIZE(ov5645_sxga_settings), + MSM_CAMERA_I2C_BYTE_DATA); + pr_err("%s:%d res =%d ov5645_sxga_settings\n", + __func__, __LINE__, res); + } else if (res == MSM_SENSOR_RES_2) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, + ov5645_1080P_settings, + ARRAY_SIZE(ov5645_1080P_settings), + MSM_CAMERA_I2C_BYTE_DATA); + pr_err("%s:%d res =%d ov5645_1080P_settings\n", + __func__, __LINE__, res); + } else { + pr_err("%s:%d failed resoultion set\n", __func__, + __LINE__); + rc = -EFAULT; + } + } + break; + case CFG_SET_STOP_STREAM: + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_stop_settings, + ARRAY_SIZE(ov5645_stop_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_SET_START_STREAM: + if (s_ctrl->camera_stream_type != MSM_CAMERA_STREAM_SNAPSHOT) { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_enable_aec_settings, + ARRAY_SIZE(ov5645_enable_aec_settings), + MSM_CAMERA_I2C_BYTE_DATA); + } else { + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_disable_aec_settings, + ARRAY_SIZE(ov5645_disable_aec_settings), + MSM_CAMERA_I2C_BYTE_DATA); + } + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl( + s_ctrl->sensor_i2c_client, ov5645_start_settings, + ARRAY_SIZE(ov5645_start_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + p_ctrl = &s_ctrl->sensordata->power_info; + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(struct msm_sensor_power_setting) + * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id %x sensor addr type %d sensor reg %x\n" + "sensor id %x\n", __func__, + sensor_slave_info.slave_addr, + sensor_slave_info.addr_type, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + p_ctrl->power_setting_size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + p_ctrl->power_setting[slave_index].seq_type, + p_ctrl->power_setting[slave_index].seq_val, + p_ctrl->power_setting[slave_index].config_val, + p_ctrl->power_setting[slave_index].delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_STREAM_TYPE: { + enum msm_camera_stream_type_t stream_type = MSM_CAMERA_STREAM_INVALID; + if (copy_from_user(&stream_type, (void *)cdata->cfg.setting, + sizeof(enum msm_camera_stream_type_t))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + s_ctrl->camera_stream_type = stream_type; + break; + } + case CFG_SET_SATURATION: + break; + case CFG_SET_CONTRAST: + break; + case CFG_SET_SHARPNESS: + break; + case CFG_SET_AUTOFOCUS: + /* TO-DO: set the Auto Focus */ + pr_debug("%s: Setting Auto Focus", __func__); + break; + case CFG_CANCEL_AUTOFOCUS: + /* TO-DO: Cancel the Auto Focus */ + pr_debug("%s: Cancelling Auto Focus", __func__); + break; + case CFG_SET_ISO: + break; + case CFG_SET_EXPOSURE_COMPENSATION: + break; + case CFG_SET_EFFECT: + break; + case CFG_SET_ANTIBANDING: + break; + case CFG_SET_BESTSHOT_MODE: + break; + case CFG_SET_WHITE_BALANCE: + break; + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +static struct msm_sensor_fn_t ov5645_sensor_func_tbl = { + .sensor_config = ov5645_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = msm_sensor_match_id, +}; + +static struct msm_sensor_ctrl_t ov5645_s_ctrl = { + .sensor_i2c_client = &ov5645_sensor_i2c_client, + .power_setting_array.power_setting = ov5645_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov5645_power_setting), + .msm_sensor_mutex = &ov5645_mut, + .sensor_v4l2_subdev_info = ov5645_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov5645_subdev_info), + .func_tbl = &ov5645_sensor_func_tbl, +}; + +module_init(ov5645_init_module); +module_exit(ov5645_exit_module); +MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/ov5648.c b/drivers/media/platform/msm/camera_v2_j5/sensor/ov5648.c new file mode 100755 index 0000000000000000000000000000000000000000..99224684a1313ff12cc637f58351e2944c65c91e --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/ov5648.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" + +#define OV5648_SENSOR_NAME "ov5648" +DEFINE_MSM_MUTEX(ov5648_mut); + +static struct msm_sensor_ctrl_t ov5648_s_ctrl; + +static struct msm_sensor_power_setting ov5648_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_VDIG, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov5648_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov5648_i2c_id[] = { + {OV5648_SENSOR_NAME, + (kernel_ulong_t)&ov5648_s_ctrl}, + { } +}; + +static int32_t msm_ov5648_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov5648_s_ctrl); +} + +static struct i2c_driver ov5648_i2c_driver = { + .id_table = ov5648_i2c_id, + .probe = msm_ov5648_i2c_probe, + .driver = { + .name = OV5648_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov5648_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static struct msm_sensor_ctrl_t ov5648_s_ctrl = { + .sensor_i2c_client = &ov5648_sensor_i2c_client, + .power_setting_array.power_setting = ov5648_power_setting, + .power_setting_array.size = + ARRAY_SIZE(ov5648_power_setting), + .msm_sensor_mutex = &ov5648_mut, + .sensor_v4l2_subdev_info = ov5648_subdev_info, + .sensor_v4l2_subdev_info_size = + ARRAY_SIZE(ov5648_subdev_info), +}; + +static const struct of_device_id ov5648_dt_match[] = { + { + .compatible = "ovti,ov5648", + .data = &ov5648_s_ctrl + }, + {} +}; + +MODULE_DEVICE_TABLE(of, ov5648_dt_match); + +static struct platform_driver ov5648_platform_driver = { + .driver = { + .name = "ovti,ov5648", + .owner = THIS_MODULE, + .of_match_table = ov5648_dt_match, + }, +}; + +static int32_t ov5648_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + + match = of_match_device(ov5648_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov5648_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_probe(&ov5648_platform_driver, + ov5648_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&ov5648_i2c_driver); +} + +static void __exit ov5648_exit_module(void) +{ + if (ov5648_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov5648_s_ctrl); + platform_driver_unregister(&ov5648_platform_driver); + } else + i2c_del_driver(&ov5648_i2c_driver); + return; +} + +module_init(ov5648_init_module); +module_exit(ov5648_exit_module); +MODULE_DESCRIPTION("ov5648"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2_j5/sensor/ov8825.c new file mode 100755 index 0000000000000000000000000000000000000000..e17c94e85b50332a60393663a16e199af0acdce8 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/ov8825.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define OV8825_SENSOR_NAME "ov8825" +DEFINE_MSM_MUTEX(ov8825_mut); + +static struct msm_sensor_ctrl_t ov8825_s_ctrl; + +static struct msm_sensor_power_setting ov8825_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov8825_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov8825_i2c_id[] = { + {OV8825_SENSOR_NAME, (kernel_ulong_t)&ov8825_s_ctrl}, + { } +}; + +static int32_t msm_ov8825_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov8825_s_ctrl); +} + +static struct i2c_driver ov8825_i2c_driver = { + .id_table = ov8825_i2c_id, + .probe = msm_ov8825_i2c_probe, + .driver = { + .name = OV8825_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov8825_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov8825_dt_match[] = { + {.compatible = "qcom,ov8825", .data = &ov8825_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov8825_dt_match); + +static struct platform_driver ov8825_platform_driver = { + .driver = { + .name = "qcom,ov8825", + .owner = THIS_MODULE, + .of_match_table = ov8825_dt_match, + }, +}; + +static int32_t ov8825_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov8825_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov8825_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov8825_platform_driver, + ov8825_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov8825_i2c_driver); +} + +static void __exit ov8825_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov8825_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov8825_s_ctrl); + platform_driver_unregister(&ov8825_platform_driver); + } else + i2c_del_driver(&ov8825_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t ov8825_s_ctrl = { + .sensor_i2c_client = &ov8825_sensor_i2c_client, + .power_setting_array.power_setting = ov8825_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov8825_power_setting), + .msm_sensor_mutex = &ov8825_mut, + .sensor_v4l2_subdev_info = ov8825_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8825_subdev_info), +}; + +module_init(ov8825_init_module); +module_exit(ov8825_exit_module); +MODULE_DESCRIPTION("ov8825"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/ov8865.c b/drivers/media/platform/msm/camera_v2_j5/sensor/ov8865.c new file mode 100755 index 0000000000000000000000000000000000000000..6d788f592b1747267081a28f536ca1875fc9bdd0 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/ov8865.c @@ -0,0 +1,185 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define OV8865_SENSOR_NAME "ov8865" +DEFINE_MSM_MUTEX(ov8865_mut); + +static struct msm_sensor_ctrl_t ov8865_s_ctrl; + +static struct msm_sensor_power_setting ov8865_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_AF_PWDM, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov8865_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id ov8865_i2c_id[] = { + {OV8865_SENSOR_NAME, (kernel_ulong_t)&ov8865_s_ctrl}, + { } +}; + +static int32_t msm_ov8865_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov8865_s_ctrl); +} + +static struct i2c_driver ov8865_i2c_driver = { + .id_table = ov8865_i2c_id, + .probe = msm_ov8865_i2c_probe, + .driver = { + .name = OV8865_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov8865_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id ov8865_dt_match[] = { + {.compatible = "ovti,ov8865", .data = &ov8865_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov8865_dt_match); + +static struct platform_driver ov8865_platform_driver = { + .driver = { + .name = "ovti,ov8865", + .owner = THIS_MODULE, + .of_match_table = ov8865_dt_match, + }, +}; + +static int32_t ov8865_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(ov8865_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov8865_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&ov8865_platform_driver, + ov8865_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&ov8865_i2c_driver); +} + +static void __exit ov8865_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (ov8865_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov8865_s_ctrl); + platform_driver_unregister(&ov8865_platform_driver); + } else + i2c_del_driver(&ov8865_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t ov8865_s_ctrl = { + .sensor_i2c_client = &ov8865_sensor_i2c_client, + .power_setting_array.power_setting = ov8865_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov8865_power_setting), + .msm_sensor_mutex = &ov8865_mut, + .sensor_v4l2_subdev_info = ov8865_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8865_subdev_info), +}; + +module_init(ov8865_init_module); +module_exit(ov8865_exit_module); +MODULE_DESCRIPTION("ov8865"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/ov9724.c b/drivers/media/platform/msm/camera_v2_j5/sensor/ov9724.c new file mode 100755 index 0000000000000000000000000000000000000000..99bf03ab1aa03b82cc1e1904fbab36fa1c57d195 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/ov9724.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" + +#define OV9724_SENSOR_NAME "ov9724" +DEFINE_MSM_MUTEX(ov9724_mut); + +static struct msm_sensor_ctrl_t ov9724_s_ctrl; + +static struct msm_sensor_power_setting ov9724_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 10, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 10, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info ov9724_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static int32_t msm_ov9724_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &ov9724_s_ctrl); +} + +static const struct i2c_device_id ov9724_i2c_id[] = { + {OV9724_SENSOR_NAME, (kernel_ulong_t)&ov9724_s_ctrl}, + { } +}; + +static struct i2c_driver ov9724_i2c_driver = { + .id_table = ov9724_i2c_id, + .probe = msm_ov9724_i2c_probe, + .driver = { + .name = OV9724_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client ov9724_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static struct msm_sensor_ctrl_t ov9724_s_ctrl = { + .sensor_i2c_client = &ov9724_sensor_i2c_client, + .power_setting_array.power_setting = ov9724_power_setting, + .power_setting_array.size = ARRAY_SIZE(ov9724_power_setting), + .msm_sensor_mutex = &ov9724_mut, + .sensor_v4l2_subdev_info = ov9724_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov9724_subdev_info), +}; + +static const struct of_device_id ov9724_dt_match[] = { + {.compatible = "qcom,ov9724", .data = &ov9724_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, ov9724_dt_match); + +static struct platform_driver ov9724_platform_driver = { + .driver = { + .name = "qcom,ov9724", + .owner = THIS_MODULE, + .of_match_table = ov9724_dt_match, + }, +}; + +static int32_t ov9724_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + + match = of_match_device(ov9724_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init ov9724_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_probe(&ov9724_platform_driver, + ov9724_platform_probe); + if (!rc) + return rc; + return i2c_add_driver(&ov9724_i2c_driver); +} + +static void __exit ov9724_exit_module(void) +{ + if (ov9724_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&ov9724_s_ctrl); + platform_driver_unregister(&ov9724_platform_driver); + } else + i2c_del_driver(&ov9724_i2c_driver); + return; +} + +module_init(ov9724_init_module); +module_exit(ov9724_exit_module); +MODULE_DESCRIPTION("ov9724"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/s5k3l1yx.c b/drivers/media/platform/msm/camera_v2_j5/sensor/s5k3l1yx.c new file mode 100755 index 0000000000000000000000000000000000000000..225e81d94cdb84ee5bd654478812e5e5f2a9416c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/s5k3l1yx.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define S5K3L1YX_SENSOR_NAME "s5k3l1yx" +DEFINE_MSM_MUTEX(s5k3l1yx_mut); + +static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl; + +static struct msm_sensor_power_setting s5k3l1yx_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VAF, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 0, + }, +}; + +static struct v4l2_subdev_info s5k3l1yx_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SBGGR10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id s5k3l1yx_i2c_id[] = { + {S5K3L1YX_SENSOR_NAME, (kernel_ulong_t)&s5k3l1yx_s_ctrl}, + { } +}; + +static int32_t msm_s5k3l1yx_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &s5k3l1yx_s_ctrl); +} + +static struct i2c_driver s5k3l1yx_i2c_driver = { + .id_table = s5k3l1yx_i2c_id, + .probe = msm_s5k3l1yx_i2c_probe, + .driver = { + .name = S5K3L1YX_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client s5k3l1yx_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id s5k3l1yx_dt_match[] = { + {.compatible = "qcom,s5k3l1yx", .data = &s5k3l1yx_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, s5k3l1yx_dt_match); + +static struct platform_driver s5k3l1yx_platform_driver = { + .driver = { + .name = "qcom,s5k3l1yx", + .owner = THIS_MODULE, + .of_match_table = s5k3l1yx_dt_match, + }, +}; + +static int32_t s5k3l1yx_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(s5k3l1yx_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init s5k3l1yx_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&s5k3l1yx_platform_driver, + s5k3l1yx_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&s5k3l1yx_i2c_driver); +} + +static void __exit s5k3l1yx_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (s5k3l1yx_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&s5k3l1yx_s_ctrl); + platform_driver_unregister(&s5k3l1yx_platform_driver); + } else + i2c_del_driver(&s5k3l1yx_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl = { + .sensor_i2c_client = &s5k3l1yx_sensor_i2c_client, + .power_setting_array.power_setting = s5k3l1yx_power_setting, + .power_setting_array.size = ARRAY_SIZE(s5k3l1yx_power_setting), + .msm_sensor_mutex = &s5k3l1yx_mut, + .sensor_v4l2_subdev_info = s5k3l1yx_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k3l1yx_subdev_info), +}; + +module_init(s5k3l1yx_init_module); +module_exit(s5k3l1yx_exit_module); +MODULE_DESCRIPTION("s5k3l1yx"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/s5k4e1.c b/drivers/media/platform/msm/camera_v2_j5/sensor/s5k4e1.c new file mode 100755 index 0000000000000000000000000000000000000000..5c70df2dec56e46aa47b1edd9b55cbd7d7dbb565 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/s5k4e1.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2013, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#define s5k4e1_SENSOR_NAME "s5k4e1" +DEFINE_MSM_MUTEX(s5k4e1_mut); + +static struct msm_sensor_ctrl_t s5k4e1_s_ctrl; + +static struct msm_sensor_power_setting s5k4e1_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 1, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 30, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 24000000, + .delay = 1, + }, + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 1, + }, +}; + +static struct v4l2_subdev_info s5k4e1_subdev_info[] = { + { + .code = V4L2_MBUS_FMT_SGRBG10_1X10, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, +}; + +static const struct i2c_device_id s5k4e1_i2c_id[] = { + {s5k4e1_SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl}, + { } +}; + +static int32_t msm_s5k4e1_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return msm_sensor_i2c_probe(client, id, &s5k4e1_s_ctrl); +} + +static struct i2c_driver s5k4e1_i2c_driver = { + .id_table = s5k4e1_i2c_id, + .probe = msm_s5k4e1_i2c_probe, + .driver = { + .name = s5k4e1_SENSOR_NAME, + }, +}; + +static struct msm_camera_i2c_client s5k4e1_sensor_i2c_client = { + .addr_type = MSM_CAMERA_I2C_WORD_ADDR, +}; + +static const struct of_device_id s5k4e1_dt_match[] = { + {.compatible = "shinetech,s5k4e1", .data = &s5k4e1_s_ctrl}, + {} +}; + +MODULE_DEVICE_TABLE(of, s5k4e1_dt_match); + +static struct platform_driver s5k4e1_platform_driver = { + .driver = { + .name = "shinetech,s5k4e1", + .owner = THIS_MODULE, + .of_match_table = s5k4e1_dt_match, + }, +}; + +static int32_t s5k4e1_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + const struct of_device_id *match; + match = of_match_device(s5k4e1_dt_match, &pdev->dev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init s5k4e1_init_module(void) +{ + int32_t rc = 0; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&s5k4e1_platform_driver, + s5k4e1_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&s5k4e1_i2c_driver); +} + +static void __exit s5k4e1_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (s5k4e1_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&s5k4e1_s_ctrl); + platform_driver_unregister(&s5k4e1_platform_driver); + } else + i2c_del_driver(&s5k4e1_i2c_driver); + return; +} + +static struct msm_sensor_ctrl_t s5k4e1_s_ctrl = { + .sensor_i2c_client = &s5k4e1_sensor_i2c_client, + .power_setting_array.power_setting = s5k4e1_power_setting, + .power_setting_array.size = ARRAY_SIZE(s5k4e1_power_setting), + .msm_sensor_mutex = &s5k4e1_mut, + .sensor_v4l2_subdev_info = s5k4e1_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k4e1_subdev_info), +}; + +module_init(s5k4e1_init_module); +module_exit(s5k4e1_exit_module); +MODULE_DESCRIPTION("s5k4e1"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/sp1628.c b/drivers/media/platform/msm/camera_v2_j5/sensor/sp1628.c new file mode 100755 index 0000000000000000000000000000000000000000..6cd06582fb36723e68d38861bd33ea5374480dbd --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/sp1628.c @@ -0,0 +1,992 @@ +/* Copyright (c) 2011-2014, The Linux Foundation. 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 and + * only 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 "msm_sensor.h" +#include "msm_cci.h" +#include "msm_camera_io_util.h" + +#define CONFIG_MSMB_CAMERA_DEBUG + +#undef CDBG +#ifdef CONFIG_MSMB_CAMERA_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) do { } while (0) +#endif + +#define SP1628_SENSOR_NAME "sp1628" +DEFINE_MSM_MUTEX(sp1628_mut); + +static struct msm_sensor_ctrl_t sp1628_s_ctrl; + +static struct msm_sensor_power_setting sp1628_power_setting[] = { + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VDIG, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VIO, + .config_val = 0, + .delay = 0, + }, + { + .seq_type = SENSOR_VREG, + .seq_val = CAM_VANA, + .config_val = 0, + .delay = 5, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_HIGH, + .delay = 50, + }, + + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 50, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_LOW, + .delay = 50, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_RESET, + .config_val = GPIO_OUT_HIGH, + .delay = 50, + }, + { + .seq_type = SENSOR_GPIO, + .seq_val = SENSOR_GPIO_STANDBY, + .config_val = GPIO_OUT_LOW, + .delay = 50, + }, + { + .seq_type = SENSOR_CLK, + .seq_val = SENSOR_CAM_MCLK, + .config_val = 0, + .delay = 1, + }, + + { + .seq_type = SENSOR_I2C_MUX, + .seq_val = 0, + .config_val = 0, + .delay = 5, + }, +}; + +static struct msm_camera_i2c_reg_conf sp1628_start_settings[] = { + {0x92, 0x81}, +}; + +static struct msm_camera_i2c_reg_conf sp1628_stop_settings[] = { + {0x92, 0x01}, +}; + +static struct msm_camera_i2c_reg_conf sp1628_recommend_settings[] = { + {0xfd, 0x00,}, + {0x91, 0x00,}, + {0x92, 0x81,}, + {0x98, 0x2a,}, + {0x96, 0xd0,}, /* c0*/ + {0x97, 0x02,}, /* 03*/ + {0x2f, 0x20,}, /* 24M*3=72M*/ + {0x0b, 0x48,}, /* analog*/ + {0x30, 0x80,}, /* 00*/ + {0x0c, 0x66,}, /* analog*/ + {0x0d, 0x12,}, + {0x13, 0x0f,}, /* 10*/ + {0x14, 0x00,}, + {0x12, 0x00,}, + {0x6b, 0x10,}, /* 11*/ + {0x6c, 0x00,}, + {0x6d, 0x00,}, + {0x6e, 0x00,}, + {0x6f, 0x10,}, /* 11*/ + {0x73, 0x11,}, /* 12*/ + {0x7a, 0x10,}, /* 11*/ + {0x15, 0x17,}, /* 18*/ + {0x71, 0x18,}, /* 19*/ + {0x76, 0x18,}, /* 19*/ + {0x29, 0x08,}, + {0x18, 0x01,}, + {0x19, 0x10,}, + {0x1a, 0xc3,}, /* c1*/ + {0x1b, 0x6f,}, + {0x1d, 0x11,}, /* 01*/ + {0x1e, 0x00,}, /* 1e*/ + {0x1f, 0x80,}, + {0x20, 0x7f,}, + {0x22, 0x3c,}, /* 1b*/ + {0x25, 0xff,}, + {0x2b, 0x88,}, + {0x2c, 0x85,}, + {0x2d, 0x00,}, + {0x2e, 0x80,}, + {0x27, 0x38,}, + {0x28, 0x03,}, + {0x70, 0x1a,}, + {0x72, 0x18,}, /* 1a*/ + {0x74, 0x18,}, + {0x75, 0x18,}, + {0x77, 0x16,}, /* 18*/ + {0x7f, 0x19,}, + {0x31, 0x11,}, /* 720P, no mirror/flip */ + {0xfd, 0x01,}, + {0x5d, 0x11,}, /* position*/ + {0x5f, 0x00,}, + {0x36, 0x08,}, + {0x2f, 0xff,}, + {0xfb, 0x25,}, /* blacklevl*/ + {0x48, 0x00,}, /* dp*/ + {0x49, 0x99,}, + {0xf2, 0x0A,}, + {0xfd, 0x02,}, /* AE*/ + {0x52, 0x34,}, + {0x53, 0x02,}, + {0x54, 0x0c,}, + {0x55, 0x08,}, + {0x86, 0x0c,}, + {0x87, 0x10,}, + {0x8b, 0x10,}, + + /* 12-30 50Hz*/ + {0xfd, 0x00,}, /* ae setting*/ + {0x03, 0x05,}, + {0x04, 0x64,}, + {0x05, 0x00,}, + {0x06, 0x00,}, + {0x09, 0x00,}, + {0x0a, 0x02,}, + {0xfd, 0x01,}, + {0xf0, 0x00,}, + {0xf7, 0xe6,}, + {0xf8, 0xc1,}, + {0x02, 0x08,}, + {0x03, 0x01,}, + {0x06, 0xe6,}, + {0x07, 0x00,}, + {0x08, 0x01,}, + {0x09, 0x00,}, + {0xfd, 0x02,}, + {0x40, 0x0a,}, + {0x41, 0xc1,}, + {0x42, 0x00,}, + {0x88, 0x37,}, + {0x89, 0xa7,}, + {0x8a, 0x22,}, + {0xfd, 0x02,}, /* Status*/ + {0xbe, 0x30,}, + {0xbf, 0x07,}, + {0xd0, 0x30,}, + {0xd1, 0x07,}, + {0xfd, 0x01,}, + {0x5b, 0x07,}, + {0x5c, 0x30,}, + {0xfd, 0x00,}, + + /* 12-30 60Hz*/ + {0xfd, 0x00,}, /* ae setting*/ + {0x03, 0x04,}, + {0x04, 0x80,}, + {0x05, 0x00,}, + {0x06, 0x00,}, + {0x09, 0x00,}, + {0x0a, 0x01,}, + {0xfd, 0x01,}, + {0xf0, 0x00,}, + {0xf7, 0xc0,}, + {0xf8, 0xc1,}, + {0x02, 0x0a,}, + {0x03, 0x01,}, + {0x06, 0xc0,}, + {0x07, 0x00,}, + {0x08, 0x01,}, + {0x09, 0x00,}, + {0xfd, 0x02,}, + {0x40, 0x0a,}, + {0x41, 0xc1,}, + {0x42, 0x00,}, + {0x88, 0x37,}, + {0x89, 0xa7,}, + {0x8a, 0x22,}, + {0xfd, 0x02,}, /* Status*/ + {0xbe, 0x80,}, + {0xbf, 0x07,}, + {0xd0, 0x80,}, + {0xd1, 0x07,}, + {0xfd, 0x01,}, + {0x5b, 0x07,}, + {0x5c, 0x80,}, + {0xfd, 0x00,}, + + {0xfd, 0x01,}, /* fix status*/ + {0x5a, 0x38,}, /* DP_gain*/ + {0xfd, 0x02,}, + {0xba, 0x30,}, /* mean_dummy_low*/ + {0xbb, 0x50,}, /* mean_low_dummy*/ + {0xbc, 0xc0,}, /* rpc_heq_low*/ + {0xbd, 0xa0,}, /* rpc_heq_dummy*/ + {0xb8, 0x80,}, /* mean_nr_dummy*/ + {0xb9, 0x90,}, /* mean_dummy_nr*/ + {0xfd, 0x01,}, /* rpc*/ + {0xe0, 0x54,}, + {0xe1, 0x40,}, + {0xe2, 0x38,}, + {0xe3, 0x34,}, + {0xe4, 0x34,}, + {0xe5, 0x30,}, + {0xe6, 0x30,}, + {0xe7, 0x2e,}, + {0xe8, 0x2e,}, + {0xe9, 0x2e,}, + {0xea, 0x2c,}, + {0xf3, 0x2c,}, + {0xf4, 0x2c,}, + {0xfd, 0x01,}, /* min gain*/ + {0x04, 0xc0,}, /* rpc_max_indr*/ + {0x05, 0x2c,}, /* rpc_min_indr*/ + {0x0a, 0xc0,}, /* rpc_max_outdr*/ + {0x0b, 0x2c,}, /* rpc_min_outdr*/ + {0xfd, 0x01,}, /* ae target*/ + {0xeb, 0x78,}, + {0xec, 0x78,}, + {0xed, 0x05,}, + {0xee, 0x0a,}, + {0xfd, 0x01,}, /* lsc*/ + {0x26, 0x30,}, + {0x27, 0xdc,}, + {0x28, 0x05,}, + {0x29, 0x08,}, + {0x2a, 0x00,}, + {0x2b, 0x03,}, + {0x2c, 0x00,}, + {0x2d, 0x2f,}, + {0xfd, 0x01,}, /* RGainf*/ + {0xa1, 0x37,}, /* left*/ + {0xa2, 0x26,}, /* right*/ + {0xa3, 0x32,}, /* up*/ + {0xa4, 0x2b,}, /* down*/ + {0xad, 0x0f,}, /* lu*/ + {0xae, 0x0a,}, /* ru*/ + {0xaf, 0x0a,}, /* ld*/ + {0xb0, 0x0a,}, /* rd*/ + {0x18, 0x2f,}, /* left*/ + {0x19, 0x30,}, /* right*/ + {0x1a, 0x32,}, /* up*/ + {0x1b, 0x30,}, /* down*/ + {0xbf, 0xa5,}, /* lu*/ + {0xc0, 0x12,}, /* ru*/ + {0xc1, 0x08,}, /* ld*/ + {0xfa, 0x00,}, /* rd*/ + {0xa5, 0x35,}, /* GGain*/ + {0xa6, 0x24,}, + {0xa7, 0x2e,}, + {0xa8, 0x25,}, + {0xb1, 0x00,}, + {0xb2, 0x04,}, + {0xb3, 0x00,}, + {0xb4, 0x00,}, + {0x1c, 0x24,}, + {0x1d, 0x23,}, + {0x1e, 0x2c,}, + {0xb9, 0x25,}, + {0x21, 0xa0,}, + {0x22, 0x13,}, + {0x23, 0x1c,}, + {0x24, 0x0d,}, + {0xa9, 0x2f,}, /* BGain*/ + {0xaa, 0x24,}, + {0xab, 0x2d,}, + {0xac, 0x24,}, + {0xb5, 0x00,}, + {0xb6, 0x00,}, + {0xb7, 0x00,}, + {0xb8, 0x00,}, + {0xba, 0x22,}, + {0xbc, 0x24,}, + {0xbd, 0x31,}, + {0xbe, 0x24,}, + {0x25, 0xa0,}, + {0x45, 0x08,}, + {0x46, 0x12,}, + {0x47, 0x09,}, + {0xfd, 0x01,}, /* awb*/ + {0x32, 0x15,}, + {0xfd, 0x02,}, + {0x26, 0xc9,}, + {0x27, 0x8b,}, + {0x1b, 0x80,}, + {0x1a, 0x80,}, + {0x18, 0x27,}, + {0x19, 0x26,}, + {0x2a, 0x01,}, + {0x2b, 0x10,}, + {0x28, 0xf8,}, + {0x29, 0x08,}, + + /* d65*/ + {0x66, 0x35,}, + {0x67, 0x60,}, + {0x68, 0xb0,}, + {0x69, 0xe0,}, + {0x6a, 0xa5,}, + + /* indoor*/ + {0x7c, 0x38,}, + {0x7d, 0x58,}, + {0x7e, 0xdb,}, + {0x7f, 0x13,}, + {0x80, 0xa6,}, + + /* cwftl84*/ + {0x70, 0x18,}, /* 2f*/ + {0x71, 0x4a,}, + {0x72, 0x08,}, + {0x73, 0x32,}, /* 24*/ + {0x74, 0xaa,}, + + /* tl84--F*/ + {0x6b, 0x02,}, /* 18*/ + {0x6c, 0x2a,}, /* 34*/ + {0x6d, 0x1e,}, /* 17*/ + {0x6e, 0x49,}, /* 32*/ + {0x6f, 0xaa,}, + + /* f--H*/ + {0x61, 0xea,}, /* 02*/ + {0x62, 0xf8,}, /* 2a*/ + {0x63, 0x4f,}, /* 1e*/ + {0x64, 0x5f,}, /* 49*/ + {0x65, 0x5a,}, /* aa*/ + + {0x75, 0x80,}, + {0x76, 0x09,}, + {0x77, 0x02,}, + {0x24, 0x25,}, + {0x0e, 0x16,}, + {0x3b, 0x09,}, + {0xfd, 0x02,}, /* sharp*/ + {0xde, 0x0f,}, + {0xd2, 0x0c,}, /* control black-white edge; 0 - bolder, f - thinner*/ + {0xd3, 0x0a,}, + {0xd4, 0x08,}, + {0xd5, 0x08,}, + {0xd7, 0x10,}, /* outline judgement*/ + {0xd8, 0x1d,}, + {0xd9, 0x32,}, + {0xda, 0x48,}, + {0xdb, 0x08,}, + {0xe8, 0x38,}, /* outline strength*/ + {0xe9, 0x38,}, + {0xea, 0x38,}, /* 30*/ + {0xeb, 0x38,}, /* 2*/ + {0xec, 0x60,}, + {0xed, 0x40,}, + {0xee, 0x38,}, /* 30*/ + {0xef, 0x38,}, /* 20*/ + {0xf3, 0x00,}, /* sharpness level of flat area*/ + {0xf4, 0x00,}, + {0xf5, 0x00,}, + {0xf6, 0x00,}, + {0xfd, 0x02,}, /* skin sharpen*/ + {0xdc, 0x04,}, /* skin de-sharpen*/ + {0x05, 0x6f,}, + {0x09, 0x10,}, + {0xfd, 0x01,}, /* dns*/ + {0x64, 0x22,}, /* 0 - max, 8 - min*/ + {0x65, 0x22,}, + {0x86, 0x20,}, /* threshold, 0 - min*/ + {0x87, 0x20,}, + {0x88, 0x20,}, + {0x89, 0x20,}, + {0x6d, 0x0f,}, + {0x6e, 0x0f,}, + {0x6f, 0x10,}, + {0x70, 0x10,}, + {0x71, 0x0d,}, + {0x72, 0x23,}, + {0x73, 0x23,}, /* 28*/ + {0x74, 0x23,}, /* 2a*/ + {0x75, 0x46,}, /* [7:4] strength of flat area, + [3:0]strength of un-flat area; + 0-max, 8-min*/ + {0x76, 0x36,}, + {0x77, 0x36,}, /* 25*/ + {0x78, 0x36,}, /* 12*/ + {0x81, 0x1d,}, /* 2x*/ + {0x82, 0x2b,}, /* 4x*/ + {0x83, 0x2b,}, /* 50; 8x*/ + {0x84, 0x2b,}, /* 80; 16x*/ + {0x85, 0x0a,}, /* 12/8reg0x81*/ + {0xfd, 0x01,}, /* gamma*/ + {0x8b, 0x00,}, /* 00; 00; 00;*/ + {0x8c, 0x0d,}, /* 02; 0b; 0b;*/ + {0x8d, 0x1f,}, /* 0a; 19; 17;*/ + {0x8e, 0x2d,}, /* 13; 2a; 27;*/ + {0x8f, 0x3a,}, /* 1d; 37; 35;*/ + {0x90, 0x4b,}, /* 30; 4b; 51;*/ + {0x91, 0x59,}, /* 40; 5e; 64;*/ + {0x92, 0x64,}, /* 4e; 6c; 74;*/ + {0x93, 0x70,}, /* 5a; 78; 80;*/ + {0x94, 0x83,}, /* 71; 92; 92;*/ + {0x95, 0x92,}, /* 85; a6; a2;*/ + {0x96, 0xa1,}, /* 96; b5; af;*/ + {0x97, 0xae,}, /* a6; bf; bb;*/ + {0x98, 0xba,}, /* b3; ca; c6;*/ + {0x99, 0xc4,}, /* c0; d2; d0;*/ + {0x9a, 0xcf,}, /* cb; d9; d9;*/ + {0x9b, 0xdb,}, /* d5; e1; e0;*/ + {0x9c, 0xe5,}, /* df; e8; e8;*/ + {0x9d, 0xec,}, /* e9; ee; ee;*/ + {0x9e, 0xf3,}, /* f2; f4; f4;*/ + {0x9f, 0xfa,}, /* fa; fa; fa;*/ + {0xa0, 0xff,}, /* ff; ff; ff;*/ + {0xfd, 0x02,}, /* CCM*/ + {0x15, 0xc8,}, /* b>th ab*/ + {0x16, 0x95,}, /* rdev); + rc = msm_sensor_platform_probe(pdev, match->data); + return rc; +} + +static int __init sp1628_init_module(void) +{ + int32_t rc; + pr_info("%s:%d\n", __func__, __LINE__); + rc = platform_driver_probe(&sp1628_platform_driver, + sp1628_platform_probe); + if (!rc) + return rc; + pr_err("%s:%d rc %d\n", __func__, __LINE__, rc); + return i2c_add_driver(&sp1628_i2c_driver); +} + +static void __exit sp1628_exit_module(void) +{ + pr_info("%s:%d\n", __func__, __LINE__); + if (sp1628_s_ctrl.pdev) { + msm_sensor_free_sensor_data(&sp1628_s_ctrl); + platform_driver_unregister(&sp1628_platform_driver); + } else + i2c_del_driver(&sp1628_i2c_driver); + return; +} + +int32_t sp1628_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__, + s_ctrl->sensordata->sensor_name, cdata->cfgtype); + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d sensor name %s\n", __func__, __LINE__, + cdata->cfg.sensor_info.sensor_name); + CDBG("%s:%d session id %d\n", __func__, __LINE__, + cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + CDBG("%s:%d mount angle valid %d value %d\n", __func__, + __LINE__, cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + /* Write Recommend settings */ + pr_err("%s, sensor write init setting!!", __func__); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, + sp1628_recommend_settings, + ARRAY_SIZE(sp1628_recommend_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_SET_RESOLUTION: + break; + case CFG_SET_STOP_STREAM: + pr_err("%s, sensor stop stream!!", __func__); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, + sp1628_stop_settings, + ARRAY_SIZE(sp1628_stop_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_SET_START_STREAM: + pr_err("%s, sensor start stream!!", __func__); + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_conf_tbl(s_ctrl->sensor_i2c_client, + sp1628_start_settings, + ARRAY_SIZE(sp1628_start_settings), + MSM_CAMERA_I2C_BYTE_DATA); + break; + case CFG_GET_SENSOR_INIT_PARAMS: + cdata->cfg.sensor_init_params.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + cdata->cfg.sensor_init_params.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_init_params.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__, + __LINE__, + cdata->cfg.sensor_init_params.modes_supported, + cdata->cfg.sensor_init_params.position, + cdata->cfg.sensor_init_params.sensor_mount_angle); + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_sensor_power_setting_array *power_setting_array; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + s_ctrl->power_setting_array = + sensor_slave_info.power_setting_array; + power_setting_array = &s_ctrl->power_setting_array; + power_setting_array->power_setting = kzalloc( + power_setting_array->size * + sizeof(struct msm_sensor_power_setting), GFP_KERNEL); + if (!power_setting_array->power_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(power_setting_array->power_setting, + (void *)sensor_slave_info.power_setting_array.power_setting, + power_setting_array->size * + sizeof(struct msm_sensor_power_setting))) { + kfree(power_setting_array->power_setting); + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + CDBG("%s sensor id %x\n", __func__, + sensor_slave_info.slave_addr); + CDBG("%s sensor addr type %d\n", __func__, + sensor_slave_info.addr_type); + CDBG("%s sensor reg %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("%s sensor id %x\n", __func__, + sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + power_setting_array->size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d\n", __func__, + slave_index, + power_setting_array->power_setting[slave_index]. + seq_type, + power_setting_array->power_setting[slave_index]. + seq_val, + power_setting_array->power_setting[slave_index]. + config_val, + power_setting_array->power_setting[slave_index]. + delay); + } + kfree(power_setting_array->power_setting); + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + if (s_ctrl->func_tbl->sensor_power_up) + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) + rc = s_ctrl->func_tbl->sensor_power_down( + s_ctrl); + else + rc = -EFAULT; + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + case CFG_SET_SATURATION: { + + break; + } + case CFG_SET_CONTRAST: { + + break; + } + case CFG_SET_SHARPNESS: { + + break; + } + case CFG_SET_ISO: { + + break; + } + case CFG_SET_EXPOSURE_COMPENSATION: { + + break; + } + case CFG_SET_EFFECT: { + + break; + } + case CFG_SET_ANTIBANDING: { + + break; + } + case CFG_SET_BESTSHOT_MODE: { + + break; + } + case CFG_SET_WHITE_BALANCE: { + + break; + } + default: + rc = -EFAULT; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + return rc; +} + +int32_t sp1628_match_id(struct msm_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + uint16_t chipid = 0; + + CDBG("%s, E. calling i2c_read:, i2c_addr:%d, id_reg_addr:%d", + __func__, + s_ctrl->sensordata->slave_info->sensor_slave_addr, + s_ctrl->sensordata->slave_info->sensor_id_reg_addr); + + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + 0x02, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x16:\n", __func__, chipid); + if (chipid != 0x16) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + + chipid = 0; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read( + s_ctrl->sensor_i2c_client, + 0xa0, + &chipid, MSM_CAMERA_I2C_BYTE_DATA); + if (rc < 0) { + pr_err("%s: %s: read id failed\n", __func__, + s_ctrl->sensordata->sensor_name); + return rc; + } + + CDBG("%s: read id: 0x%x expected id 0x28:\n", __func__, chipid); + if (chipid != 0x28) { + pr_err("msm_sensor_match_id chip id doesnot match\n"); + return -ENODEV; + } + + return rc; +} + + +static struct msm_sensor_fn_t sp1628_sensor_func_tbl = { + .sensor_config = sp1628_sensor_config, + .sensor_power_up = msm_sensor_power_up, + .sensor_power_down = msm_sensor_power_down, + .sensor_match_id = sp1628_match_id, +}; + +static struct msm_sensor_ctrl_t sp1628_s_ctrl = { + .sensor_i2c_client = &sp1628_sensor_i2c_client, + .power_setting_array.power_setting = sp1628_power_setting, + .power_setting_array.size = ARRAY_SIZE(sp1628_power_setting), + .msm_sensor_mutex = &sp1628_mut, + .sensor_v4l2_subdev_info = sp1628_subdev_info, + .sensor_v4l2_subdev_info_size = ARRAY_SIZE(sp1628_subdev_info), + .func_tbl = &sp1628_sensor_func_tbl, +}; + +module_init(sp1628_init_module); +module_exit(sp1628_exit_module); +MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20.h b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20.h new file mode 100755 index 0000000000000000000000000000000000000000..7a22c0b1b4ecca48fdc210c8f6406bd2c352ff66 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2011-2013, The Linux Foundation. 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 and + * only 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. + * + */ + +#ifndef __sr200pc20_H__ +#define __sr200pc20_H__ + +#include "msm_sensor.h" +#include "msm_sensor_driver.h" + +#undef sr200pc20_DEBUG +#undef CDBG +#define sr200pc20_DEBUG +#ifdef sr200pc20_DEBUG +#define CDBG(fmt, args...) printk("[sr200pc20] %s : %d : "fmt "\n", __FUNCTION__, __LINE__, ##args) +#endif + +int32_t sr200pc20_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp); +int32_t sr200pc20_sensor_native_control(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp); +#endif //__sr200pc20_H__ \ No newline at end of file diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv.c b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv.c new file mode 100755 index 0000000000000000000000000000000000000000..2ef0157b13b80f61143e351de3639cef706f32fb --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv.c @@ -0,0 +1,708 @@ +/* Copyright (c) 2011-2013, The Linux Foundation. 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 and + * only 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 "sr200pc20.h" +#if defined(CONFIG_SEC_ROSSA_PROJECT) +#include "sr200pc20_yuv_coreprime.h" +#else +#include "sr200pc20_yuv.h" +#endif +#include "msm_sd.h" +#include "camera.h" +#include "msm_cci.h" +#include "msm_camera_dt_util.h" + +#if defined CONFIG_SEC_CAMERA_TUNING +#define SR200PC20_WRITE_LIST(A) \ + if (front_tune) \ + register_read_from_sdcard(A,s_ctrl,MSM_CAMERA_I2C_BYTE_DATA,#A); \ + else \ + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_conf_tbl( \ + s_ctrl->sensor_i2c_client, A, ARRAY_SIZE(A), \ + MSM_CAMERA_I2C_BYTE_DATA); CDBG("REGSEQ *** %s", #A) +#else +#define SR200PC20_WRITE_LIST(A) \ + s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_conf_tbl( \ + s_ctrl->sensor_i2c_client, A, ARRAY_SIZE(A), \ + MSM_CAMERA_I2C_BYTE_DATA); CDBG("REGSEQ *** %s", #A) +#endif + +static struct yuv_ctrl sr200pc20_ctrl; +static exif_data_t sr200pc20_exif; +#if defined(CONFIG_SEC_ROSSA_PROJECT) +bool init_setting_write = FALSE; +#endif + +#if defined CONFIG_SEC_CAMERA_TUNING +#if defined(CONFIG_SEC_ROSSA_PROJECT) +#define FILENAME "/data/sr200pc20_yuv_coreprime.h" +#else +#define FILENAME "/data/sr200pc20_yuv.h" +#endif +extern int register_read_from_sdcard (struct msm_camera_i2c_reg_conf *settings, + struct msm_sensor_ctrl_t *s_ctrl, + enum msm_camera_i2c_data_type data_type, + char *name); +extern int register_table_init(char *filename); +extern void register_table_exit(void); +extern int front_tune; +#endif +static int32_t streamon = 0; +static int32_t recording = 0; +static int32_t resolution = MSM_SENSOR_RES_FULL; + +static int sr200pc20_exif_shutter_speed(struct msm_sensor_ctrl_t *s_ctrl) +{ + u16 read_value1 = 0; + u16 read_value2 = 0; + u16 read_value3 = 0; + int OPCLK = 26000000; + int rc = 0; + + /* Exposure Time */ + s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write(s_ctrl->sensor_i2c_client, 0x03,0x20,MSM_CAMERA_I2C_BYTE_DATA); + s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_read(s_ctrl->sensor_i2c_client, 0x80,&read_value1,MSM_CAMERA_I2C_BYTE_DATA); + s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_read(s_ctrl->sensor_i2c_client, 0x81,&read_value2,MSM_CAMERA_I2C_BYTE_DATA); + s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_read(s_ctrl->sensor_i2c_client, 0x82,&read_value3,MSM_CAMERA_I2C_BYTE_DATA); + if(read_value1 == 0 && read_value2 == 0 && read_value3 == 0) + { + pr_err("%s::%d read_value1=%d read_value2=%d read_value3=%d " + ,__func__,__LINE__,read_value1,read_value2,read_value3); + rc = -EFAULT; + } + else + { + sr200pc20_exif.shutterspeed = OPCLK / ((read_value1 << 19) + + (read_value2 << 11) + (read_value3 << 3)); + CDBG("Exposure time = %d", sr200pc20_exif.shutterspeed); + } + return rc; +} + +static int sr200pc20_exif_iso(struct msm_sensor_ctrl_t *s_ctrl) +{ + u16 read_value4 = 0; + unsigned short gain_value; + + /* ISO*/ + s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write(s_ctrl->sensor_i2c_client, 0x03,0x20,MSM_CAMERA_I2C_BYTE_DATA); + s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_read(s_ctrl->sensor_i2c_client, 0xb0,&read_value4,MSM_CAMERA_I2C_BYTE_DATA); + + gain_value = (read_value4 / 32) * 1000 +500; + if (gain_value < 1140) + sr200pc20_exif.iso = 50; + else if (gain_value < 2140) + sr200pc20_exif.iso = 100; + else if (gain_value < 2640) + sr200pc20_exif.iso = 200; + else if (gain_value < 7520) + sr200pc20_exif.iso = 400; + else + sr200pc20_exif.iso = 800; + + CDBG("ISO = %d", sr200pc20_exif.iso); + + return 0; +} + +void sr200pc20_get_exif(struct msm_sensor_ctrl_t *s_ctrl) +{ + CDBG("E"); + + /*Exif data*/ + sr200pc20_exif_shutter_speed(s_ctrl); + sr200pc20_exif_iso(s_ctrl); + CDBG("exp_time : %d -- iso_value : %d",sr200pc20_exif.shutterspeed, sr200pc20_exif.iso); + return; +} + +int32_t sr200pc20_get_exif_info(struct ioctl_native_cmd * exif_info) +{ + exif_info->value_1 = 1; // equals 1 to update the exif value in the user level. + exif_info->value_2 = sr200pc20_exif.iso; + exif_info->value_3 = sr200pc20_exif.shutterspeed; + return 0; +} + +int32_t sr200pc20_set_exposure_compensation(struct msm_sensor_ctrl_t *s_ctrl, int mode) +{ + int32_t rc = 0; + CDBG("CAM-SETTING -- EV is %d", mode); + switch (mode) { + case CAMERA_EV_M4: + SR200PC20_WRITE_LIST(sr200pc20_brightness_M4); + break; + case CAMERA_EV_M3: + SR200PC20_WRITE_LIST(sr200pc20_brightness_M3); + break; + case CAMERA_EV_M2: + SR200PC20_WRITE_LIST(sr200pc20_brightness_M2); + break; + case CAMERA_EV_M1: + SR200PC20_WRITE_LIST(sr200pc20_brightness_M1); + break; + case CAMERA_EV_DEFAULT: + SR200PC20_WRITE_LIST(sr200pc20_brightness_default); + break; + case CAMERA_EV_P1: + SR200PC20_WRITE_LIST(sr200pc20_brightness_P1); + break; + case CAMERA_EV_P2: + SR200PC20_WRITE_LIST(sr200pc20_brightness_P2); + break; + case CAMERA_EV_P3: + SR200PC20_WRITE_LIST(sr200pc20_brightness_P3); + break; + case CAMERA_EV_P4: + SR200PC20_WRITE_LIST(sr200pc20_brightness_P4); + break; + default: + CDBG("Setting %d is invalid", mode); + rc = 0; + } + return rc; +} + +int32_t sr200pc20_set_white_balance(struct msm_sensor_ctrl_t *s_ctrl, int mode) +{ + int32_t rc = 0; + CDBG("CAM-SETTING -- WB is %d", mode); + switch (mode) { + case CAMERA_WHITE_BALANCE_OFF: + case CAMERA_WHITE_BALANCE_AUTO: + SR200PC20_WRITE_LIST(sr200pc20_WB_Auto); + break; + case CAMERA_WHITE_BALANCE_INCANDESCENT: + SR200PC20_WRITE_LIST(sr200pc20_WB_Incandescent); + break; + case CAMERA_WHITE_BALANCE_FLUORESCENT: + SR200PC20_WRITE_LIST(sr200pc20_WB_Fluorescent); + break; + case CAMERA_WHITE_BALANCE_DAYLIGHT: + SR200PC20_WRITE_LIST(sr200pc20_WB_Daylight); + break; + case CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT: + SR200PC20_WRITE_LIST(sr200pc20_WB_Cloudy); + break; + default: + CDBG("%s: Setting %d is invalid", __func__, mode); + rc = 0; + } + return rc; +} + +int32_t sr200pc20_set_resolution(struct msm_sensor_ctrl_t *s_ctrl, int mode, int flicker_type) +{ + int32_t rc = 0; + CDBG("CAM-SETTING-- resolution is %d", mode); + switch (mode) { + case MSM_SENSOR_RES_FULL: + SR200PC20_WRITE_LIST(sr200pc20_Capture); + sr200pc20_get_exif(s_ctrl); + break; + default: +#if defined(CONFIG_SEC_ROSSA_PROJECT) + if (init_setting_write) { + if (flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz Preview initial\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_640x480_Preview_for_initial_50hz); + } else { + pr_err("%s : %d 60Hz Preview initial\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_640x480_Preview_for_initial_60hz); + } + init_setting_write = FALSE; + }else { + if (flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz Preview initial\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_640x480_Preview_for_Return_50hz); + } else { + pr_err("%s : %d 60Hz Preview initial\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_640x480_Preview_for_Return_60hz); + } + } +#else + if (mode == MSM_SENSOR_RES_QTR) { + if (flicker_type == MSM_CAM_FLICKER_50HZ) { + SR200PC20_WRITE_LIST(sr200pc20_800x600_Preview_for_Return_50hz); + } else { + SR200PC20_WRITE_LIST(sr200pc20_800x600_Preview_for_Return_60hz); + } + } +#endif +#if 0 + else if (mode == MSM_SENSOR_RES_2) { + if (flicker_type == MSM_CAM_FLICKER_50HZ) { + SR200PC20_WRITE_LIST(sr200pc20_640x480_Preview_for_Return_50hz); + } else { + SR200PC20_WRITE_LIST(sr200pc20_640x480_Preview_for_Return_60hz); + } + } +#endif + //rc = msm_sensor_driver_WRT_LIST(s_ctrl,sr200pc20_800x600_Preview); + pr_err("%s: Setting %d is invalid\n", __func__, mode); + rc=0; + } + return rc; +} + +int32_t sr200pc20_set_effect(struct msm_sensor_ctrl_t *s_ctrl, int mode) +{ + int32_t rc = 0; + CDBG("CAM-SETTING-- effect is %d", mode); + switch (mode) { + case CAMERA_EFFECT_OFF: + SR200PC20_WRITE_LIST(sr200pc20_Effect_Normal); + break; + case CAMERA_EFFECT_MONO: + SR200PC20_WRITE_LIST(sr200pc20_Effect_Gray); + break; + case CAMERA_EFFECT_NEGATIVE: + SR200PC20_WRITE_LIST(sr200pc20_Effect_Negative); + break; + case CAMERA_EFFECT_SEPIA: + SR200PC20_WRITE_LIST(sr200pc20_Effect_Sepia); + break; + default: + pr_err("%s: Setting %d is invalid\n", __func__, mode); + } + return rc; +} + +int32_t sr200pc20_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp; + int32_t rc = 0; + int32_t i = 0; + mutex_lock(s_ctrl->msm_sensor_mutex); + + CDBG("ENTER %d", cdata->cfgtype); + + switch (cdata->cfgtype) { + case CFG_GET_SENSOR_INFO: + CDBG(" CFG_GET_SENSOR_INFO"); + memcpy(cdata->cfg.sensor_info.sensor_name, + s_ctrl->sensordata->sensor_name, + sizeof(cdata->cfg.sensor_info.sensor_name)); + cdata->cfg.sensor_info.session_id = + s_ctrl->sensordata->sensor_info->session_id; + for (i = 0; i < SUB_MODULE_MAX; i++) + cdata->cfg.sensor_info.subdev_id[i] = + s_ctrl->sensordata->sensor_info->subdev_id[i]; + + + cdata->cfg.sensor_info.is_mount_angle_valid = + s_ctrl->sensordata->sensor_info->is_mount_angle_valid; + cdata->cfg.sensor_info.sensor_mount_angle = + s_ctrl->sensordata->sensor_info->sensor_mount_angle; + cdata->cfg.sensor_info.position = + s_ctrl->sensordata->sensor_info->position; + cdata->cfg.sensor_info.modes_supported = + s_ctrl->sensordata->sensor_info->modes_supported; + + CDBG("sensor name %s", cdata->cfg.sensor_info.sensor_name); + CDBG("session id %d", cdata->cfg.sensor_info.session_id); + for (i = 0; i < SUB_MODULE_MAX; i++) + CDBG("%s:%d subdev_id[%d] %d", __func__, __LINE__, i, + cdata->cfg.sensor_info.subdev_id[i]); + + CDBG("mount angle valid %d value %d", cdata->cfg.sensor_info.is_mount_angle_valid, + cdata->cfg.sensor_info.sensor_mount_angle); + + break; + case CFG_SET_INIT_SETTING: + sr200pc20_ctrl.vtcall_mode = 0; + CDBG("CFG_SET_INIT_SETTING writing INIT registers: sr200pc20_Init_Reg \n"); +#if defined(CONFIG_SEC_ROSSA_PROJECT) + init_setting_write = TRUE; +#endif + if (cdata->flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz init setting\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Init_Reg_50hz); + } else { + pr_err("%s : %d 60Hz init setting\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Init_Reg_60hz); + } + +#ifdef CONFIG_SEC_CAMERA_TUNING + if (front_tune){ + register_table_init(FILENAME); + pr_err("/data/sr200pc20_yuv.h inside CFG_SET_INIT_SETTING"); + } +#endif + break; + case CFG_SET_RESOLUTION: + resolution = *((int32_t *)cdata->cfg.setting); + if (sr200pc20_ctrl.prev_mode == CAMERA_MODE_INIT) { + if (sr200pc20_ctrl.vtcall_mode) { + if (cdata->flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz VT init setting\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_VT_Init_Reg_50Hz); + } else { + pr_err("%s : %d 60Hz VT init setting\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_VT_Init_Reg_60Hz); + } + }else { +#if 0 + if (cdata->flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz init setting\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Init_Reg_50hz); + } else { + pr_err("%s : %d 60Hz init setting\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Init_Reg_60hz); + } +#endif + CDBG("Init settings"); + } + } + CDBG("CFG_SET_RESOLUTION *** res = %d" , resolution); + if( sr200pc20_ctrl.op_mode == CAMERA_MODE_RECORDING ) { + //sr200pc20_set_resolution(s_ctrl , resolution , cdata->flicker_type); + if (cdata->flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz 24fps camcorder\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_24fps_Camcoder_50hz); + } else { + pr_err("%s : %d 60Hz 24fps camcorder\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_24fps_Camcoder_60hz); + } +#if 0 + CDBG("CFG_SET_RESOLUTION recording START recording =1 *** res = %d" , resolution); + if (cdata->flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz Auto fps\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Auto_fps_50hz); + } else { + pr_err("%s : %d 60Hz Auto fps\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Auto_fps_60hz); + } + +#endif + sr200pc20_set_effect( s_ctrl , sr200pc20_ctrl.settings.effect); + sr200pc20_set_white_balance( s_ctrl, sr200pc20_ctrl.settings.wb); + sr200pc20_set_exposure_compensation( s_ctrl , sr200pc20_ctrl.settings.exposure); + recording = 1; + }else{ + if(recording == 1){ + CDBG("CFG_SET_RESOLUTION recording STOP recording =1 *** res = %d" , resolution); + //sr200pc20_set_resolution(s_ctrl , resolution , cdata->flicker_type); + + if (cdata->flicker_type == MSM_CAM_FLICKER_50HZ) { + pr_err("%s : %d 50Hz Auto fps\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Auto_fps_50hz); + } else { + pr_err("%s : %d 60Hz Auto fps\n", __func__, __LINE__); + SR200PC20_WRITE_LIST(sr200pc20_Auto_fps_60hz); + } + sr200pc20_set_effect( s_ctrl , sr200pc20_ctrl.settings.effect); + sr200pc20_set_white_balance( s_ctrl, sr200pc20_ctrl.settings.wb); + sr200pc20_set_exposure_compensation( s_ctrl , sr200pc20_ctrl.settings.exposure); + sr200pc20_set_resolution(s_ctrl , resolution , cdata->flicker_type); + recording = 0; + }else if( sr200pc20_ctrl.prev_mode == CAMERA_MODE_INIT ){ + sr200pc20_set_effect( s_ctrl , sr200pc20_ctrl.settings.effect); + sr200pc20_set_white_balance( s_ctrl, sr200pc20_ctrl.settings.wb); + sr200pc20_set_exposure_compensation( s_ctrl , sr200pc20_ctrl.settings.exposure); + sr200pc20_set_resolution(s_ctrl , resolution , cdata->flicker_type); + CDBG("CFG_SET_RESOLUTION END *** res = %d" , resolution); + } else{ + sr200pc20_set_resolution(s_ctrl , resolution , cdata->flicker_type); + CDBG("CFG_SET_RESOLUTION END *** res = %d" , resolution); + } + } + break; + + case CFG_SET_STOP_STREAM: + CDBG("CFG_SET_STOP_STREAM"); + if(streamon == 1){ + SR200PC20_WRITE_LIST(sr200pc20_stop_stream); + rc=0; + streamon = 0; + } + break; + case CFG_SET_START_STREAM: + CDBG(" CFG_SET_START_STREAM"); +#if 0 + if( sr200pc20_ctrl.op_mode != CAMERA_MODE_CAPTURE){ + sr200pc20_set_effect( s_ctrl , sr200pc20_ctrl.settings.effect); + sr200pc20_set_white_balance( s_ctrl, sr200pc20_ctrl.settings.wb); + sr200pc20_set_exposure_compensation( s_ctrl , sr200pc20_ctrl.settings.exposure); + } +#endif + streamon = 1; + break; + case CFG_SET_SLAVE_INFO: { + struct msm_camera_sensor_slave_info sensor_slave_info; + struct msm_camera_power_ctrl_t *p_ctrl; + uint16_t size; + int slave_index = 0; + if (copy_from_user(&sensor_slave_info, + (void *)cdata->cfg.setting, + sizeof(sensor_slave_info))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + /* Update sensor slave address */ + if (sensor_slave_info.slave_addr) { + s_ctrl->sensor_i2c_client->cci_client->sid = + sensor_slave_info.slave_addr >> 1; + } + + /* Update sensor address type */ + s_ctrl->sensor_i2c_client->addr_type = + sensor_slave_info.addr_type; + + /* Update power up / down sequence */ + p_ctrl = &s_ctrl->sensordata->power_info; + size = sensor_slave_info.power_setting_array.size; + if (p_ctrl->power_setting_size < size) { + struct msm_sensor_power_setting *tmp; + tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL); + if (!tmp) { + pr_err("%s: failed to alloc mem\n", __func__); + rc = -ENOMEM; + break; + } + kfree(p_ctrl->power_setting); + p_ctrl->power_setting = tmp; + } + p_ctrl->power_setting_size = size; + rc = copy_from_user(p_ctrl->power_setting, (void *) + sensor_slave_info.power_setting_array.power_setting, + size * sizeof(struct msm_sensor_power_setting)); + if (rc) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(sensor_slave_info.power_setting_array. + power_setting); + rc = -EFAULT; + break; + } + CDBG("sensor id %x", sensor_slave_info.slave_addr); + CDBG("sensor addr type %d", sensor_slave_info.addr_type); + CDBG("sensor reg %x", sensor_slave_info.sensor_id_info.sensor_id_reg_addr); + CDBG("sensor id %x", sensor_slave_info.sensor_id_info.sensor_id); + for (slave_index = 0; slave_index < + p_ctrl->power_setting_size; slave_index++) { + CDBG("%s i %d power setting %d %d %ld %d", __func__, + slave_index, + p_ctrl->power_setting[slave_index].seq_type, + p_ctrl->power_setting[slave_index].seq_val, + p_ctrl->power_setting[slave_index].config_val, + p_ctrl->power_setting[slave_index].delay); + } + break; + } + case CFG_WRITE_I2C_ARRAY: { + struct msm_camera_i2c_reg_setting conf_array; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + CDBG(" CFG_WRITE_I2C_ARRAY"); + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table( + s_ctrl->sensor_i2c_client, &conf_array); + kfree(reg_setting); + break; + } + case CFG_WRITE_I2C_SEQ_ARRAY: { + struct msm_camera_i2c_seq_reg_setting conf_array; + struct msm_camera_i2c_seq_reg_array *reg_setting = NULL; + + CDBG("CFG_WRITE_I2C_SEQ_ARRAY"); + + if (copy_from_user(&conf_array, + (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_seq_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = kzalloc(conf_array.size * + (sizeof(struct msm_camera_i2c_seq_reg_array)), + GFP_KERNEL); + if (!reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(reg_setting, (void *)conf_array.reg_setting, + conf_array.size * + sizeof(struct msm_camera_i2c_seq_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(reg_setting); + rc = -EFAULT; + break; + } + + conf_array.reg_setting = reg_setting; + rc = s_ctrl->sensor_i2c_client->i2c_func_tbl-> + i2c_write_seq_table(s_ctrl->sensor_i2c_client, + &conf_array); + kfree(reg_setting); + break; + } + + case CFG_POWER_UP: + streamon = 0; + sr200pc20_ctrl.op_mode = CAMERA_MODE_INIT; + sr200pc20_ctrl.prev_mode = CAMERA_MODE_INIT; + sr200pc20_ctrl.settings.metering = CAMERA_CENTER_WEIGHT; + sr200pc20_ctrl.settings.exposure = CAMERA_EV_DEFAULT; + sr200pc20_ctrl.settings.wb = CAMERA_WHITE_BALANCE_AUTO; + sr200pc20_ctrl.settings.iso = CAMERA_ISO_MODE_AUTO; + sr200pc20_ctrl.settings.effect = CAMERA_EFFECT_OFF; + sr200pc20_ctrl.settings.scenemode = CAMERA_SCENE_AUTO; + if (s_ctrl->func_tbl->sensor_power_up) { + CDBG("CFG_POWER_UP"); + rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl); + } else + rc = -EFAULT; + break; + + case CFG_POWER_DOWN: + if (s_ctrl->func_tbl->sensor_power_down) { + CDBG("CFG_POWER_DOWN"); + rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl); + } else + rc = -EFAULT; +#ifdef CONFIG_SEC_CAMERA_TUNING + if (front_tune){ + register_table_exit(); + } +#endif + break; + + case CFG_SET_STOP_STREAM_SETTING: { + struct msm_camera_i2c_reg_setting *stop_setting = + &s_ctrl->stop_setting; + struct msm_camera_i2c_reg_array *reg_setting = NULL; + + CDBG("CFG_SET_STOP_STREAM_SETTING"); + + if (copy_from_user(stop_setting, (void *)cdata->cfg.setting, + sizeof(struct msm_camera_i2c_reg_setting))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -EFAULT; + break; + } + + reg_setting = stop_setting->reg_setting; + stop_setting->reg_setting = kzalloc(stop_setting->size * + (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL); + if (!stop_setting->reg_setting) { + pr_err("%s:%d failed\n", __func__, __LINE__); + rc = -ENOMEM; + break; + } + if (copy_from_user(stop_setting->reg_setting, + (void *)reg_setting, stop_setting->size * + sizeof(struct msm_camera_i2c_reg_array))) { + pr_err("%s:%d failed\n", __func__, __LINE__); + kfree(stop_setting->reg_setting); + stop_setting->reg_setting = NULL; + stop_setting->size = 0; + rc = -EFAULT; + break; + } + break; + } + default: + rc = 0; + break; + } + + mutex_unlock(s_ctrl->msm_sensor_mutex); + + CDBG("EXIT"); + + return rc; +} + +int32_t sr200pc20_sensor_native_control(struct msm_sensor_ctrl_t *s_ctrl, + void __user *argp) +{ + int32_t rc = 0; + struct ioctl_native_cmd *cam_info = (struct ioctl_native_cmd *)argp; + mutex_lock(s_ctrl->msm_sensor_mutex); + /* CDBG("cam_info values = %d : %d : %d : %d : %d", cam_info->mode, cam_info->address,\ + cam_info->value_1, cam_info->value_2 , cam_info->value_3); */ + switch (cam_info->mode) { + case EXT_CAM_EV: + sr200pc20_ctrl.settings.exposure = cam_info->value_1; + if(streamon == 1) + sr200pc20_set_exposure_compensation(s_ctrl, sr200pc20_ctrl.settings.exposure); + break; + case EXT_CAM_WB: + sr200pc20_ctrl.settings.wb = cam_info->value_1; + if(streamon == 1) + sr200pc20_set_white_balance(s_ctrl, sr200pc20_ctrl.settings.wb); + break; + case EXT_CAM_EFFECT: + sr200pc20_ctrl.settings.effect = cam_info->value_1; + if(streamon == 1) + sr200pc20_set_effect(s_ctrl, sr200pc20_ctrl.settings.effect); + break; + case EXT_CAM_SENSOR_MODE: + sr200pc20_ctrl.prev_mode = sr200pc20_ctrl.op_mode; + sr200pc20_ctrl.op_mode = cam_info->value_1; + /*CDBG("EXT_CAM_SENSOR_MODE = %d", sr200pc20_ctrl.op_mode);*/ + break; + case EXT_CAM_EXIF: + sr200pc20_get_exif_info(cam_info); + if (!copy_to_user((void *)argp, + (const void *)&cam_info, + sizeof(cam_info))) + CDBG("copy failed"); + break; + case EXT_CAM_VT_MODE: + /*CDBG("EXT_CAM_VT_MODE = %d",cam_info->value_1);*/ + sr200pc20_ctrl.vtcall_mode = cam_info->value_1; + break; + default: + rc = 0; + break; + } + mutex_unlock(s_ctrl->msm_sensor_mutex); + CDBG("EXIT"); + return 0; +} diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv.h b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv.h new file mode 100755 index 0000000000000000000000000000000000000000..fa16f1fd7e8e70ebb734d3abbbe98907ab8167b1 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv.h @@ -0,0 +1,15599 @@ +#ifndef __SR200PC20_REGS_H__ +#define __SR200PC20_REGS_H__ + +/*//////////////////////////////////////////////////////////*/ +/*==========================================================*/ +/* MODEL NO.: SM-G3608W(Rossa_CMCC_OPEN) */ +/* SENSOR : SILICONFILE SR200PC20M */ +/* DSP : MSM 8916 */ +/* MCLK : 26.00 Mhz */ +/* PCLK : 52.00 Mhz */ +/* Preview : 640x480 */ +/* DATE : 2014.08.29 */ +/*==========================================================*/ +/* Frequency 50hz */ + +struct msm_camera_i2c_reg_conf sr200pc20_Init_Reg_50hz[] = { +/* 01. Start Setting */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_404 */ +{0x41, 0x94,}, +{0x42, 0x00,}, +{0x43, 0x83,}, /* 131 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0c,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0c,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0c,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0c,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0d,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0d,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x94,}, +{0x45, 0x84,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x94,}, +{0x4b, 0x84,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xb0,}, +{0x55, 0xb0,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th*/ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xc0,}, +{0x5b, 0xc0,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th*/ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc8,}, +{0x61, 0xc8,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ + +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Defalt */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /* EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 6500.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x05,}, /*EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /*0x1470 */ /* 201110130x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /*10160x04 ->0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 ND */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, + +{0xff, 0x0a,}, /* 100ms */ + +}; + + +struct msm_camera_i2c_reg_conf sr200pc20_Init_Reg_60hz[] = { + + +/* 01. Start Setting */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_404 */ +{0x41, 0x94,}, +{0x42, 0x00,}, +{0x43, 0x6e,}, /* 110 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0f,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0f,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0f,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0f,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0d,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0d,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x94,}, +{0x45, 0x84,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x94,}, +{0x4b, 0x84,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xb0,}, +{0x55, 0xb0,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th*/ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xc0,}, +{0x5b, 0xc0,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th*/ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc8,}, +{0x61, 0xc8,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, //EXP Normal 30.00 fps +{0x84, 0xa5,}, +{0x85, 0xe0,}, +{0x86, 0x01,}, //EXPMin 6500.00 fps +{0x87, 0xf4,}, +{0x88, 0x06,}, //EXP Max 8.00 fps +{0x89, 0x2e,}, +{0x8a, 0x08,}, +{0x8B, 0x7e,}, //EXP100 +{0x8C, 0xf4,}, +{0x8D, 0x69,}, //EXP120 +{0x8E, 0x78,}, +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 0x1470 */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /*1016 0x04 -> 0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 ND */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, + +{0xff, 0x0a,}, /* 100ms */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_800x600_Preview_for_Return_50hz[] = { + + + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x00,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x40,}, /* 800x600 MiPi OutPut */ +{0x31, 0x06,}, + +/* {0x30, 0x00,}, */ /* 640 x 480 MiPi OutPut */ +/* {0x31, 0x05,}, */ + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x0a,}, +/* 100ms */ + +/* END of sr200pc20m_preview */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_800x600_Preview_for_Return_60hz[] = { + + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x00,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x40,}, /* 800x600 MiPi OutPut */ +{0x31, 0x06,}, + +/* {0x30, 0x00,}, */ /* 640 x 480 MiPi OutPut */ +/* {0x31, 0x05,}, */ + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x0a,}, +/* 100ms */ + +/* END of sr200pc20m_preview */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_initial_50hz[] = { + + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only forPreview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 ART */ +{0x03, 0x48,}, + +/* PLL Settng */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX etting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 ND */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x28,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_initial_60hz[] = { + + + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only forPreview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 ART */ +{0x03, 0x48,}, + +/* PLL Settng */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX etting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 ND */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x28,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_Return_50hz[] = { + + +/* 01. Start Setting */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_404 */ +{0x41, 0x94,}, +{0x42, 0x00,}, +{0x43, 0x83,}, /* 131 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0c,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0c,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0c,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0c,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0d,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0d,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x94,}, +{0x45, 0x84,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x94,}, +{0x4b, 0x84,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xb0,}, +{0x55, 0xb0,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th*/ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xc0,}, +{0x5b, 0xc0,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th*/ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc8,}, +{0x61, 0xc8,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /* EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 6500.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x05,}, /*EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /*0x1470 */ /* 201110130x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /*10160x04 ->0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 ND */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x28,}, /* NEED Delay 400ms */ + +}; + + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_Return_60hz[] = { + + +/* 01. Start Setting */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_404 */ +{0x41, 0x94,}, +{0x42, 0x00,}, +{0x43, 0x6e,}, /* 110 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0f,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0f,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0f,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0f,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0d,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0d,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x94,}, +{0x45, 0x84,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x94,}, +{0x4b, 0x84,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xb0,}, +{0x55, 0xb0,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th*/ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xc0,}, +{0x5b, 0xc0,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th*/ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc8,}, +{0x61, 0xc8,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, //EXP Normal 30.00 fps +{0x84, 0xa5,}, +{0x85, 0xe0,}, +{0x86, 0x01,}, //EXPMin 6500.00 fps +{0x87, 0xf4,}, +{0x88, 0x06,}, //EXP Max 8.00 fps +{0x89, 0x2e,}, +{0x8a, 0x08,}, +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /*0x1470 */ /* 201110130x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /*10160x04 ->0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 ND */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x28,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_VT_Init_Reg_50Hz[] = { + + +/* SKT-VT - continuous */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x94,}, /* Enable Fixed Frame */ +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 14 ->0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_360 */ +{0x41, 0x68,}, +{0x42, 0x00,}, /* Vblank 50hz */ +{0x43, 0x94,}, +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0c,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0c,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0c,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0c,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* For Preview */ + +{0x40, 0x80,}, +{0x41, 0x20,}, /* Dyoffset */ +{0x50, 0xf0,}, /* Threshold Dyoffset */ + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, /* 20120224 0x06 -> 0x04 */ + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th*/ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th*/ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* For Preview */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, + +/* only for Preview DPC */ +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X Center */ +{0x21, 0x80,}, /* Y Center */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS(6500K) */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,}, /* Double_AG 37 */ +{0x19, 0x5d,}, /* Double_AG 36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xef,}, /* add 20120223 enable Dgain for Dark */ +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, /* add 20120223 */ +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0xaa,}, +{0x61, 0xaa,}, +{0x62, 0xaa,}, +{0x63, 0xaa,}, +{0x64, 0xaa,}, +{0x65, 0xaa,}, +{0x66, 0xab,}, +{0x67, 0xea,}, +{0x68, 0xab,}, +{0x69, 0xea,}, +{0x6a, 0xaa,}, +{0x6b, 0xaa,}, +{0x6c, 0xaa,}, +{0x6d, 0xaa,}, +{0x6e, 0xaa,}, +{0x6f, 0xaa,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /* EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 6500.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x05,}, /*EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x91, 0x06,}, /*EXP Fix 8.00 fps*/ +{0x92, 0x32,}, +{0x93, 0xea,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, /* for wb speed 20120314 */ +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* for tracking 20120314 */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, /* for tracking 20120314 */ + +{0x41, 0x43,}, /* stable c_diff */ +{0x42, 0x22,}, /* stable c_sum */ +{0x43, 0xf1,}, +{0x44, 0x54,}, /* unstable c_diff */ +{0x45, 0x22,}, /* unstable c_sum */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* for A light */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x28,}, /* low temp Rgain */ +{0xb0, 0x26,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 */ +{0xb4, 0xbf,}, /* for tracking 20120314 */ +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131024 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHz:0x02, 48MHz:0x03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x28,}, + +/* END of sr200pc20m_vt_common */ + +}; + + +struct msm_camera_i2c_reg_conf sr200pc20_VT_Init_Reg_60Hz[] = { + +/* SKT-VT - continuous */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x94,}, /* Enable Fixed Frame */ +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 14 ->0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_360 */ +{0x41, 0x68,}, +{0x42, 0x00,}, /* Vblank 50hz */ +{0x43, 0x7e,}, +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0f,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0f,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0f,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0f,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* For Preview */ + +{0x40, 0x80,}, +{0x41, 0x20,}, /* Dyoffset */ +{0x50, 0xf0,}, /* Threshold Dyoffset */ + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, /* 20120224 0x06 -> 0x04 */ + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th */ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th */ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* For Preview */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, + +/* only for Preview DPC */ +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X Center */ +{0x21, 0x80,}, /* Y Center */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS(6500K) */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,}, /* Double_AG 37 */ +{0x19, 0x5d,}, /* Double_AG 36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xef,}, /* add 20120223 enable Dgain for Dark */ +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, /* add 20120223 */ +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0xaa,}, +{0x61, 0xaa,}, +{0x62, 0xaa,}, +{0x63, 0xaa,}, +{0x64, 0xaa,}, +{0x65, 0xaa,}, +{0x66, 0xab,}, +{0x67, 0xea,}, +{0x68, 0xab,}, +{0x69, 0xea,}, +{0x6a, 0xaa,}, +{0x6b, 0xaa,}, +{0x6c, 0xaa,}, +{0x6d, 0xaa,}, +{0x6e, 0xaa,}, +{0x6f, 0xaa,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, //EXP Normal 30.00 fps +{0x84, 0xa5,}, +{0x85, 0xe0,}, + +{0x86, 0x01,}, //EXPMin 6500.00 fps +{0x87, 0xf4,}, + +{0x88, 0x06,}, //EXP Max 8.00 fps +{0x89, 0x2e,}, +{0x8a, 0x08,}, + +{0x8B, 0x7e,}, //EXP100 +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x91, 0x06,}, /*EXP Fix 8.00 fps*/ +{0x92, 0x32,}, +{0x93, 0xea,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, /* for wb speed 20120314 */ +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* for tracking 20120314 */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, /* for tracking 20120314 */ + +{0x41, 0x43,}, /* stable c_diff */ +{0x42, 0x22,}, /* stable c_sum */ +{0x43, 0xf1,}, +{0x44, 0x54,}, /* unstable c_diff */ +{0x45, 0x22,}, /* unstable c_sum */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* for A light */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x28,}, /* low temp Rgain */ +{0xb0, 0x26,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 */ +{0xb4, 0xbf,}, /* for tracking 20120314 */ +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131024 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHz:0x02, 48MHz:0x03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, + +{0xff, 0x0a,}, /* NEED Delay 100ms */ +/* END of sr200pc20m_vt_common */ + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_stop_stream[] = { +{0x03, 0x00,}, +{0x01, 0x01,}, +{0xff, 0x00,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_i2c_check[] = { +{0x03, 0x00,}, +{0x01, 0x30,}, + +{0xff, 0x0a,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Capture[] = { + +{0x03, 0x00,}, +{0x01, 0x31,}, /* b[0] set power sleep by preserving all register values, 0=OFF 1=ON */ + +{0x03, 0x22,}, /* Page 22 */ +{0x10, 0x69,}, /* AWB Off */ + +{0x03, 0x00,}, +{0x10, 0x00,}, /* Imge size, windowing, Hsync, Vsync */ + +{0x20, 0x00,}, /* windowing */ +{0x21, 0x0a,}, /* modify 20110929 0x0c -> 0x0a */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +/* Page10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, /* not defined in data sheet */ +{0x60, 0x63,}, /* color saturation */ + +/* Page12 */ /* Noise reduction */ +{0x03, 0x12,}, +{0x20, 0x0f,}, +{0x21, 0x0f,}, +{0x90, 0x5d,}, + +/* only forPreview DPC Off */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ /* Edge enhancement */ +{0x03, 0x13,}, +{0x10, 0xcb,}, /* Edge On */ +{0x80, 0xfd,}, + +/* PAGE 18 */ /* Image scaling */ +{0x03, 0x18,}, +{0x10, 0x00,}, /* Scaling Off */ + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Settng */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x81,}, +{0x70, 0x85,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX etting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, +{0x1d, 0x10,}, +{0x1e, 0x08,}, +{0x1f, 0x04,}, +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x80,}, /* 1600 x 1200 MiPi OutPut */ +{0x31, 0x0c,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x03,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* Page0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, /* Dummy 750us */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, /* Sleep Off */ +{0xff, 0x03,}, /* Increase from 30ms */ +/* END of sr200pc20m_capture. */ + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Capture_X_Flip[] = { +{0x03, 0x00,}, +{0x11, 0x91,}, /* B[0]_horizontal flip funtion(0:off,1:on) */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Capture_Y_Flip[] = { +{0x03, 0x00,}, +{0x11, 0x92,}, /* B[1]_vertical flip funtion(0:off,1:on) */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M4[] = { +{0x03, 0x10,}, +{0x40, 0xd0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M3[] = { +{0x03, 0x10,}, +{0x40, 0xc0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M2[] = { +{0x03, 0x10,}, +{0x40, 0xb0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M1[] = { +{0x03, 0x10,}, +{0x40, 0xa0,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_default[] = { +{0x03, 0x10,}, +{0x40, 0x00,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P1[] = { +{0x03, 0x10,}, +{0x40, 0x20,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P2[] = { +{0x03, 0x10,}, +{0x40, 0x30,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P3[] = { +{0x03, 0x10,}, +{0x40, 0x40,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P4[] = { +{0x03, 0x10,}, +{0x40, 0x50,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M4[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x00,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M3[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x20,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M2[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x40,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M1[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x60,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_default[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x40,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P1[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x60,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P2[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x80,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P3[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0xa0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P4[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0xff,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Normal[] = { +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x30,}, +{0x44, 0x80,}, +{0x45, 0x80,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Negative[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x38,}, +{0x44, 0x80,}, +{0x45, 0x80,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Gray[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x33,}, +{0x44, 0x80,}, +{0x45, 0x80,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Sepia[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x33,}, +{0x44, 0x70,}, +{0x45, 0x98,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Aqua[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x33,}, +{0x44, 0xb0,}, +{0x45, 0x40,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Vintage_Cold[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Vintage_Warm[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Posterize[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Solarize[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Washed[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Color1[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Color2[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Color3[] = +{ + +}; + +/* WhiteBalance */ +struct msm_camera_i2c_reg_conf sr200pc20_WB_Auto[] = +{ +{0x03, 0x22,}, +{0x11, 0x2e,}, +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, +{0x83, 0x56,}, // R Max D65 +{0x84, 0x20,}, // R Min H +{0x85, 0x58,}, // B Max H +{0x86, 0x20,}, // B Min D65 +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Daylight[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x3b,}, +{0x81, 0x20,}, +{0x82, 0x35,}, +{0x83, 0x3c,}, +{0x84, 0x3a,}, +{0x85, 0x36,}, +{0x86, 0x34,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Cloudy[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x49,}, +{0x81, 0x20,}, +{0x82, 0x2a,}, +{0x83, 0x4a,}, +{0x84, 0x48,}, +{0x85, 0x2b,}, +{0x86, 0x29,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Fluorescent[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x3c,}, +{0x81, 0x20,}, +{0x82, 0x49,}, +{0x83, 0x3e,}, +{0x84, 0x38,}, +{0x85, 0x4d,}, +{0x86, 0x44,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Incandescent[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x20,}, +{0x81, 0x20,}, +{0x82, 0x58,}, +{0x83, 0x23,}, +{0x84, 0x1f,}, +{0x85, 0x58,}, +{0x86, 0x52,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Auto_fps_50hz[] = { + + +/* 01. Start Setting */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_404 */ +{0x41, 0x94,}, +{0x42, 0x00,}, +{0x43, 0x83,}, /* 131 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0c,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0c,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0c,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0c,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0d,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0d,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x94,}, +{0x45, 0x84,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x94,}, +{0x4b, 0x84,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xb0,}, +{0x55, 0xb0,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th*/ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xc0,}, +{0x5b, 0xc0,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th*/ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc8,}, +{0x61, 0xc8,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ + +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /* EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 6500.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x05,}, /*EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /*0x1470 */ /* 201110130x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /*10160x04 ->0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 ND */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x0a,}, /* delay 100ms */ + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Auto_fps_60hz[] = { + + +/* 01. Start Setting */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_404 */ +{0x41, 0x94,}, +{0x42, 0x00,}, +{0x43, 0x6e,}, /* 110 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0f,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0f,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0f,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0f,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0d,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0d,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x94,}, +{0x45, 0x84,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x94,}, +{0x4b, 0x84,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xb0,}, +{0x55, 0xb0,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th*/ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xc0,}, +{0x5b, 0xc0,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th*/ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc8,}, +{0x61, 0xc8,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ + +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, //EXP Normal 30.00 fps +{0x84, 0xa5,}, +{0x85, 0xe0,}, +{0x86, 0x01,}, //EXPMin 6500.00 fps +{0x87, 0xf4,}, +{0x88, 0x06,}, //EXP Max 8.00 fps +{0x89, 0x2e,}, +{0x8a, 0x08,}, +{0x8B, 0x7e,}, //EXP100 +{0x8C, 0xf4,}, +{0x8D, 0x69,}, //EXP120 +{0x8E, 0x78,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /*0x1470 */ /* 201110130x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /*10160x04 ->0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 ND */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x10,}, +{0x1e, 0x06,}, +{0x1f, 0x03,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ +/* END of sr200pc20m_recording_50Hz_common*/ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_24fps_Camcoder_50hz[] = { + + +/* Recording 24fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank 280 */ +{0x41, 0x18,}, +{0x42, 0x00,}, /* Vblank 20 */ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x04,}, /* BLC_TIME_TH_ON */ +{0x91, 0x04,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x04,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x04,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th*/ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th*/ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /* EXP Normal 33.33 fps */ +{0x84, 0xdb,}, +{0x85, 0x50,}, + +{0x86, 0x01,}, /* EXPMin 8463.54 fps */ +{0x87, 0xe0,}, + +{0x88, 0x02,}, /*EXP Max 25.00 fps */ +{0x89, 0x79,}, +{0x8a, 0xc0,}, + +{0x8B, 0x9e,}, /*EXP100 */ +{0x8C, 0x70,}, + +{0x8D, 0x84,}, /*EXP120 */ +{0x8E, 0x30,}, + +{0x91, 0x02,}, /*EXP Fix 24.01 fps*/ +{0x92, 0x94,}, +{0x93, 0xf0,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x16,}, /*EXP Limit 705.30 fps */ +{0x9d, 0x80,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xe0,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x3c,}, /* MiPi Pllx 2.5 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, /* 20121019 */ +{0x1d, 0x10,}, +{0x1e, 0x08,}, /* 20121009 */ +{0x1f, 0x04,}, /* 20121101 0x05 -> 0x004 */ /* 0x04->0x03 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x35, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ +/* END of sr200pc20m_recording_50Hz_common*/ + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_24fps_Camcoder_60hz[] = { + + +/* Recording 24fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank 280 */ +{0x41, 0x18,}, +{0x42, 0x00,}, /* Vblank 20 */ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x04,}, /* BLC_TIME_TH_ON */ +{0x91, 0x04,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xa8,}, /* BLC_AG_TH_ON */ +{0x93, 0xa0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC*/ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x41,}, /* B */ +{0xaa, 0x41,}, +{0xac, 0x41,}, +{0xae, 0x41,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x04,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x04,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xa8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7b,}, /* 77 */ +{0x62, 0x7b,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x05,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th*/ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th*/ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th*/ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clipth */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x70,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x5e,}, /* 3e */ +{0x50, 0x40,}, /* 28 */ +{0x60, 0x3d,}, /* 24 */ +{0x70, 0x40,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS*/ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0x34,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0x78,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x73,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xf2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x45,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x02,}, //EXP Normal 30.00 fps +{0x84, 0x10,}, +{0x85, 0xc0,}, +{0x86, 0x01,}, //EXPMin 8463.54 fps +{0x87, 0xe0,}, +{0x88, 0x02,}, //EXP Max 30.00 fps +{0x89, 0x10,}, +{0x8a, 0xc0,}, +{0x8B, 0x9e,}, //EXP100 +{0x8C, 0x70,}, +{0x8D, 0x84,}, //EXP120 +{0x8E, 0x30,}, + +{0x91, 0x02,}, /*EXP Fix 24.01 fps*/ +{0x92, 0x94,}, +{0x93, 0xf0,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x16,}, /*EXP Limit 705.30 fps */ +{0x9d, 0x80,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xe0,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb0,}, +{0xb3, 0x14,}, +{0xb4, 0x14,}, +{0xb5, 0x38,}, +{0xb6, 0x26,}, +{0xb7, 0x20,}, +{0xb8, 0x1d,}, +{0xb9, 0x1b,}, +{0xba, 0x1a,}, +{0xbb, 0x19,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x81,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, +{0x84, 0x20,}, +{0x85, 0x58,}, +{0x86, 0x20,}, + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x3a,}, +{0x8a, 0x29,}, + +{0x8b, 0x3d,}, +{0x8c, 0x36,}, +{0x8d, 0x37,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x3c,}, /* MiPi Pllx 2.5 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + + +{0x19, 0x00,}, +{0x1a, 0x30,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, /* 20121019 */ +{0x1d, 0x10,}, +{0x1e, 0x08,}, /* 20121009 */ +{0x1f, 0x04,}, /* 20121101 0x05 -> 0x004 */ /* 0x04->0x03 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x35, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ +/* END of sr200pc20m_recording_50Hz_common*/ +}; + +#if 0 +static const u16 sr200pc20_15fps[] = { + +/* Recording 15fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /*Hblank 404*/ +{0x41, 0x94,}, +{0x42, 0x00,}, /*Vblank 20*/ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x07,}, /*BLC_TIME_TH_ON*/ +{0x91, 0x07,}, /*BLC_TIME_TH_OFF */ +{0x92, 0xb0,}, /*BLC_AG_TH_ON*/ +{0x93, 0xa8,}, /*BLC_AG_TH_OFF*/ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x07,}, /*DCDC_TIME_TH_ON*/ +{0xd5, 0x07,}, /*DCDC_TIME_TH_OFF */ +{0xd6, 0xb0,}, /*DCDC_AG_TH_ON*/ +{0xd7, 0xa8,}, /*DCDC_AG_TH_OFF*/ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x67,}, /* Setting For Camcorder 24 */ +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0x50,}, /* Double_AG 50->30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0xa0,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th */ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th */ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x36,}, /* CMCOFSGM */ +{0x16, 0x26,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, +/* PAGE 18 END */ + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 30.00 fps */ +{0x84, 0xa7,}, +{0x85, 0x2c,}, + +{0x86, 0x01,}, /*EXPMin 6360.08 fps*/ +{0x87, 0xff,}, + +{0x88, 0x02,}, /*EXP Max 17.14 fps */ +{0x89, 0xe4,}, +{0x8a, 0x8d,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xc0,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0xcb,}, + +{0x91, 0x03,}, /*EXP Fix 15.00 fps*/ +{0x92, 0x4e,}, +{0x93, 0x58,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 530.01 fps */ +{0x9d, 0xf4,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xff,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb8,}, +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* 5e */ +{0x84, 0x22,}, /* 24 21 22 Spec AWB H modify */ +{0x85, 0x55,}, /* 54 51 4f Spec AWB H modify */ +{0x86, 0x20,}, /* 24 */ + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, /* 38 */ +{0x8a, 0x29,}, /* 2a */ + +{0x8b, 0x3c,}, /* R Max 3c->3e */ +{0x8c, 0x38,}, /* R Min */ +{0x8d, 0x32,}, /* B Max 32->33 */ +{0x8e, 0x2c,}, /* 2c */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x39,}, +{0x95, 0x30,}, +{0x96, 0x2c,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x77,}, +{0x9c, 0x66,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xc0,}, +{0xa1, 0x54,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 {0x10, continuous -> 0x00, not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* {0x14, 0x70,}, */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, /* 20121004 */ +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x28,}, /* NEED Delay 400ms */ +/* END of sr200pc20m_recording_50Hz_common*/ + +}; + +static const u16 sr200pc20_20fps[] = { + +/* Recording 24fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank 280 */ +{0x41, 0x18,}, +{0x42, 0x00,}, /* Vblank 20 */ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x05,}, /* BLC_TIME_TH_ON */ +{0x91, 0x05,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xb0,}, /* BLC_AG_TH_ON */ +{0x93, 0xa8,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x05,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x05,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xb0,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa8,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x67,}, /* Setting For Camcorder 24 */ +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0x50,}, /* Double_AG 50->30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0xa0,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th */ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th */ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x36,}, /* CMCOFSGM */ +{0x16, 0x26,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x02,}, /*EXP Normal 30.00 fps */ +{0x84, 0x10,}, +{0x85, 0xc0,}, + +{0x86, 0x01,}, /* EXPMin 8463.54 fps */ +{0x87, 0xe0,}, + +{0x88, 0x02,}, /*EXP Max 24.00 fps */ +{0x89, 0x94,}, +{0x8a, 0xf0,}, + +{0x8B, 0x9e,}, /*EXP100 */ +{0x8C, 0x70,}, + +{0x8D, 0x84,}, /*EXP120 */ +{0x8E, 0x30,}, + +{0x91, 0x03,}, /*EXP Fix 20.01 fps*/ +{0x92, 0x19,}, +{0x93, 0x20,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x16,}, /*EXP Limit 705.30 fps */ +{0x9d, 0x80,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xe0,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb8,}, +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* 5e */ +{0x84, 0x22,}, /* 24 21 22 Spec AWB H modify */ +{0x85, 0x55,}, /* 54 51 4f Spec AWB H modify */ +{0x86, 0x20,}, /* 24 */ + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, /* 38 */ +{0x8a, 0x29,}, /* 2a */ + +{0x8b, 0x3c,}, /* R Max 3c->3e */ +{0x8c, 0x38,}, /* R Min */ +{0x8d, 0x32,}, /* B Max 32->33 */ +{0x8e, 0x2c,}, /* 2c */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x39,}, +{0x95, 0x30,}, +{0x96, 0x2c,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x77,}, +{0x9c, 0x66,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xc0,}, +{0xa1, 0x54,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x3c,}, /* MiPi Pllx 2.5 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* {0x14, 0x70,}, */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, /* 20121019 */ +{0x1d, 0x0f,}, /* 20121101 0x0e -> 0x0f */ +{0x1e, 0x08,}, /* 20121009 */ +{0x1f, 0x03,}, /* 20121101 0x05 -> 0x004 */ /* 0x04->0x03 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x35, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x28,}, /* NEED Delay 400ms */ +/* END of sr200pc20m_recording_50Hz_common*/ +}; + + +/******************************************************* +* CAMERA_SCENE +*******************************************************/ +static const u16 sr200pc20m_scene_off[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + + +static const u16 sr200pc20m_scene_landscape[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation +1, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x8a,},/*+10*/ +{0x62, 0x86,},/*+10*/ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness +1*/ +{0x03, 0x13,}, +{0x12, 0x02,}, +{0x25, 0x02,}, +{0x20, 0x1a,}, +{0x21, 0x1a,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/* AE Matrix(Average)*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x55,}, +{0x63, 0x55,}, +{0x64, 0x55,}, +{0x65, 0x55,}, +{0x66, 0x55,}, +{0x67, 0x55,}, +{0x68, 0x55,}, +{0x69, 0x55,}, +{0x6a, 0x55,}, +{0x6b, 0x55,}, +{0x6c, 0x55,}, +{0x6d, 0x55,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + + +static const u16 sr200pc20m_scene_party[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation +1, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x8a,}, +{0x62, 0x86,}, +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xe4,}, /* adaptive off*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + + /*ISO_200*/ +{0xb0, 0x37,}, +{0xb1, 0x37,}, +{0xb2, 0x40,}, +{0xb3, 0x37,}, +{0xb4, 0x37,}, +{0xb5, 0x40,}, +{0xb6, 0x3e,}, +{0xb7, 0x3c,}, +{0xb8, 0x3a,}, +{0xb9, 0x39,}, +{0xba, 0x38,}, +{0xbb, 0x37,}, +{0xbc, 0x37,}, +{0xbd, 0x37,}, + +{0xc0, 0x10,}, +{0xc1, 0x37,}, +{0xc2, 0x37,}, +{0xc3, 0x37,}, +{0xc4, 0x0b,}, + +{0xff, 0x05,}, +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ + +}; + + +static const u16 sr200pc20m_scene_sunset[] = { + +/* WB Daylight*/ +{0x03, 0x22,}, +{0x11, 0x2c,}, + +{0x80, 0x3b,}, +{0x81, 0x20,}, +{0x82, 0x35,}, /* 3a */ + +{0x83, 0x3c,}, /* */ +{0x84, 0x3a,}, /* */ +{0x85, 0x36,}, /* */ +{0x86, 0x34,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_dawn[] = { +/*WB FLUORESCENT*/ +{0x03, 0x22,}, +{0x11, 0x2c,}, + +{0x80, 0x3c,}, +{0x81, 0x20,}, +{0x82, 0x49,}, /* 3a */ + +{0x83, 0x3e,}, /* */ +{0x84, 0x38,}, /* */ +{0x85, 0x4d,}, /* */ +{0x86, 0x44,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ + +}; + +static const u16 sr200pc20m_scene_fall[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation +2, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x9a,},/*+20*/ +{0x62, 0x96,},/*+20*/ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /* Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_nightshot_Normal[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 //*/ +{0x62, 0x76,}, /* 77 //*/ +{0x63, 0xf0,}, +{0x64, 0xf0,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x01,}, +{0xa2, 0x01,}, +{0xa4, 0x01,}, +{0xa6, 0x01,}, + +{0x03, 0x20,}, /*Page 20, Dark condition*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*DARK Conditon1*/ +{0x88, 0x10,}, /*EXP Max 3.00 fps */ +{0x89, 0x87,}, +{0x8a, 0xb8,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xff,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_nightshot_Dark[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 //*/ +{0x62, 0x76,}, /* 77 //*/ +{0x63, 0xf0,}, +{0x64, 0xf0,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x01,}, +{0xa2, 0x01,}, +{0xa4, 0x01,}, +{0xa6, 0x01,}, + +{0x03, 0x20,}, /*Page 20, Dark condition*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*DARK Conditon2*/ +{0x83, 0x10,}, /*EXP 3.00 fps*/ +{0x84, 0x87,}, +{0x85, 0xb8,}, + +{0x88, 0x10,}, /*EXP Max 3.00 fps */ +{0x89, 0x87,}, +{0x8a, 0xb8,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xff,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_backlight[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Flash OFF _Spot*/ +{0x60, 0x00,}, +{0x61, 0x00,}, +{0x62, 0x00,}, +{0x63, 0x00,}, +{0x64, 0x00,}, +{0x65, 0x00,}, +{0x66, 0x03,}, +{0x67, 0xc0,}, +{0x68, 0x03,}, +{0x69, 0xc0,}, +{0x6a, 0x00,}, +{0x6b, 0x00,}, +{0x6c, 0x00,}, +{0x6d, 0x00,}, +{0x6e, 0x00,}, +{0x6f, 0x00,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ + +}; + + +static const u16 sr200pc20m_scene_candle[] = { + +/* WB Daylight*/ +{0x03, 0x22,}, +{0x11, 0x2c,}, + +{0x80, 0x3b,}, +{0x81, 0x20,}, +{0x82, 0x35,}, /* 3a */ + +{0x83, 0x3c,}, /* */ +{0x84, 0x3a,}, /* */ +{0x85, 0x36,}, /* */ +{0x86, 0x34,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x72,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x0c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x8c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + + + +/******************************************************* +* CAMERA_METERING +*******************************************************/ +static const u16 sr200pc20m_metering_matrix[] = { +{0x03, 0x20,}, +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x55,}, +{0x63, 0x55,}, +{0x64, 0x55,}, +{0x65, 0x55,}, +{0x66, 0x55,}, +{0x67, 0x55,}, +{0x68, 0x55,}, +{0x69, 0x55,}, +{0x6a, 0x55,}, +{0x6b, 0x55,}, +{0x6c, 0x55,}, +{0x6d, 0x55,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, +}; + +static const u16 sr200pc20m_metering_spot[] = { +{0x03, 0x20,}, +{0x60, 0x00,}, +{0x61, 0x00,}, +{0x62, 0x00,}, +{0x63, 0x00,}, +{0x64, 0x00,}, +{0x65, 0x00,}, +{0x66, 0x03,}, +{0x67, 0xc0,}, +{0x68, 0x03,}, +{0x69, 0xc0,}, +{0x6a, 0x00,}, +{0x6b, 0x00,}, +{0x6c, 0x00,}, +{0x6d, 0x00,}, +{0x6e, 0x00,}, +{0x6f, 0x00,}, +}; + +static const u16 sr200pc20m_metering_center[] = { +{0x03, 0x20,}, +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, +}; + +#endif + +#endif diff --git a/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv_coreprime.h b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv_coreprime.h new file mode 100755 index 0000000000000000000000000000000000000000..bfc3f06bd8cf9930fbd92dc73290179420a5df9c --- /dev/null +++ b/drivers/media/platform/msm/camera_v2_j5/sensor/sr200pc20_yuv_coreprime.h @@ -0,0 +1,13371 @@ +#ifndef __SR200PC20_REGS_H__ +#define __SR200PC20_REGS_H__ + +/*//////////////////////////////////////////////////////////*/ +/*==========================================================*/ +/* MODEL NO.: SM-G3608W(Rossa_CMCC_OPEN) */ +/* SENSOR : SILICONFILE SR200PC20M */ +/* DSP : MSM 8916 */ +/* MCLK : 26.00 Mhz */ +/* PCLK : 52.00 Mhz */ +/* Preview : 640x480 */ +/* DATE : 2014.08.29 */ +/*==========================================================*/ +/* Frequency 50hz */ + +struct msm_camera_i2c_reg_conf sr200pc20_Init_Reg_50hz[] = { +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_360 */ +{0x41, 0x68,}, +{0x42, 0x00,}, +{0x43, 0x94,}, /* 148 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0c,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0c,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xc8,}, /* BLC_AG_TH_ON */ +{0x93, 0xc0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, /* B */ +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0c,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0c,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xc8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xc0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x04,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th */ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th */ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ + +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* 3e */ +{0x50, 0x24,}, /* 28 */ +{0x60, 0x20,}, /* 24 */ +{0x70, 0x24,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0xf4,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /* EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 6500.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x05,}, /*EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, // R Max D65 +{0x84, 0x22,}, // R Min H +{0x85, 0x4F,}, // B Max H +{0x86, 0x20,}, // B Min D65 + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, +{0x8a, 0x29,}, + +{0x8b, 0x3c,}, +{0x8c, 0x38,}, +{0x8d, 0x32,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 0x1470 */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /* 10160x04 -> 0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, + +{0xff, 0x28,}, /* 400ms */ + +}; + + +struct msm_camera_i2c_reg_conf sr200pc20_Init_Reg_60hz[] = { + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /*Hblank 404*/ +{0x41, 0x94,}, +{0x42, 0x00,}, /*Vblank 110*/ +{0x43, 0x6e,}, + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0f,}, /*BLC_TIME_TH_ON*/ +{0x91, 0x0f,}, /*BLC_TIME_TH_OFF */ +{0x92, 0xc8,}, /* BLC_AG_TH_ON */ +{0x93, 0xc0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, /* B */ +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0f,}, /*DCDC_TIME_TH_ON*/ +{0xd5, 0x0f,}, /*DCDC_TIME_TH_OFF */ +{0xd6, 0xc8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xc0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x04,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th */ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th */ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ + +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* 3e */ +{0x50, 0x24,}, /* 28 */ +{0x60, 0x20,}, /* 24 */ +{0x70, 0x24,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0xf4,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 30.00 fps */ +{0x84, 0xa7,}, +{0x85, 0x2c,}, + +{0x86, 0x01,}, /*EXPMin 6360.08 fps*/ +{0x87, 0xff,}, + +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xc0,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0xcb,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 530.01 fps */ +{0x9d, 0xf4,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xff,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, // R Max D65 +{0x84, 0x22,}, // R Min H +{0x85, 0x4F,}, // B Max H +{0x86, 0x20,}, // B Min D65 + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, +{0x8a, 0x29,}, + +{0x8b, 0x3c,}, +{0x8c, 0x38,}, +{0x8d, 0x32,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 0x1470 */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /* 10160x04 -> 0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, + +{0xff, 0x28,}, /* 400ms */ + +}; + + +struct msm_camera_i2c_reg_conf sr200pc20_800x600_Preview_50hz[] = { + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x00,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x40,}, /* 800x600 MiPi OutPut */ +{0x31, 0x06,}, + +/* {0x30, 0x00,}, */ /* 640 x 480 MiPi OutPut */ +/* {0x31, 0x05,}, */ + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +/* END of sr200pc20m_preview */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_800x600_Preview_60hz[] = { + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x00,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x40,}, /* 800x600 MiPi OutPut */ +{0x31, 0x06,}, + +/* {0x30, 0x00,}, */ /* 640 x 480 MiPi OutPut */ +/* {0x31, 0x05,}, */ + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +/* END of sr200pc20m_preview */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_initial_50hz[] = { + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_initial_60hz[] = { + + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_Return_50hz[] = { + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +{0xff, 0x28,}, /* 400ms */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_640x480_Preview_for_Return_60hz[] = { + + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +{0xff, 0x28,}, /* 400ms */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_VT_Init_Reg_50Hz[] = { +/* SKT-VT - continuous */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x94,}, /* Enable Fixed Frame */ +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 14 ->0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_360 */ +{0x41, 0x68,}, +{0x42, 0x00,}, /* Vblank 50hz */ +{0x43, 0x94,}, +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0c,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0c,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xf0,}, /* BLC_AG_TH_ON */ +{0x93, 0xe8,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0c,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0c,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xf0,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xe8,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* For Preview */ + +{0x40, 0x80,}, +{0x41, 0x20,}, /* Dyoffset */ +{0x50, 0xf0,}, /* Threshold Dyoffset */ + +{0x60, 0x6b,}, +{0x61, 0x7a,}, /* Sat B */ +{0x62, 0x72,}, /* Sat R */ +{0x63, 0xff,}, /* Th decolor_saturation */ +{0x64, 0xff,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* Cb_Pos_Sat */ +{0x6b, 0x74,}, /* Cb_Neg_Sat */ +{0x6c, 0x71,}, /* Cr_Pos_Sat */ +{0x6d, 0x8e,}, /* Cr_Neg_Sat */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, /* 20120224 0x06 -> 0x04 */ + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th */ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th */ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* For Preview */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, + +/* only for Preview DPC */ +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/* Dark2 */ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X Center */ +{0x21, 0x80,}, /* Y Center */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS(6500K) */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,}, /* Double_AG 37 */ +{0x19, 0x5d,}, /* Double_AG 36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xef,}, /* add 20120223 enable Dgain for Dark */ +{0x29, 0x0d,}, /* 20100305 ad -> 0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, /* add 20120223 */ +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0xaa,}, +{0x61, 0xaa,}, +{0x62, 0xaa,}, +{0x63, 0xaa,}, +{0x64, 0xaa,}, +{0x65, 0xaa,}, +{0x66, 0xab,}, +{0x67, 0xea,}, +{0x68, 0xab,}, +{0x69, 0xea,}, +{0x6a, 0xaa,}, +{0x6b, 0xaa,}, +{0x6c, 0xaa,}, +{0x6d, 0xaa,}, +{0x6e, 0xaa,}, +{0x6f, 0xaa,}, + +{0x70, 0x72,}, /* 6c */ +{0x71, 0x82,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0x02,}, +{0x78, 0x24,}, /* 24 */ +{0x79, 0x49,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 6500.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x05,}, /*EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x91, 0x06,}, /*EXP Fix 8.00 fps*/ +{0x92, 0x32,}, +{0x93, 0xea,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xf8,}, /* AG Max */ +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0xa0,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, /* for wb speed 20120314 */ +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* for tracking 20120314 */ + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, /* for tracking 20120314 */ + +{0x41, 0x43,}, /* stable c_diff */ +{0x42, 0x22,}, /* stable c_sum */ +{0x43, 0xf1,}, +{0x44, 0x54,}, /* unstable c_diff */ +{0x45, 0x22,}, /* unstable c_sum */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* for A light */ + +{0x83, 0x56,}, /* R Max */ +{0x84, 0x1e,}, /* R Min */ +{0x85, 0x56,}, /* B Max */ +{0x86, 0x20,}, /* B Min */ + +{0x87, 0x4b,}, /* R Max */ +{0x88, 0x31,}, /* R Min */ +{0x89, 0x37,}, /* B Max */ +{0x8a, 0x29,}, /* B Min */ + +{0x8b, 0x3f,}, /* R Max */ +{0x8c, 0x37,}, /* R Min */ +{0x8d, 0x30,}, /* B Max */ +{0x8e, 0x2a,}, /* B Min */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x28,}, /* low temp Rgain */ +{0xb0, 0x26,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 */ +{0xb4, 0xbf,}, /* for tracking 20120314 */ +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131024 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHz:0x02, 48MHz:0x03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, + +{0xff, 0x28,}, /* NEED Delay 400ms */ +/* END of sr200pc20m_vt_common */ + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_VT_Init_Reg_60Hz[] = { + +/* SKT-VT - continuous */ +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x94,}, /* Enable Fixed Frame */ +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 14 ->0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /*Hblank 404*/ +{0x41, 0x94,}, +{0x42, 0x00,}, /*Vblank 20*/ +{0x43, 0x14,}, +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0e,}, /*BLC_TIME_TH_ON*/ +{0x91, 0x0e,}, /*BLC_TIME_TH_OFF */ +{0x92, 0xf0,}, /* BLC_AG_TH_ON */ +{0x93, 0xe8,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0e,}, /*DCDC_TIME_TH_ON*/ +{0xd5, 0x0e,}, /*DCDC_TIME_TH_OFF */ +{0xd6, 0xf0,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xe8,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* For Preview */ + +{0x40, 0x80,}, +{0x41, 0x20,}, /* Dyoffset */ +{0x50, 0xf0,}, /* Threshold Dyoffset */ + +{0x60, 0x6b,}, +{0x61, 0x7a,}, /* Sat B */ +{0x62, 0x72,}, /* Sat R */ +{0x63, 0xff,}, /* Th decolor_saturation */ +{0x64, 0xff,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* Cb_Pos_Sat */ +{0x6b, 0x74,}, /* Cb_Neg_Sat */ +{0x6c, 0x71,}, /* Cr_Pos_Sat */ +{0x6d, 0x8e,}, /* Cr_Neg_Sat */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, /* 20120224 0x06 -> 0x04 */ + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th */ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th */ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* For Preview */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, + +/* only for Preview DPC */ +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/* Dark2 */ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X Center */ +{0x21, 0x80,}, /* Y Center */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS(6500K) */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,}, /* Double_AG 37 */ +{0x19, 0x5d,}, /* Double_AG 36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xef,}, /* add 20120223 enable Dgain for Dark */ +{0x29, 0x0d,}, /* 20100305 ad -> 0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, /* add 20120223 */ +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0xaa,}, +{0x61, 0xaa,}, +{0x62, 0xaa,}, +{0x63, 0xaa,}, +{0x64, 0xaa,}, +{0x65, 0xaa,}, +{0x66, 0xab,}, +{0x67, 0xea,}, +{0x68, 0xab,}, +{0x69, 0xea,}, +{0x6a, 0xaa,}, +{0x6b, 0xaa,}, +{0x6c, 0xaa,}, +{0x6d, 0xaa,}, +{0x6e, 0xaa,}, +{0x6f, 0xaa,}, + +{0x70, 0x72,}, /* 6c */ +{0x71, 0x82,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0x02,}, +{0x78, 0x24,}, /* 24 */ +{0x79, 0x49,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 30.00 fps */ +{0x84, 0xa7,}, +{0x85, 0x2c,}, + +{0x86, 0x01,}, /*EXPMin 6360.08 fps*/ +{0x87, 0xff,}, + +{0x88, 0x05,}, /*EXP Max 8.57 fps */ +{0x89, 0xc9,}, +{0x8a, 0x1a,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xc0,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0xcb,}, + +{0x91, 0x06,}, /*EXP Fix 8.00 fps*/ +{0x92, 0x32,}, +{0x93, 0xe5,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 530.01 fps */ +{0x9d, 0xf4,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xff,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xf8,}, /* AG Max */ +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0xa0,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, /* for wb speed 20120314 */ +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* for tracking 20120314 */ + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, /* for tracking 20120314 */ + +{0x41, 0x43,}, /* stable c_diff */ +{0x42, 0x22,}, /* stable c_sum */ +{0x43, 0xf1,}, +{0x44, 0x54,}, /* unstable c_diff */ +{0x45, 0x22,}, /* unstable c_sum */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* for A light */ + +{0x83, 0x56,}, /* R Max */ +{0x84, 0x1e,}, /* R Min */ +{0x85, 0x56,}, /* B Max */ +{0x86, 0x20,}, /* B Min */ + +{0x87, 0x4b,}, /* R Max */ +{0x88, 0x31,}, /* R Min */ +{0x89, 0x37,}, /* B Max */ +{0x8a, 0x29,}, /* B Min */ + +{0x8b, 0x3f,}, /* R Max */ +{0x8c, 0x37,}, /* R Min */ +{0x8d, 0x30,}, /* B Max */ +{0x8e, 0x2a,}, /* B Min */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x28,}, /* low temp Rgain */ +{0xb0, 0x26,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 */ +{0xb4, 0xbf,}, /* for tracking 20120314 */ +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131024 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHz:0x02, 48MHz:0x03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, + +{0xff, 0x28,}, /* NEED Delay 400ms */ +/* END of sr200pc20m_vt_common */ + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_stop_stream[] = { +{0x03, 0x00,}, +{0x01, 0x01,}, +{0xff, 0x00,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_i2c_check[] = { +{0x03, 0x00,}, +{0x01, 0x00,}, + +{0xff, 0x0a,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Capture[] = { + +{0x03, 0x00,}, +{0x01, 0x31,}, /* b[0] set power sleep by preserving all register values, 0=OFF 1=ON */ + +{0x03, 0x22,}, /* Page 22 */ +{0x10, 0x69,}, /* AWB Off */ + +{0x03, 0x00,}, +{0x10, 0x00,}, /* Imge size, windowing, Hsync, Vsync */ + +{0x20, 0x00,}, /* windowing */ +{0x21, 0x0a,}, /* modify 20110929 0x0c -> 0x0a */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +/* Page10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, /* not defined in data sheet */ +{0x60, 0x63,}, /* color saturation */ + +/* Page12 */ /* Noise reduction */ +{0x03, 0x12,}, +{0x20, 0x0f,}, +{0x21, 0x0f,}, +{0x90, 0x5d,}, + +/* only for Preview DPC Off */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ /* Edge enhancement */ +{0x03, 0x13,}, +{0x10, 0xcb,}, /* Edge On */ +{0x80, 0xfd,}, + +/* PAGE 18 */ /* Image scaling */ +{0x03, 0x18,}, +{0x10, 0x00,}, /* Scaling Off */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x81,}, +{0x70, 0x85,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, +{0x1d, 0x0e,}, +{0x1e, 0x08,}, +{0x1f, 0x03,}, +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x80,}, /* 1600 x 1200 MiPi OutPut */ +{0x31, 0x0c,}, + +/* {0x30, 0x40,}, */ /* 800x600 MiPi OutPut */ +/* {0x31, 0x06,}, */ + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x03,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* Page0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, /* Dummy 750us */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, /* Sleep Off */ + +{0xff, 0x03,}, /* Increase from 30ms */ +/* END of sr200pc20m_capture. */ + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Capture_X_Flip[] = { +{0x03, 0x00,}, +{0x11, 0x91,}, /* B[0]_horizontal flip funtion(0:off,1:on) */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Capture_Y_Flip[] = { +{0x03, 0x00,}, +{0x11, 0x92,}, /* B[1]_vertical flip funtion(0:off,1:on) */ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M4[] = { +{0x03, 0x10,}, +{0x40, 0xd0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M3[] = { +{0x03, 0x10,}, +{0x40, 0xc0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M2[] = { +{0x03, 0x10,}, +{0x40, 0xb0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_M1[] = { +{0x03, 0x10,}, +{0x40, 0xa0,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_default[] = { +{0x03, 0x10,}, +{0x40, 0x00,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P1[] = { +{0x03, 0x10,}, +{0x40, 0x20,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P2[] = { +{0x03, 0x10,}, +{0x40, 0x30,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P3[] = { +{0x03, 0x10,}, +{0x40, 0x40,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_brightness_P4[] = { +{0x03, 0x10,}, +{0x40, 0x50,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M4[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x00,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M3[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x20,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M2[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x40,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_M1[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x60,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_default[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x40,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P1[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x60,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P2[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0x80,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P3[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0xa0,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_contrast_P4[] = { +{0x03,0x10,}, +{0x13,0x02,}, +{0x48,0xff,}, +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Normal[] = { +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x30,}, +{0x44, 0x80,}, +{0x45, 0x80,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Negative[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x38,}, +{0x44, 0x80,}, +{0x45, 0x80,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Gray[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x33,}, +{0x44, 0x80,}, +{0x45, 0x80,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Sepia[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x33,}, +{0x44, 0x70,}, +{0x45, 0x98,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Aqua[] = +{ +{0x03, 0x10,}, +{0x11, 0x03,}, +{0x12, 0x33,}, +{0x44, 0xb0,}, +{0x45, 0x40,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Vintage_Cold[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Vintage_Warm[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Posterize[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Solarize[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Washed[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Color1[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Color2[] = +{ + +}; +struct msm_camera_i2c_reg_conf sr200pc20_Effect_Color3[] = +{ + +}; + +/* WhiteBalance */ +struct msm_camera_i2c_reg_conf sr200pc20_WB_Auto[] = +{ +{0x03, 0x22,}, +{0x11, 0x2e,}, +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, +{0x83, 0x56,}, // R Max D65 +{0x84, 0x22,}, // R Min H +{0x85, 0x4F,}, // B Max H +{0x86, 0x20,}, // B Min D65 +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Daylight[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x3b,}, +{0x81, 0x20,}, +{0x82, 0x35,}, +{0x83, 0x3c,}, +{0x84, 0x3a,}, +{0x85, 0x36,}, +{0x86, 0x34,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Cloudy[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x49,}, +{0x81, 0x20,}, +{0x82, 0x2a,}, +{0x83, 0x4a,}, +{0x84, 0x48,}, +{0x85, 0x2b,}, +{0x86, 0x29,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Fluorescent[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x3c,}, +{0x81, 0x20,}, +{0x82, 0x49,}, +{0x83, 0x3e,}, +{0x84, 0x38,}, +{0x85, 0x4d,}, +{0x86, 0x44,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_WB_Incandescent[] = +{ +{0x03, 0x22,}, +{0x11, 0x2c,}, +{0x80, 0x20,}, +{0x81, 0x20,}, +{0x82, 0x58,}, +{0x83, 0x23,}, +{0x84, 0x1f,}, +{0x85, 0x58,}, +{0x86, 0x52,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Auto_fps_50hz[] = { + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank_360 */ +{0x41, 0x68,}, +{0x42, 0x00,}, +{0x43, 0x94,}, /* 148 */ + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0c,}, /* BLC_TIME_TH_ON */ +{0x91, 0x0c,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xc8,}, /* BLC_AG_TH_ON */ +{0x93, 0xc0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, /* B */ +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0c,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x0c,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xc8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xc0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x04,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th */ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th */ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ + +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* 3e */ +{0x50, 0x24,}, /* 28 */ +{0x60, 0x20,}, /* 24 */ +{0x70, 0x24,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0xf4,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /* EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 6500.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x05,}, /*EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, // R Max D65 +{0x84, 0x22,}, // R Min H +{0x85, 0x4F,}, // B Max H +{0x86, 0x20,}, // B Min D65 + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, +{0x8a, 0x29,}, + +{0x8b, 0x3c,}, +{0x8c, 0x38,}, +{0x8d, 0x32,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 0x1470 */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /* 10160x04 -> 0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, + +{0xff, 0x0a,}, /* NEED Delay 100ms */ + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x1c,}, /* AE off 50hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_Auto_fps_60hz[] = { + + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1mode */ +{0x11, 0x90,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, /* ESD Check Register */ +{0x0c, 0xaa,}, /* ESD Check Register */ +{0x0d, 0xaa,}, /* ESD Check Register */ + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929, 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929, 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /*Hblank 404*/ +{0x41, 0x94,}, +{0x42, 0x00,}, /*Vblank 110*/ +{0x43, 0x6e,}, + +{0x44, 0x09,}, /* VSCLIP */ + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x0f,}, /*BLC_TIME_TH_ON*/ +{0x91, 0x0f,}, /*BLC_TIME_TH_OFF */ +{0x92, 0xc8,}, /* BLC_AG_TH_ON */ +{0x93, 0xc0,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, /* B */ +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* OutDoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, /*add 20120430 */ +{0x59, 0x20,}, /*add 20120430 */ +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x0f,}, /*DCDC_TIME_TH_ON*/ +{0xd5, 0x0f,}, /*DCDC_TIME_TH_OFF */ +{0xd6, 0xc8,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xc0,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* 00: CrYCbY, 01: CbYCrY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x6b,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50 -> 30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ +{0x76, 0x01,}, /* ADD 20120522 */ +{0x79, 0x04,}, /* ADD 20120522 */ + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, + +{0x26, 0x68,}, /* Double_AG 31 -> 20 */ +{0x27, 0x62,}, /* Double_AG 34 -> 22 */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x03,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0f,}, +{0x46, 0x0c,}, +{0x47, 0x0b,}, + +/* Dark2 D-LPF th */ +{0x48, 0x88,}, +{0x49, 0x2c,}, +{0x4a, 0x80,}, +{0x4b, 0x0f,}, +{0x4c, 0x0c,}, +{0x4d, 0x0b,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x23,}, +{0x50, 0x80,}, +{0x51, 0x0f,}, +{0x52, 0x0c,}, +{0x53, 0x0c,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0x90,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x50,}, +{0x54, 0xa8,}, +{0x55, 0xa8,}, +{0x56, 0xb0,}, +{0x57, 0x7b,}, + +/* Dark2 th */ +{0x58, 0xa0,}, +{0x59, 0x40,}, +{0x5a, 0xb8,}, +{0x5b, 0xb8,}, +{0x5c, 0xc8,}, +{0x5d, 0x7b,}, + +/* Dark3 th */ +{0x5e, 0x9c,}, +{0x5f, 0x40,}, +{0x60, 0xc0,}, +{0x61, 0xc0,}, +{0x62, 0xc8,}, +{0x63, 0x7b,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* add 20120430 */ + +/* Dont Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x17,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xd5, 0x0f,}, +{0xD6, 0xff,}, +{0xd7, 0xff,}, +/* End */ + +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ + +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x09,}, +{0x63, 0x09,}, +{0x64, 0x09,}, +{0x65, 0x07,}, +{0x66, 0x07,}, +{0x67, 0x07,}, + +/* Dark2 Edge */ +{0x68, 0x08,}, +{0x69, 0x08,}, +{0x6a, 0x08,}, +{0x6b, 0x06,}, +{0x6c, 0x06,}, +{0x6d, 0x06,}, + +/* Dark3 Edge */ +{0x6e, 0x08,}, +{0x6f, 0x08,}, +{0x70, 0x08,}, +{0x71, 0x06,}, +{0x72, 0x06,}, +{0x73, 0x06,}, + +/* 2DY */ +{0x80, 0x00,}, /* For Preview */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* 3e */ +{0x50, 0x24,}, /* 28 */ +{0x60, 0x20,}, /* 24 */ +{0x70, 0x24,}, /* 28 */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x38,}, /* CMCOFSGM */ +{0x16, 0x28,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x00,}, +{0x51, 0x00,}, +{0x52, 0x00,}, +{0x53, 0x84,}, +{0x54, 0x20,}, +{0x55, 0x9c,}, +{0x56, 0x00,}, +{0x57, 0x00,}, +{0x58, 0x00,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x0e,}, +{0x32, 0x1e,}, +{0x33, 0x34,}, +{0x34, 0x56,}, +{0x35, 0x74,}, +{0x36, 0x8b,}, +{0x37, 0x9c,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc5,}, +{0x3b, 0xd2,}, +{0x3c, 0xdb,}, +{0x3d, 0xe5,}, +{0x3e, 0xeb,}, +{0x3f, 0xf3,}, +{0x40, 0xf8,}, +{0x41, 0xfd,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x0e,}, +{0x72, 0x1f,}, +{0x73, 0x3f,}, +{0x74, 0x5d,}, +{0x75, 0x75,}, +{0x76, 0x8a,}, +{0x77, 0x9c,}, +{0x78, 0xad,}, +{0x79, 0xbb,}, +{0x7a, 0xc6,}, +{0x7b, 0xd1,}, +{0x7c, 0xda,}, +{0x7d, 0xe3,}, +{0x7e, 0xea,}, +{0x7f, 0xf1,}, +{0x80, 0xf6,}, +{0x81, 0xfb,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0xff,}, +{0x2b, 0xf4,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, +{0x57, 0xa0,}, +{0x58, 0x20,}, +{0x59, 0x74,}, +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 30.00 fps */ +{0x84, 0xa7,}, +{0x85, 0x2c,}, + +{0x86, 0x01,}, /*EXPMin 6360.08 fps*/ +{0x87, 0xff,}, + +{0x88, 0x06,}, /*EXP Max 8.00 fps */ +{0x89, 0x32,}, +{0x8a, 0xe5,}, + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xc0,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0xcb,}, + +{0x98, 0x9d,}, +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 530.01 fps */ +{0x9d, 0xf4,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xff,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, /* Low On */ +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, /* Add 20120514 light stable */ + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, // R Max D65 +{0x84, 0x22,}, // R Min H +{0x85, 0x4F,}, // B Max H +{0x86, 0x20,}, // B Min D65 + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, +{0x8a, 0x29,}, + +{0x8b, 0x3c,}, +{0x8c, 0x38,}, +{0x8d, 0x32,}, +{0x8e, 0x2c,}, + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x3a,}, +{0x95, 0x32,}, +{0x96, 0x2b,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x78,}, +{0x9c, 0x77,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xb0,}, +{0xa1, 0x44,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* a2:b-2,R+2 b4:B-3,R+4 lowtemp b0 a1 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +/* {0x17, 0xcc,}, */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 0x1470 */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, /* 10160x04 -> 0x05*/ + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ: 0x02, 48MHz:0x03 */ +/* {0x17, 0xc4,}, */ /* MHSHIM */ +/* {0x17, 0xc0,}, */ /* MHSHIM */ +/* {0x17, 0x00,}, */ /* MHSHIM */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, + +{0x01, 0x30,}, + +{0xff, 0x0a,}, /* NEED Delay 100ms */ + +{0x03, 0x00,}, /* Sleep On */ +{0x01, 0x31,}, + +{0x03, 0x20,}, /* page 20 */ +{0x18, 0x30,}, /* for Preview */ +{0x10, 0x0c,}, /* AE off 60hz */ + +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* awb off */ + +{0x03, 0x00,}, /* page 0 */ +{0x10, 0x11,}, + +{0x20, 0x00,}, /* windowing, row start, high byte */ +{0x21, 0x02,}, /* windowing, row start, low byte */ /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, /* windowing, column start, high byte */ +{0x23, 0x0a,}, /* windowing, column start, low byte */ /* modify 20110929 0x14 -> 0x0a */ + +/* Page 10 */ +{0x03, 0x10,}, +{0x3f, 0x00,}, +{0x60, 0x63,}, + +/* Page12 */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* 0f */ +{0x21, 0x0f,}, /* 0f */ +{0x90, 0x5d,}, /* 5f */ + +/* only for Preview DPC */ +{0xd2, 0x67,}, +{0xd5, 0x02,}, +{0xd7, 0x18,}, + +/* Page13 */ +{0x03, 0x13,}, +{0x10, 0x4a,}, /* Edge Off */ +{0x80, 0x00,}, + +/* Page18 */ +{0x03, 0x18,}, +{0x10, 0x07,}, + +/* PAGE 48 TART */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2, orig 0x30 => 16.5, 0x60 => 32fps */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 : continuous -> 0x00 : not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640 x 480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x01,}, +{0x36, 0x03,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,},/* drivability 24MHZ:02, 48MHz:03 */ + +{0x50, 0x00,}, +/* PAGE 48 END */ + +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +{0x03, 0x22,}, +{0x10, 0xe9,}, /* AWB ON */ + +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, /* Sleep Off */ +{0x01, 0x30,}, + +}; + +struct msm_camera_i2c_reg_conf sr200pc20_24fps_Camcoder_50hz[] = { + +/* Recording 24fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank 280 */ +{0x41, 0x18,}, +{0x42, 0x00,}, /* Vblank 20 */ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x04,}, /* BLC_TIME_TH_ON */ +{0x91, 0x04,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xb0,}, /* BLC_AG_TH_ON */ +{0x93, 0xa8,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x04,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x04,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xb0,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa8,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x67,}, /* Setting For Camcorder 24 */ +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0x50,}, /* Double_AG 50->30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0xa0,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th */ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th */ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x36,}, /* CMCOFSGM */ +{0x16, 0x26,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 33.33 fps */ +{0x84, 0xdb,}, +{0x85, 0x50,}, + +{0x86, 0x01,}, /* EXPMin 8463.54 fps */ +{0x87, 0xe0,}, + +{0x88, 0x02,}, /*EXP Max 25.00 fps */ +{0x89, 0x79,}, +{0x8a, 0xc0,}, + +{0x8B, 0x9e,}, /*EXP100 */ +{0x8C, 0x70,}, + +{0x8D, 0x84,}, /*EXP120 */ +{0x8E, 0x30,}, + +{0x91, 0x02,}, /*EXP Fix 24.01 fps*/ +{0x92, 0x94,}, +{0x93, 0xf0,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x16,}, /*EXP Limit 705.30 fps */ +{0x9d, 0x80,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xe0,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb8,}, +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* 5e */ +{0x84, 0x22,}, /* 24 21 22 Spec AWB H modify */ +{0x85, 0x55,}, /* 54 51 4f Spec AWB H modify */ +{0x86, 0x20,}, /* 24 */ + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, /* 38 */ +{0x8a, 0x29,}, /* 2a */ + +{0x8b, 0x3c,}, /* R Max 3c->3e */ +{0x8c, 0x38,}, /* R Min */ +{0x8d, 0x32,}, /* B Max 32->33 */ +{0x8e, 0x2c,}, /* 2c */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x39,}, +{0x95, 0x30,}, +{0x96, 0x2c,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x77,}, +{0x9c, 0x66,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xc0,}, +{0xa1, 0x54,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x3c,}, /* MiPi Pllx 2.5 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* {0x14, 0x70,}, */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, /* 20121019 */ +{0x1d, 0x0f,}, /* 20121101 0x0e -> 0x0f */ +{0x1e, 0x08,}, /* 20121009 */ +{0x1f, 0x03,}, /* 20121101 0x05 -> 0x004 */ /* 0x04->0x03 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x35, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ +/* END of sr200pc20m_recording_50Hz_common*/ +}; + +struct msm_camera_i2c_reg_conf sr200pc20_24fps_Camcoder_60hz[] = { + +/* Recording 24fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x0c,}, /* AE off 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank 280 */ +{0x41, 0x18,}, +{0x42, 0x00,}, /* Vblank 20 */ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x04,}, /*BLC_TIME_TH_ON*/ +{0x91, 0x04,}, /*BLC_TIME_TH_OFF */ +{0x92, 0xb0,}, /* BLC_AG_TH_ON */ +{0x93, 0xa8,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x04,}, /*DCDC_TIME_TH_ON*/ +{0xd5, 0x04,}, /*DCDC_TIME_TH_OFF */ +{0xd6, 0xb0,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa8,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x67,}, /* Setting For Camcorder 24 */ +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0x50,}, /* Double_AG 50->30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0xa0,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th */ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th */ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x36,}, /* CMCOFSGM */ +{0x16, 0x26,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x02,}, /*EXP Normal 30.00 fps */ +{0x84, 0x10,}, +{0x85, 0xc0,}, + +{0x86, 0x01,}, /* EXPMin 8463.54 fps */ +{0x87, 0xe0,}, + +{0x88, 0x02,}, /*EXP Max 30.00 fps */ +{0x89, 0x10,}, +{0x8a, 0xc0,}, + +{0x8B, 0x9e,}, /*EXP100 */ +{0x8C, 0x70,}, + +{0x8D, 0x84,}, /*EXP120 */ +{0x8E, 0x30,}, + +{0x91, 0x02,}, /*EXP Fix 24.01 fps*/ +{0x92, 0x94,}, +{0x93, 0xf0,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x16,}, /*EXP Limit 705.30 fps */ +{0x9d, 0x80,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xe0,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb8,}, +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* 5e */ +{0x84, 0x22,}, /* 24 21 22 Spec AWB H modify */ +{0x85, 0x55,}, /* 54 51 4f Spec AWB H modify */ +{0x86, 0x20,}, /* 24 */ + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, /* 38 */ +{0x8a, 0x29,}, /* 2a */ + +{0x8b, 0x3c,}, /* R Max 3c->3e */ +{0x8c, 0x38,}, /* R Min */ +{0x8d, 0x32,}, /* B Max 32->33 */ +{0x8e, 0x2c,}, /* 2c */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x39,}, +{0x95, 0x30,}, +{0x96, 0x2c,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x77,}, +{0x9c, 0x66,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xc0,}, +{0xa1, 0x54,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x3c,}, /* MiPi Pllx 2.5 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* {0x14, 0x70,}, */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, /* 20121019 */ +{0x1d, 0x0f,}, /* 20121101 0x0e -> 0x0f */ +{0x1e, 0x08,}, /* 20121009 */ +{0x1f, 0x03,}, /* 20121101 0x05 -> 0x004 */ /* 0x04->0x03 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x35, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x8c,}, /* AE on 60hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x0a,}, /* NEED Delay 100ms */ +/* END of sr200pc20m_recording_50Hz_common*/ +}; + +#if 0 +static const u16 sr200pc20_15fps[] = { + +/* Recording 15fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank 360 */ +{0x41, 0x68,}, +{0x42, 0x00,}, /*Vblank 20*/ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x06,}, /* BLC_TIME_TH_ON */ +{0x91, 0x06,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xb0,}, /* BLC_AG_TH_ON */ +{0x93, 0xa8,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x06,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x06,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xb0,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa8,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x67,}, /* Setting For Camcorder 24 */ +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0x50,}, /* Double_AG 50->30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0xa0,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th */ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th */ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x36,}, /* CMCOFSGM */ +{0x16, 0x26,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, +/* PAGE 18 END */ + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 33.33 fps */ +{0x84, 0x7c,}, +{0x85, 0xdc,}, + +{0x86, 0x01,}, /* EXPMin 5950.00 fps */ +{0x87, 0xf4,}, + +{0x88, 0x02,}, /*EXP Max 16.67 fps */ +{0x89, 0xf9,}, +{0x8a, 0xb8,} + +{0x8B, 0x7e,}, /*EXP100 */ +{0x8C, 0xf4,}, + +{0x8D, 0x69,}, /*EXP120 */ +{0x8E, 0x78,}, + +{0x91, 0x03,}, /*EXP Fix 15.01 fps*/ +{0x92, 0x4d,}, +{0x93, 0xb4,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x17,}, /*EXP Limit 541.67 fps */ +{0x9d, 0x70,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xf4,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb8,}, +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* 5e */ +{0x84, 0x22,}, /* 24 21 22 Spec AWB H modify */ +{0x85, 0x55,}, /* 54 51 4f Spec AWB H modify */ +{0x86, 0x20,}, /* 24 */ + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, /* 38 */ +{0x8a, 0x29,}, /* 2a */ + +{0x8b, 0x3c,}, /* R Max 3c-> 3e */ +{0x8c, 0x38,}, /* R Min */ +{0x8d, 0x32,}, /* B Max 32->33 */ +{0x8e, 0x2c,}, /* 2c */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x39,}, +{0x95, 0x30,}, +{0x96, 0x2c,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x77,}, +{0x9c, 0x66,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xc0,}, +{0xa1, 0x54,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x30,}, /* MiPi Pllx2 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 {0x10, continuous -> 0x00, not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* {0x14, 0x70,}, */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0c,}, +{0x1d, 0x0f,}, /* 20121004 */ +{0x1e, 0x06,}, +{0x1f, 0x02,}, /* 0x05->0x03 20131101 */ /* 0x03->0x02 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* CLK LP -> HS Prepare time 24MHz:0x02, 48MHz:0x03 */ +{0x35, 0x03,}, +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x02,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x28,}, /* NEED Delay 400ms */ +/* END of sr200pc20m_recording_50Hz_common*/ + +}; + +static const u16 sr200pc20_20fps[] = { + +/* Recording 24fps Anti-Flicker 50Hz END of Initial */ +/* CAMERA INITIAL for Self Recording 24 Fixed Frame */ + +{0x01, 0x31,}, /* sleep on */ +{0x01, 0x33,}, /* sleep on */ +{0x01, 0x31,}, /* sleep on */ +{0x08, 0x2f,}, /* sleep on */ +{0x0a, 0x00,}, /* sleep on */ + +/* PAGE 20 */ +{0x03, 0x20,}, /* page 20 */ +{0x10, 0x1c,}, /* AE off 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, /* page 22 */ +{0x10, 0x69,}, /* AWB off */ + +{0x03, 0x12,}, +{0x20, 0x00,}, +{0x21, 0x00,}, + +{0x03, 0x13,}, +{0x10, 0xcb,}, + +/* Initial Start */ +/* PAGE 0 START */ +{0x03, 0x00,}, +{0x10, 0x11,}, /* Vsync Active High B:[3], Sub1/2 + Preview 1 */ +{0x11, 0x94,}, +{0x12, 0x04,}, /* Pclk Falling Edge B:[2] */ + +{0x0b, 0xaa,}, +{0x0c, 0xaa,}, +{0x0d, 0xaa,}, + +{0x20, 0x00,}, +{0x21, 0x02,}, /* modify 20110929 0x04 -> 0x02 */ +{0x22, 0x00,}, +{0x23, 0x0a,}, /* modify 20110929 0x14 -> 0x0a */ + +{0x24, 0x04,}, +{0x25, 0xb0,}, +{0x26, 0x06,}, +{0x27, 0x40,}, + +{0x28, 0x0c,}, +{0x29, 0x04,}, +{0x2a, 0x02,}, +{0x2b, 0x04,}, +{0x2c, 0x06,}, +{0x2d, 0x02,}, + +{0x40, 0x01,}, /* Hblank 280 */ +{0x41, 0x18,}, +{0x42, 0x00,}, /* Vblank 20 */ +{0x43, 0x14,}, + +{0x45, 0x04,}, +{0x46, 0x18,}, +{0x47, 0xd8,}, + +/* BLC */ +{0x80, 0x2e,}, +{0x81, 0x7e,}, +{0x82, 0x90,}, +{0x83, 0x00,}, +{0x84, 0x0c,}, +{0x85, 0x00,}, +{0x90, 0x05,}, /* BLC_TIME_TH_ON */ +{0x91, 0x05,}, /* BLC_TIME_TH_OFF */ +{0x92, 0xb0,}, /* BLC_AG_TH_ON */ +{0x93, 0xa8,}, /* BLC_AG_TH_OFF */ +{0x94, 0xff,}, +{0x95, 0xff,}, +{0x96, 0xdc,}, +{0x97, 0xfe,}, +{0x98, 0x38,}, + +/* Dark BLC */ +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +/* Normal BLC */ +{0xa8, 0x43,}, +{0xaa, 0x43,}, +{0xac, 0x43,}, +{0xae, 0x43,}, + +/* Outdoor BLC */ +{0x99, 0x43,}, +{0x9a, 0x43,}, +{0x9b, 0x43,}, +{0x9c, 0x43,}, +/* PAGE 0 END */ + +/* PAGE 2 START */ +{0x03, 0x02,}, +{0x12, 0x03,}, +{0x13, 0x03,}, +{0x16, 0x00,}, +{0x17, 0x8C,}, +{0x18, 0x4c,}, /* Double_AG */ +{0x19, 0x00,}, +{0x1a, 0x39,}, /* Double_AG 38 -> 39 */ +{0x1c, 0x09,}, +{0x1d, 0x40,}, +{0x1e, 0x30,}, +{0x1f, 0x10,}, + +{0x20, 0x77,}, +{0x21, 0xde,}, +{0x22, 0xa7,}, +{0x23, 0x30,}, /* CLAMP */ +{0x27, 0x3c,}, +{0x2b, 0x80,}, +{0x2e, 0x00,}, +{0x2f, 0x00,}, +{0x30, 0x05,}, /* For Hi-253 never no change 0x05 */ + +{0x50, 0x20,}, +{0x51, 0x1c,}, /* add 20110826 */ +{0x52, 0x01,}, /* 0x03 -> 0x01 */ +{0x53, 0xc1,}, /* add 20110818 */ +{0x54, 0xc0,}, +{0x55, 0x1c,}, +{0x56, 0x11,}, +{0x58, 0x22,}, +{0x59, 0x20,}, +{0x5d, 0xa2,}, +{0x5e, 0x5a,}, + +{0x60, 0x87,}, +{0x61, 0x99,}, +{0x62, 0x88,}, +{0x63, 0x97,}, +{0x64, 0x88,}, +{0x65, 0x97,}, + +{0x67, 0x0c,}, +{0x68, 0x0c,}, +{0x69, 0x0c,}, + +{0x72, 0x89,}, +{0x73, 0x96,}, +{0x74, 0x89,}, +{0x75, 0x96,}, +{0x76, 0x89,}, +{0x77, 0x96,}, + +{0x7c, 0x85,}, +{0x7d, 0xaf,}, +{0x80, 0x01,}, +{0x81, 0x7f,}, +{0x82, 0x13,}, +{0x83, 0x24,}, +{0x84, 0x7d,}, +{0x85, 0x81,}, +{0x86, 0x7d,}, +{0x87, 0x81,}, + +{0x92, 0x48,}, +{0x93, 0x54,}, +{0x94, 0x7d,}, +{0x95, 0x81,}, +{0x96, 0x7d,}, +{0x97, 0x81,}, + +{0xa0, 0x02,}, +{0xa1, 0x7b,}, +{0xa2, 0x02,}, +{0xa3, 0x7b,}, +{0xa4, 0x7b,}, +{0xa5, 0x02,}, +{0xa6, 0x7b,}, +{0xa7, 0x02,}, + +{0xa8, 0x85,}, +{0xa9, 0x8c,}, +{0xaa, 0x85,}, +{0xab, 0x8c,}, +{0xac, 0x10,}, +{0xad, 0x16,}, +{0xae, 0x10,}, +{0xaf, 0x16,}, + +{0xb0, 0x99,}, +{0xb1, 0xa3,}, +{0xb2, 0xa4,}, +{0xb3, 0xae,}, +{0xb4, 0x9b,}, +{0xb5, 0xa2,}, +{0xb6, 0xa6,}, +{0xb7, 0xac,}, +{0xb8, 0x9b,}, +{0xb9, 0x9f,}, +{0xba, 0xa6,}, +{0xbb, 0xaa,}, +{0xbc, 0x9b,}, +{0xbd, 0x9f,}, +{0xbe, 0xa6,}, +{0xbf, 0xaa,}, + +{0xc4, 0x2c,}, +{0xc5, 0x43,}, +{0xc6, 0x63,}, +{0xc7, 0x79,}, + +{0xc8, 0x2d,}, +{0xc9, 0x42,}, +{0xca, 0x2d,}, +{0xcb, 0x42,}, +{0xcc, 0x64,}, +{0xcd, 0x78,}, +{0xce, 0x64,}, +{0xcf, 0x78,}, +{0xd0, 0x0a,}, +{0xd1, 0x09,}, +{0xd4, 0x05,}, /* DCDC_TIME_TH_ON */ +{0xd5, 0x05,}, /* DCDC_TIME_TH_OFF */ +{0xd6, 0xb0,}, /* DCDC_AG_TH_ON */ +{0xd7, 0xa8,}, /* DCDC_AG_TH_OFF */ +{0xe0, 0xc4,}, +{0xe1, 0xc4,}, +{0xe2, 0xc4,}, +{0xe3, 0xc4,}, +{0xe4, 0x00,}, +{0xe8, 0x80,}, +{0xe9, 0x40,}, +{0xea, 0x7f,}, + +{0xf0, 0x01,}, +{0xf1, 0x01,}, +{0xf2, 0x01,}, +{0xf3, 0x01,}, +{0xf4, 0x01,}, + +/* PAGE 2 END */ + +/* PAGE 3 */ +{0x03, 0x03,}, +{0x10, 0x10,}, +/* PAGE 3 END */ + +/* PAGE 10 START */ +{0x03, 0x10,}, +{0x10, 0x01,}, /* CrYCbY */ +{0x12, 0x30,}, +{0x20, 0x00,}, +{0x30, 0x00,}, +{0x31, 0x00,}, +{0x32, 0x00,}, +{0x33, 0x00,}, + +{0x34, 0x30,}, +{0x35, 0x00,}, +{0x36, 0x00,}, +{0x38, 0x00,}, +{0x3e, 0x58,}, +{0x3f, 0x00,}, /* Setting For Camcorder 24 */ + +{0x40, 0x80,}, +{0x41, 0x00,}, + +{0x60, 0x67,}, /* Setting For Camcorder 24 */ +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0x50,}, /* Double_AG 50->30 */ +{0x64, 0x80,}, + +{0x66, 0x42,}, +{0x67, 0x00,}, + +{0x6a, 0x8a,}, /* 8a */ +{0x6b, 0x74,}, /* 74 */ +{0x6c, 0x71,}, /* 7e */ +{0x6d, 0x8e,}, /* 8e */ + +{0x76, 0x01,}, +{0x79, 0x04,}, + +/* PAGE 11 START */ +{0x03, 0x11,}, +{0x10, 0x7f,}, +{0x11, 0x40,}, +{0x12, 0x0a,}, /* Blue Max-Filter Delete */ +{0x13, 0xb9,}, /* 20120307 0xbb -> 0xb9 */ + +{0x26, 0x68,}, /* Double_AG */ +{0x27, 0x62,}, /* Double_AG */ +{0x28, 0x0f,}, +{0x29, 0x10,}, +{0x2b, 0x30,}, +{0x2c, 0x32,}, + +/* Out2 D-LPF th */ +{0x30, 0x70,}, +{0x31, 0x10,}, +{0x32, 0x58,}, +{0x33, 0x09,}, +{0x34, 0x06,}, +{0x35, 0x03,}, + +/* Out1 D-LPF th */ +{0x36, 0x70,}, +{0x37, 0x18,}, +{0x38, 0x58,}, +{0x39, 0x20,}, +{0x3a, 0x1f,}, +{0x3b, 0x03,}, + +/* Indoor D-LPF th */ +{0x3c, 0x80,}, +{0x3d, 0x18,}, +{0x3e, 0x80,}, +{0x3f, 0x0c,}, +{0x40, 0x09,}, +{0x41, 0x06,}, + +/* Dark1 D-LPF th */ +{0x42, 0x80,}, +{0x43, 0x18,}, +{0x44, 0x80,}, +{0x45, 0x0c,}, +{0x46, 0x09,}, +{0x47, 0x06,}, + +/* Dark2 D-LPF th */ +{0x48, 0x80,}, +{0x49, 0x18,}, +{0x4a, 0x80,}, +{0x4b, 0x0c,}, +{0x4c, 0x09,}, +{0x4d, 0x06,}, + +/* Dark3 D-LPF th */ +{0x4e, 0x80,}, +{0x4f, 0x18,}, +{0x50, 0x80,}, +{0x51, 0x0c,}, +{0x52, 0x09,}, +{0x53, 0x06,}, + +{0x54, 0x11,}, +{0x55, 0x17,}, +{0x56, 0x20,}, +{0x57, 0x01,}, +{0x58, 0x00,}, +{0x59, 0x00,}, + +{0x5a, 0x18,}, +{0x5b, 0x00,}, +{0x5c, 0x00,}, + +{0x60, 0x3f,}, +{0x62, 0x60,}, +{0x70, 0x06,}, +/* PAGE 11 END */ + +/* PAGE 12 START */ +{0x03, 0x12,}, +{0x20, 0x0f,}, /* Setting For Camcorder 24 */ +{0x21, 0x0f,}, /* Setting For Camcorder 24 */ + +{0x25, 0x00,}, /* 0x30 */ + +{0x28, 0x00,}, +{0x29, 0x00,}, +{0x2a, 0x00,}, + +{0x30, 0x50,}, +{0x31, 0x18,}, +{0x32, 0x32,}, +{0x33, 0x40,}, +{0x34, 0x50,}, +{0x35, 0x70,}, +{0x36, 0xa0,}, + +/* Out2 th */ +{0x40, 0xa0,}, +{0x41, 0x40,}, +{0x42, 0xa0,}, +{0x43, 0x90,}, +{0x44, 0x90,}, +{0x45, 0x80,}, + +/* Out1 th */ +{0x46, 0xb0,}, +{0x47, 0x55,}, +{0x48, 0xb0,}, +{0x49, 0xb0,}, +{0x4a, 0x90,}, +{0x4b, 0x80,}, + +/* Indoor th */ +{0x4c, 0xb0,}, +{0x4d, 0x40,}, +{0x4e, 0x90,}, +{0x4f, 0x90,}, +{0x50, 0xa0,}, +{0x51, 0x80,}, + +/* Dark1 th */ +{0x52, 0xb0,}, +{0x53, 0x40,}, +{0x54, 0x90,}, +{0x55, 0x90,}, +{0x56, 0xa0,}, +{0x57, 0x78,}, + +/* Dark2 th */ +{0x58, 0xb0,}, +{0x59, 0x40,}, +{0x5a, 0x90,}, +{0x5b, 0x90,}, +{0x5c, 0xa0,}, +{0x5d, 0x78,}, + +/* Dark3 th */ +{0x5e, 0xb0,}, +{0x5f, 0x40,}, +{0x60, 0x90,}, +{0x61, 0x90,}, +{0x62, 0xa0,}, +{0x63, 0x78,}, + +{0x70, 0x15,}, +{0x71, 0x01,}, /* Don't Touch register */ + +{0x72, 0x18,}, +{0x73, 0x01,}, /* Don't Touch register */ + +{0x74, 0x25,}, +{0x75, 0x15,}, + +{0x80, 0x20,}, +{0x81, 0x40,}, +{0x82, 0x65,}, +{0x85, 0x1a,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x90, 0x5d,}, /* Setting For Camcorder 24 */ + +/* Don't Touch register */ +{0xD0, 0x0c,}, +{0xD1, 0x80,}, +{0xD2, 0x67,}, +{0xD3, 0x00,}, +{0xD4, 0x00,}, +{0xD5, 0x02,}, +{0xD6, 0xff,}, +{0xD7, 0x18,}, +/* End */ +{0x3b, 0x06,}, +{0x3c, 0x06,}, + +/* Don't Touch register */ +{0xc5, 0x30,}, /* 55 -> 48 */ +{0xc6, 0x2a,}, /* 48 -> 40 */ +/* PAGE 12 END */ + +/* PAGE 13 START */ +{0x03, 0x13,}, +{0x10, 0xcb,}, +{0x11, 0x7b,}, +{0x12, 0x07,}, +{0x14, 0x00,}, + +{0x20, 0x15,}, +{0x21, 0x13,}, +{0x22, 0x33,}, +{0x23, 0x05,}, +{0x24, 0x09,}, + +{0x25, 0x0a,}, + +{0x26, 0x18,}, +{0x27, 0x30,}, +{0x29, 0x12,}, +{0x2a, 0x50,}, + +/* Low clip th */ +{0x2b, 0x02,}, +{0x2c, 0x02,}, +{0x25, 0x06,}, +{0x2d, 0x0c,}, +{0x2e, 0x12,}, +{0x2f, 0x12,}, + +/* Out2 Edge */ +{0x50, 0x10,}, +{0x51, 0x14,}, +{0x52, 0x12,}, +{0x53, 0x0c,}, +{0x54, 0x0f,}, +{0x55, 0x0c,}, + +/* Out1 Edge */ +{0x56, 0x0f,}, +{0x57, 0x12,}, +{0x58, 0x12,}, +{0x59, 0x09,}, +{0x5a, 0x0c,}, +{0x5b, 0x0c,}, + +/* Indoor Edge */ +{0x5c, 0x0a,}, +{0x5d, 0x0b,}, +{0x5e, 0x0a,}, +{0x5f, 0x08,}, +{0x60, 0x09,}, +{0x61, 0x08,}, + +/* Dark1 Edge */ +{0x62, 0x0a,}, +{0x63, 0x0b,}, +{0x64, 0x0a,}, +{0x65, 0x08,}, +{0x66, 0x09,}, +{0x67, 0x08,}, + +/* Dark2 Edge */ +{0x68, 0x0a,}, +{0x69, 0x0b,}, +{0x6a, 0x0a,}, +{0x6b, 0x08,}, +{0x6c, 0x09,}, +{0x6d, 0x08,}, + +/* Dark3 Edge */ +{0x6e, 0x0a,}, +{0x6f, 0x0b,}, +{0x70, 0x0a,}, +{0x71, 0x08,}, +{0x72, 0x09,}, +{0x73, 0x08,}, + +/* 2DY */ +{0x80, 0xfd,}, /* Setting For Camcorder 24 */ +{0x81, 0x1f,}, +{0x82, 0x05,}, +{0x83, 0x31,}, + +{0x90, 0x05,}, +{0x91, 0x05,}, +{0x92, 0x33,}, +{0x93, 0x30,}, +{0x94, 0x03,}, +{0x95, 0x14,}, +{0x97, 0x20,}, +{0x99, 0x20,}, + +{0xa0, 0x01,}, +{0xa1, 0x02,}, +{0xa2, 0x01,}, +{0xa3, 0x02,}, +{0xa4, 0x05,}, +{0xa5, 0x05,}, +{0xa6, 0x07,}, +{0xa7, 0x08,}, +{0xa8, 0x07,}, +{0xa9, 0x08,}, +{0xaa, 0x07,}, +{0xab, 0x08,}, + +/* Out2 */ +{0xb0, 0x22,}, +{0xb1, 0x2a,}, +{0xb2, 0x28,}, +{0xb3, 0x22,}, +{0xb4, 0x2a,}, +{0xb5, 0x28,}, + +/* Out1 */ +{0xb6, 0x22,}, +{0xb7, 0x2a,}, +{0xb8, 0x28,}, +{0xb9, 0x22,}, +{0xba, 0x2a,}, +{0xbb, 0x28,}, + +/* Indoor */ +{0xbc, 0x25,}, +{0xbd, 0x2a,}, +{0xbe, 0x27,}, +{0xbf, 0x25,}, +{0xc0, 0x2a,}, +{0xc1, 0x27,}, + +/* Dark1 */ +{0xc2, 0x1e,}, +{0xc3, 0x24,}, +{0xc4, 0x20,}, +{0xc5, 0x1e,}, +{0xc6, 0x24,}, +{0xc7, 0x20,}, + +/*Dark2*/ +{0xc8, 0x18,}, +{0xc9, 0x20,}, +{0xca, 0x1e,}, +{0xcb, 0x18,}, +{0xcc, 0x20,}, +{0xcd, 0x1e,}, + +/* Dark3 */ +{0xce, 0x18,}, +{0xcf, 0x20,}, +{0xd0, 0x1e,}, +{0xd1, 0x18,}, +{0xd2, 0x20,}, +{0xd3, 0x1e,}, +/* PAGE 13 END */ + +/* PAGE 14 START */ +{0x03, 0x14,}, +{0x10, 0x11,}, + +{0x14, 0x80,}, /* GX */ +{0x15, 0x80,}, /* GY */ +{0x16, 0x80,}, /* RX */ +{0x17, 0x80,}, /* RY */ +{0x18, 0x80,}, /* BX */ +{0x19, 0x80,}, /* BY */ + +{0x20, 0x80,}, /* X */ +{0x21, 0x80,}, /* Y */ + +{0x22, 0x80,}, +{0x23, 0x80,}, +{0x24, 0x80,}, + +{0x30, 0xc8,}, +{0x31, 0x2b,}, +{0x32, 0x00,}, +{0x33, 0x00,}, +{0x34, 0x90,}, + +{0x40, 0x34,}, /* LSC Red */ +{0x50, 0x24,}, /* LSC Gr */ +{0x60, 0x20,}, /* LSC Blue */ +{0x70, 0x24,}, /* LSC Gb */ +/* PAGE 14 END */ + +/* PAGE 15 START */ +{0x03, 0x15,}, +{0x10, 0x0f,}, + +/* Rstep H 16 */ +/* Rstep L 14 */ +{0x14, 0x46,}, /* CMCOFSGH */ +{0x15, 0x36,}, /* CMCOFSGM */ +{0x16, 0x26,}, /* CMCOFSGL */ +{0x17, 0x2f,}, /* CMC SIGN */ + +/* CMC */ +{0x30, 0x8f,}, +{0x31, 0x59,}, +{0x32, 0x0a,}, +{0x33, 0x15,}, +{0x34, 0x5b,}, +{0x35, 0x06,}, +{0x36, 0x07,}, +{0x37, 0x40,}, +{0x38, 0x87,}, + +/* CMC OFS */ +{0x40, 0x94,}, +{0x41, 0x20,}, +{0x42, 0x89,}, +{0x43, 0x84,}, +{0x44, 0x03,}, +{0x45, 0x01,}, +{0x46, 0x88,}, +{0x47, 0x9c,}, +{0x48, 0x28,}, + +/* CMC POFS */ +{0x50, 0x02,}, +{0x51, 0x82,}, +{0x52, 0x00,}, +{0x53, 0x07,}, +{0x54, 0x11,}, +{0x55, 0x98,}, +{0x56, 0x00,}, +{0x57, 0x0b,}, +{0x58, 0x8b,}, + +{0x80, 0x00,}, +{0x85, 0x80,}, +{0x87, 0x02,}, +{0x88, 0x00,}, +{0x89, 0x00,}, +{0x8a, 0x00,}, +/* PAGE 15 END */ + +/* PAGE 16 START */ +{0x03, 0x16,}, +{0x10, 0x31,}, +{0x18, 0x5e,},/* Double_AG 5e->37 */ +{0x19, 0x5d,},/* Double_AG 5e->36 */ +{0x1a, 0x0e,}, +{0x1b, 0x01,}, +{0x1c, 0xdc,}, +{0x1d, 0xfe,}, + +/* GMA Default */ +{0x30, 0x00,}, +{0x31, 0x08,}, +{0x32, 0x1c,}, +{0x33, 0x32,}, +{0x34, 0x54,}, +{0x35, 0x70,}, +{0x36, 0x87,}, +{0x37, 0x9a,}, +{0x38, 0xaa,}, +{0x39, 0xb9,}, +{0x3a, 0xc4,}, +{0x3b, 0xcf,}, +{0x3c, 0xd8,}, +{0x3d, 0xe0,}, +{0x3e, 0xe9,}, +{0x3f, 0xf0,}, +{0x40, 0xf7,}, +{0x41, 0xfc,}, +{0x42, 0xff,}, + +{0x50, 0x00,}, +{0x51, 0x08,}, +{0x52, 0x1e,}, +{0x53, 0x36,}, +{0x54, 0x5a,}, +{0x55, 0x75,}, +{0x56, 0x8d,}, +{0x57, 0xa1,}, +{0x58, 0xb2,}, +{0x59, 0xbe,}, +{0x5a, 0xc9,}, +{0x5b, 0xd2,}, +{0x5c, 0xdb,}, +{0x5d, 0xe3,}, +{0x5e, 0xeb,}, +{0x5f, 0xf0,}, +{0x60, 0xf5,}, +{0x61, 0xf7,}, +{0x62, 0xf8,}, + +{0x70, 0x00,}, +{0x71, 0x08,}, +{0x72, 0x1c,}, +{0x73, 0x32,}, +{0x74, 0x54,}, +{0x75, 0x70,}, +{0x76, 0x87,}, +{0x77, 0x9a,}, +{0x78, 0xaa,}, +{0x79, 0xb9,}, +{0x7a, 0xc4,}, +{0x7b, 0xcf,}, +{0x7c, 0xd8,}, +{0x7d, 0xe0,}, +{0x7e, 0xe9,}, +{0x7f, 0xf0,}, +{0x80, 0xf7,}, +{0x81, 0xfc,}, +{0x82, 0xff,}, +/* PAGE 16 END */ + +/* PAGE 17 START */ +{0x03, 0x17,}, +{0x10, 0xf7,}, +/* PAGE 17 END */ + +/* 640x480 size */ +{0x03, 0x18,}, +{0x10, 0x07,}, +{0x11, 0x00,}, +{0x12, 0x58,}, +{0x20, 0x05,}, +{0x21, 0x00,}, +{0x22, 0x01,}, +{0x23, 0xe0,}, +{0x24, 0x00,}, /* X start position */ +{0x25, 0x08,}, +{0x26, 0x00,}, /* Y start position */ +{0x27, 0x02,}, +{0x28, 0x05,}, /* X End position */ +{0x29, 0x08,}, +{0x2a, 0x01,}, /* Y End position */ +{0x2b, 0xe2,}, +{0x2c, 0x0a,}, +{0x2d, 0x00,}, +{0x2e, 0x0a,}, +{0x2f, 0x00,}, +{0x30, 0x46,}, +{0x15, 0x01,}, + +/* PAGE 20 START */ +{0x03, 0x20,}, +{0x11, 0x1c,}, +{0x18, 0x30,}, +{0x1a, 0x08,}, +{0x20, 0x05,}, +{0x21, 0x30,}, +{0x22, 0x10,}, +{0x23, 0x00,}, +{0x24, 0x00,}, + +{0x28, 0xe7,}, +{0x29, 0x0d,}, /* 20100305 ad->0d */ +{0x2a, 0x03,}, +{0x2b, 0xf5,}, + +{0x2c, 0xc2,}, +{0x2d, 0x5f,}, +{0x2e, 0x33,}, +{0x30, 0xf8,}, +{0x32, 0x03,}, +{0x33, 0x2e,}, +{0x34, 0x30,}, +{0x35, 0xd4,}, +{0x36, 0xfe,}, +{0x37, 0x32,}, +{0x38, 0x04,}, +{0x39, 0x22,}, +{0x3a, 0xde,}, +{0x3b, 0x22,}, +{0x3c, 0xde,}, + +{0x50, 0x45,}, +{0x51, 0x88,}, + +{0x56, 0x27,}, /* for tracking 20120314 */ +{0x57, 0xa0,}, /* for tracking 20120314 */ +{0x58, 0x20,}, /* for tracking 20120314 */ +{0x59, 0x74,}, /* for tracking 20120314 */ +{0x5a, 0x04,}, + +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +{0x70, 0x70,}, /* 6c */ +{0x71, 0x80,}, /* 82(+8) */ + +{0x76, 0x43,}, +{0x77, 0xE2,}, +{0x78, 0x23,}, /* 24 */ +{0x79, 0x43,}, /* Y Target 70 => 25, 72 => 26 */ +{0x7a, 0x23,}, /* 23 */ +{0x7b, 0x22,}, /* 22 */ +{0x7d, 0x23,}, + +{0x83, 0x01,}, /*EXP Normal 33.33 fps */ +{0x84, 0xdb,}, +{0x85, 0x50,}, + +{0x86, 0x01,}, /* EXPMin 8463.54 fps */ +{0x87, 0xe0,}, + +{0x88, 0x02,}, /*EXP Max 25.00 fps */ +{0x89, 0x79,}, +{0x8a, 0xc0,} + +{0x8B, 0x9e,}, /*EXP100 */ +{0x8C, 0x70,}, + +{0x8D, 0x84,}, /*EXP120 */ +{0x8E, 0x30,}, + +{0x91, 0x03,}, /*EXP Fix 20.01 fps*/ +{0x92, 0x19,}, +{0x93, 0x20,}, + +{0x98, 0x9d,}, /* 9d */ +{0x99, 0x45,}, +{0x9a, 0x0d,}, +{0x9b, 0xde,}, + +{0x9c, 0x16,}, /*EXP Limit 705.30 fps */ +{0x9d, 0x80,}, + +{0x9e, 0x01,}, /*EXP Unit */ +{0x9f, 0xe0,}, + +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xb8,}, +{0xb3, 0x18,}, +{0xb4, 0x1a,}, +{0xb5, 0x44,}, +{0xb6, 0x2f,}, +{0xb7, 0x28,}, +{0xb8, 0x25,}, +{0xb9, 0x22,}, +{0xba, 0x21,}, +{0xbb, 0x20,}, +{0xbc, 0x32,}, +{0xbd, 0x32,}, + +{0xc0, 0x10,}, +{0xc1, 0x2b,}, +{0xc2, 0x2b,}, +{0xc3, 0x2b,}, +{0xc4, 0x08,}, + +{0xc8, 0x80,}, +{0xc9, 0x80,}, +/* PAGE 20 END */ + +/* PAGE 22 START */ +{0x03, 0x22,}, +{0x10, 0xfd,}, +{0x11, 0x2e,}, +{0x19, 0x01,}, +{0x20, 0x30,}, +{0x21, 0x40,}, +{0x24, 0x01,}, +{0x25, 0x7e,}, + +{0x30, 0x80,}, +{0x31, 0x80,}, +{0x38, 0x11,}, +{0x39, 0x34,}, +{0x40, 0xe4,}, + +{0x41, 0x43,}, /* 33 */ +{0x42, 0x22,}, /* 22 */ +{0x43, 0xf1,}, /* f6 */ +{0x44, 0x54,}, /* 44 */ +{0x45, 0x22,}, /* 33 */ +{0x46, 0x02,}, +{0x50, 0xb2,}, +{0x51, 0x81,}, +{0x52, 0x98,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* 5e */ +{0x84, 0x22,}, /* 24 21 22 Spec AWB H modify */ +{0x85, 0x55,}, /* 54 51 4f Spec AWB H modify */ +{0x86, 0x20,}, /* 24 */ + +{0x87, 0x41,}, +{0x88, 0x31,}, +{0x89, 0x39,}, /* 38 */ +{0x8a, 0x29,}, /* 2a */ + +{0x8b, 0x3c,}, /* R Max 3c->3e */ +{0x8c, 0x38,}, /* R Min */ +{0x8d, 0x32,}, /* B Max 32->33 */ +{0x8e, 0x2c,}, /* 2c */ + +{0x8f, 0x5c,}, +{0x90, 0x5b,}, +{0x91, 0x57,}, +{0x92, 0x4f,}, +{0x93, 0x41,}, +{0x94, 0x39,}, +{0x95, 0x30,}, +{0x96, 0x2c,}, +{0x97, 0x23,}, +{0x98, 0x20,}, +{0x99, 0x1f,}, +{0x9a, 0x1f,}, + +{0x9b, 0x77,}, +{0x9c, 0x66,}, +{0x9d, 0x48,}, +{0x9e, 0x38,}, +{0x9f, 0x30,}, + +{0xa0, 0xc0,}, +{0xa1, 0x54,}, +{0xa2, 0x6f,}, +{0xa3, 0xff,}, + +{0xa4, 0x14,}, /* 1500fps */ +{0xa5, 0x2c,}, /* 700fps */ +{0xa6, 0xcf,}, + +{0xad, 0x40,}, +{0xae, 0x4a,}, + +{0xaf, 0x2f,}, /* low temp Rgain */ +{0xb0, 0x2d,}, /* low temp Rgain */ + +{0xb1, 0x00,}, /* 0x20 -> 0x00 0405 modify */ +{0xb4, 0xbf,}, +{0xb8, 0x09,}, /* lowtemp b0: b-3, r 0 Spec AWB A modify */ +{0xb9, 0x00,}, +/* PAGE 22 END */ + +/* PAGE 48 START */ +{0x03, 0x48,}, + +/* PLL Setting */ +{0x70, 0x05,}, +{0x71, 0x3c,}, /* MiPi Pllx 2.5 */ +{0x72, 0x85,}, +{0x70, 0xa5,}, /* PLL Enable */ +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x03, 0x48,}, +{0x70, 0x95,}, /* CLK_GEN_ENABLE */ + +/* MIPI TX Setting */ +{0x11, 0x00,}, /* 20111013 0x10 continuous -> 0x00 not Continuous */ +{0x10, 0x1c,}, +{0x12, 0x00,}, +{0x14, 0x30,}, /* {0x14, 0x70,}, */ /* 20111013 0x00 -> 0x30 Clock Delay */ +{0x16, 0x04,}, + + +{0x19, 0x00,}, +{0x1a, 0x32,}, +{0x1b, 0x17,}, +{0x1c, 0x0b,}, /* 20121019 */ +{0x1d, 0x0f,}, /* 20121101 0x0e -> 0x0f */ +{0x1e, 0x08,}, /* 20121009 */ +{0x1f, 0x03,}, /* 20121101 0x05 -> 0x004 */ /* 0x04->0x03 20140509 */ +{0x20, 0x00,}, + +{0x23, 0x01,}, +{0x24, 0x1e,}, +{0x25, 0x00,}, +{0x26, 0x00,}, +{0x27, 0x01,}, +{0x28, 0x00,}, +{0x2a, 0x06,}, +{0x2b, 0x40,}, +{0x2c, 0x04,}, +{0x2d, 0xb0,}, + +{0x30, 0x00,}, /* 640x480 MiPi OutPut */ +{0x31, 0x05,}, + +{0x32, 0x0c,}, +{0x33, 0x0a,}, +{0x34, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x35, 0x02,}, /* 20121101 0x03 -> 0x02 */ +{0x36, 0x01,}, +{0x37, 0x07,}, +{0x38, 0x02,}, +{0x39, 0x03,}, /* drivability 24MHZ:02, 48MHz:03 */ +{0x50, 0x00,}, +/* PAGE 48 END */ + +/* PAGE 20 */ +{0x03, 0x20,}, +{0x10, 0x9c,}, /* AE on 50hz */ + +/* PAGE 22 */ +{0x03, 0x22,}, +{0x10, 0xe9,}, + +/* PAGE 0 */ +{0x03, 0x00,}, +{0x11, 0x94,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, +{0x03, 0x00,}, + +{0x03, 0x00,}, +{0x01, 0x30,}, +{0xff, 0x28,}, /* NEED Delay 400ms */ +/* END of sr200pc20m_recording_50Hz_common*/ +}; + + +/******************************************************* +* CAMERA_SCENE +*******************************************************/ +static const u16 sr200pc20m_scene_off[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x05,}, /* EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + + +static const u16 sr200pc20m_scene_landscape[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation +1, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x8a,},/*+10*/ +{0x62, 0x86,},/*+10*/ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness +1*/ +{0x03, 0x13,}, +{0x12, 0x02,}, +{0x25, 0x02,}, +{0x20, 0x1a,}, +{0x21, 0x1a,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/* AE Matrix(Average)*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x55,}, +{0x63, 0x55,}, +{0x64, 0x55,}, +{0x65, 0x55,}, +{0x66, 0x55,}, +{0x67, 0x55,}, +{0x68, 0x55,}, +{0x69, 0x55,}, +{0x6a, 0x55,}, +{0x6b, 0x55,}, +{0x6c, 0x55,}, +{0x6d, 0x55,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x05,}, /*EXP Max 8.33 fps*/ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + + +static const u16 sr200pc20m_scene_party[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation +1, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x8a,}, +{0x62, 0x86,}, +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xe4,}, /* adaptive off*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x05,}, /*EXP Max 8.33 fps*/ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + + /*ISO_200*/ +{0xb0, 0x37,}, +{0xb1, 0x37,}, +{0xb2, 0x40,}, +{0xb3, 0x37,}, +{0xb4, 0x37,}, +{0xb5, 0x40,}, +{0xb6, 0x3e,}, +{0xb7, 0x3c,}, +{0xb8, 0x3a,}, +{0xb9, 0x39,}, +{0xba, 0x38,}, +{0xbb, 0x37,}, +{0xbc, 0x37,}, +{0xbd, 0x37,}, + +{0xc0, 0x10,}, +{0xc1, 0x37,}, +{0xc2, 0x37,}, +{0xc3, 0x37,}, +{0xc4, 0x0b,}, + +{0xff, 0x05,}, +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ + +}; + + +static const u16 sr200pc20m_scene_sunset[] = { + +/* WB Daylight*/ +{0x03, 0x22,}, +{0x11, 0x2c,}, + +{0x80, 0x3b,}, +{0x81, 0x20,}, +{0x82, 0x35,}, /* 3a */ + +{0x83, 0x3c,}, /* */ +{0x84, 0x3a,}, /* */ +{0x85, 0x36,}, /* */ +{0x86, 0x34,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x05,}, /* EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_dawn[] = { +/*WB FLUORESCENT*/ +{0x03, 0x22,}, +{0x11, 0x2c,}, + +{0x80, 0x3c,}, +{0x81, 0x20,}, +{0x82, 0x49,}, /* 3a */ + +{0x83, 0x3e,}, /* */ +{0x84, 0x38,}, /* */ +{0x85, 0x4d,}, /* */ +{0x86, 0x44,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x05,}, /* EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ + +}; + +static const u16 sr200pc20m_scene_fall[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation +2, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x9a,},/*+20*/ +{0x62, 0x96,},/*+20*/ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /* Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x05,}, /*EXP Max 8.33 fps*/ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_nightshot_Normal[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 //*/ +{0x62, 0x76,}, /* 77 //*/ +{0x63, 0xf0,}, +{0x64, 0xf0,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x01,}, +{0xa2, 0x01,}, +{0xa4, 0x01,}, +{0xa6, 0x01,}, + +{0x03, 0x20,}, /*Page 20, Dark condition*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*DARK Conditon1*/ +{0x88, 0x10,}, /*EXP Max 3.03 fps*/ +{0x89, 0x5d,}, +{0x8a, 0x74,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xff,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_nightshot_Dark[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 //*/ +{0x62, 0x76,}, /* 77 //*/ +{0x63, 0xf0,}, +{0x64, 0xf0,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x01,}, +{0xa2, 0x01,}, +{0xa4, 0x01,}, +{0xa6, 0x01,}, + +{0x03, 0x20,}, /*Page 20, Dark condition*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*DARK Conditon2*/ +{0x83, 0x10,}, /*EXP 3.03 fps*/ +{0x84, 0x5d,}, +{0x85, 0x74,}, + +{0x88, 0x10,}, /*EXP Max 3.03 fps*/ +{0x89, 0x5d,}, +{0x8a, 0x74,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xff,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + +static const u16 sr200pc20m_scene_backlight[] = { + +/*WB Auto*/ +{0x03, 0x22,}, +{0x11, 0x2e,}, + +{0x80, 0x38,}, +{0x81, 0x20,}, +{0x82, 0x3a,}, /* 3a */ + +{0x83, 0x56,}, /* */ +{0x84, 0x22,}, /* */ +{0x85, 0x55,}, /* */ +{0x86, 0x20,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x76,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Flash OFF _Spot*/ +{0x60, 0x00,}, +{0x61, 0x00,}, +{0x62, 0x00,}, +{0x63, 0x00,}, +{0x64, 0x00,}, +{0x65, 0x00,}, +{0x66, 0x03,}, +{0x67, 0xc0,}, +{0x68, 0x03,}, +{0x69, 0xc0,}, +{0x6a, 0x00,}, +{0x6b, 0x00,}, +{0x6c, 0x00,}, +{0x6d, 0x00,}, +{0x6e, 0x00,}, +{0x6f, 0x00,}, + +/*Normal condition*/ +{0x88, 0x05,}, /* EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ + +}; + + +static const u16 sr200pc20m_scene_candle[] = { + +/* WB Daylight*/ +{0x03, 0x22,}, +{0x11, 0x2c,}, + +{0x80, 0x3b,}, +{0x81, 0x20,}, +{0x82, 0x35,}, /* 3a */ + +{0x83, 0x3c,}, /* */ +{0x84, 0x3a,}, /* */ +{0x85, 0x36,}, /* */ +{0x86, 0x34,}, /* */ + +/*Saturation 0, EV 0*/ +{0x03, 0x10,}, +{0x41, 0x00,}, +{0x60, 0x61,}, +{0x61, 0x7a,}, /* 77 */ +{0x62, 0x72,}, /* 77 */ +{0x63, 0xa0,}, /* Double_AG 50->30 //*/ +{0x64, 0x80,}, + +/*Sharpness 0*/ +{0x03, 0x13,}, +{0x12, 0x07,}, +{0x25, 0x0a,}, +{0x20, 0x15,}, +{0x21, 0x13,}, + +/*Dark BLC*/ +{0x03, 0x00,}, +{0xa0, 0x00,}, +{0xa2, 0x00,}, +{0xa4, 0x00,}, +{0xa6, 0x00,}, + +{0x03, 0x20,}, /*Page 20*/ +{0x10, 0x1c,}, /* AE Off*/ + +{0x2b, 0xf4,}, /* adaptive on*/ + +/*Metering Center*/ +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, + +/*Normal condition*/ +{0x88, 0x05,}, /* EXP Max 8.33 fps */ +{0x89, 0xf3,}, +{0x8a, 0x70,}, + +/*ISO AUTO*/ +{0xb0, 0x18,}, +{0xb1, 0x14,}, +{0xb2, 0xd0,}, +{0xb3, 0x18,}, +{0xb4, 0x1c,}, +{0xb5, 0x48,}, +{0xb6, 0x32,}, +{0xb7, 0x2b,}, +{0xb8, 0x27,}, +{0xb9, 0x25,}, +{0xba, 0x23,}, +{0xbb, 0x22,}, +{0xbc, 0x46,}, +{0xbd, 0x44,}, + +{0xc0, 0x10,}, +{0xc1, 0x3c,}, +{0xc2, 0x3c,}, +{0xc3, 0x3c,}, +{0xc4, 0x08,}, + +{0x10, 0x9c,}, /* AE On*/ + +{0xff, 0x1e,}, /* 300ms DELAY*/ +}; + + + +/******************************************************* +* CAMERA_METERING +*******************************************************/ +static const u16 sr200pc20m_metering_matrix[] = { +{0x03, 0x20,}, +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x55,}, +{0x63, 0x55,}, +{0x64, 0x55,}, +{0x65, 0x55,}, +{0x66, 0x55,}, +{0x67, 0x55,}, +{0x68, 0x55,}, +{0x69, 0x55,}, +{0x6a, 0x55,}, +{0x6b, 0x55,}, +{0x6c, 0x55,}, +{0x6d, 0x55,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, +}; + +static const u16 sr200pc20m_metering_spot[] = { +{0x03, 0x20,}, +{0x60, 0x00,}, +{0x61, 0x00,}, +{0x62, 0x00,}, +{0x63, 0x00,}, +{0x64, 0x00,}, +{0x65, 0x00,}, +{0x66, 0x03,}, +{0x67, 0xc0,}, +{0x68, 0x03,}, +{0x69, 0xc0,}, +{0x6a, 0x00,}, +{0x6b, 0x00,}, +{0x6c, 0x00,}, +{0x6d, 0x00,}, +{0x6e, 0x00,}, +{0x6f, 0x00,}, +}; + +static const u16 sr200pc20m_metering_center[] = { +{0x03, 0x20,}, +{0x60, 0x55,}, +{0x61, 0x55,}, +{0x62, 0x6A,}, +{0x63, 0xA9,}, +{0x64, 0x6A,}, +{0x65, 0xA9,}, +{0x66, 0x6B,}, +{0x67, 0xE9,}, +{0x68, 0x6B,}, +{0x69, 0xE9,}, +{0x6a, 0x6A,}, +{0x6b, 0xA9,}, +{0x6c, 0x6A,}, +{0x6d, 0xA9,}, +{0x6e, 0x55,}, +{0x6f, 0x55,}, +}; + +#endif + +#endif