Commit fc0e375a authored by sub77's avatar sub77
Browse files

media: camera_v2: update driver [SM-T530_EUR_LL_Opensource_T530XXU1BOD8]

parent f80a51f5
......@@ -99,6 +99,22 @@ config S5K4E5YA
2 mipi lanes, preview config = 1280 * 980 at 30 fps,
snapshot config = 2608 * 1960 at 30 fps.
config S5K4H5YB
bool "Sensor S5K4H5YB (BAYER 8M)"
depends on MSMB_CAMERA
---help---
Samsung 8 MP Bayer Sensor with auto focus, uses
4 mipi lanes, preview config = 1984 * 1508 at 30 fps,
snapshot config = 4000 * 3000 at 20 fps,
hfr video at 60, 90 and 120 fps.
config S5K6A3YX
bool "Sensor S5K6A3YX (BAYER 2M)"
depends on MSMB_CAMERA
---help---
Samsung 2 MP Bayer Sensor,
Front Sensor.
config IMX134
bool "Sensor IMX134 (BAYER 8M)"
depends on MSMB_CAMERA
......
/* 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 <linux/of.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/ioctl.h>
#include <linux/spinlock.h>
#include <linux/proc_fs.h>
#include <linux/atomic.h>
#include <linux/wait.h>
#include <linux/videodev2.h>
#include <linux/msm_ion.h>
#include <linux/iommu.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <media/v4l2-fh.h>
#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; */
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;
}
static long msm_ioctl_cam_dummy(struct file *fp, unsigned int cmd,
unsigned long arg)
{
return 0;
}
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,
.unlocked_ioctl = msm_ioctl_cam_dummy,
};
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,
},
};
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;
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);
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");
/* 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 <linux/of.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/ioctl.h>
#include <linux/spinlock.h>
#include <linux/proc_fs.h>
#include <linux/atomic.h>
#include <linux/wait.h>
#include <linux/videodev2.h>
#include <linux/msm_ion.h>
#include <linux/iommu.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <media/v4l2-fh.h>
#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; */
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;
}
static long msm_ioctl_cam_dummy(struct file *fp, unsigned int cmd,
unsigned long arg)
{
return 0;
}
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,
.unlocked_ioctl = msm_ioctl_cam_dummy,
};
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,
},
};
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;
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);
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");
......@@ -65,10 +65,12 @@ static int camera_check_event_status(struct v4l2_event *event)
(struct msm_v4l2_event_data *)&event->u.data[0];
if (event_data->status > MSM_CAMERA_ERR_EVT_BASE) {
pr_err("%s : event_data->status failed!", __func__);
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;
}
......@@ -603,6 +605,8 @@ static int camera_v4l2_open(struct file *filep)
pr_err("%s : camera_check_event_status", __func__);
goto post_fail;
}
/* Disable power colapse latency */
msm_pm_qos_update_request(CAMERA_DISABLE_PC_LATENCY);
} else {
rc = msm_create_command_ack_q(pvdev->vdev->num,
atomic_read(&pvdev->opened));
......@@ -655,6 +659,8 @@ static int camera_v4l2_close(struct file *filep)
if (atomic_read(&pvdev->opened) == 0) {
/* Enable power colapse latency */
msm_pm_qos_update_request(CAMERA_ENABLE_PC_LATENCY);
camera_pack_event(filep, MSM_CAMERA_SET_PARM,
MSM_CAMERA_PRIV_DEL_STREAM, -1, &event);
......
......@@ -338,11 +338,14 @@ static int msm_isp_get_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id,
if (bufq->buf_type == ISP_SHARE_BUF) {
temp_buf_info = kzalloc(
sizeof(struct msm_isp_buffer), GFP_ATOMIC);
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);
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;
......@@ -569,6 +572,10 @@ static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr,
buf_info->tv, buf_info->frame_id, 0);
} else {
bufq = msm_isp_get_bufq(buf_mgr, info->handle);
if(!bufq) {
pr_err("Fail to allocate memory\n");
return rc;
}
if (BUF_SRC(bufq->stream_id)) {
rc = msm_isp_put_buf(buf_mgr,
info->handle, info->buf_idx);
......@@ -601,7 +608,7 @@ static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr,
struct msm_isp_bufq *bufq = NULL;
CDBG("%s: E\n", __func__);
if (!buf_request->num_buf || buf_request->num_buf > VIDEO_MAX_FRAME) {
if (!buf_request->num_buf) {
pr_err("Invalid buffer request\n");
return rc;
}
......
......@@ -78,8 +78,12 @@ static int __devinit vfe_probe(struct platform_device *pdev)
of_property_read_u32((&pdev->dev)->of_node,
"cell-index", &pdev->id);
match_dev = of_match_device(msm_vfe_dt_match, &pdev->dev);
vfe_dev->hw_info =
(struct msm_vfe_hardware_info *) match_dev->data;
if (match_dev != NULL) {
vfe_dev->hw_info =
(struct msm_vfe_hardware_info *) match_dev->data;
} else {
pr_err("%s: failed to match device\n", __func__);
}
} else {
vfe_dev->hw_info = (struct msm_vfe_hardware_info *)
platform_get_device_id(pdev)->driver_data;
......
......@@ -449,6 +449,8 @@ struct vfe_device {
struct msm_isp_buf_mgr *buf_mgr;
int dump_reg;
uint32_t vfe_open_cnt;
uint32_t frame_id;
uint32_t eof_event_occur;
};
#endif
......@@ -90,7 +90,9 @@ vfe_remap_failed:
msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
clk_enable_failed:
regulator_disable(vfe_dev->fs_vfe);
if (vfe_dev->fs_vfe) {
regulator_disable(vfe_dev->fs_vfe);
}
fs_failed:
msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
bus_scale_register_failed:
......
......@@ -264,7 +264,9 @@ vfe_remap_failed:
msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe40_clk_info), 0);
clk_enable_failed:
regulator_disable(vfe_dev->fs_vfe);
if (vfe_dev->fs_vfe) {
regulator_disable(vfe_dev->fs_vfe);
}
fs_failed:
msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
bus_scale_register_failed:
......@@ -330,8 +332,10 @@ static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev,
msm_isp_update_framedrop_reg(vfe_dev);
}
}
if (irq_status0 & (1 << 1))
if (irq_status0 & (1 << 1)) {
vfe_dev->eof_event_occur = 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))
......
......@@ -408,6 +408,8 @@ void msm_isp_sof_notify(struct vfe_device *vfe_dev,
}
sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
vfe_dev->frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
vfe_dev->eof_event_occur = 0;
sof_event.timestamp = ts->event_time;
msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
}
......@@ -918,8 +920,8 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev)
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;
axi_data->src_info[VFE_PIX_0].pixel_clock *
ISP_DEFAULT_FORMAT_FACTOR / ISP_Q2;
total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth;
rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id,
......@@ -939,7 +941,13 @@ static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev,
spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
init_completion(&vfe_dev->stream_config_complete);
vfe_dev->axi_data.pipeline_update = camif_update;
#if defined(CONFIG_MACH_AFYONLTE_TMO) \
|| defined(CONFIG_MACH_AFYONLTE_MTR) \
|| defined(CONFIG_SEC_RUBENS_PROJECT)
vfe_dev->axi_data.stream_update = 1;
#else
vfe_dev->axi_data.stream_update = 2;
#endif
spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stream_config_complete,
......@@ -1009,6 +1017,31 @@ static void msm_isp_get_stream_wm_mask(
*wm_reload_mask |= (1 << stream_info->wm[i]);
}
#if defined(CONFIG_MACH_AFYONLTE_TMO) \
|| defined(CONFIG_MACH_AFYONLTE_MTR) \
|| defined(CONFIG_SEC_RUBENS_PROJECT)
static void msm_isp_axi_stream_update_new(struct vfe_device *vfe_dev, enum msm_isp_camif_update_state camif_update)
{
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 (camif_update == DISABLE_CAMIF) {
vfe_dev->hw_info->vfe_ops.stats_ops.enable_module(vfe_dev, 0xFF, 0);
vfe_dev->axi_data.pipeline_update = NO_UPDATE;
}
}
#endif
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)
......@@ -1057,8 +1090,17 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, camif_update);
}
#if defined(CONFIG_MACH_AFYONLTE_TMO) \
|| defined(CONFIG_MACH_AFYONLTE_MTR) \
|| defined(CONFIG_SEC_RUBENS_PROJECT)
if (wait_for_complete){
msm_isp_axi_stream_update_new(vfe_dev, camif_update);
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
}
#else
if (wait_for_complete)
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
#endif
return rc;
}
......@@ -1075,8 +1117,15 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
stream_info->state = STOP_PENDING;
}
#if defined(CONFIG_MACH_AFYONLTE_TMO) \
|| defined (CONFIG_MACH_AFYONLTE_MTR) \
|| defined(CONFIG_SEC_RUBENS_PROJECT)
pr_err("[richard] %s : state [%d], camif_update [%d]\n", __func__, stream_info->state, camif_update);
msm_isp_axi_stream_update_new(vfe_dev, DISABLE_CAMIF);
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, NO_UPDATE);
#else
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
#endif
if (rc < 0) {
pr_err("%s: wait for config done failed\n", __func__);
pr_err("%s:<DEBUG00>timeout:no frame from sensor\n", __func__);
......
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* 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
......@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <media/v4l2-subdev.h>
#include <linux/ratelimit.h>
#include <asm/div64.h>
#include "msm.h"
#include "msm_isp_util.h"
......@@ -345,6 +346,10 @@ long msm_isp_ioctl(struct v4l2_subdev *sd,
* longer time to complete such as start/stop ISP streams
* which blocks until the hardware start/stop streaming
*/
if (vfe_dev->vfe_open_cnt == 0) {
pr_err("%s: No open VFE nodes!\n", __func__);
return rc;
}
ISP_DBG("%s cmd: %d\n", __func__, _IOC_TYPE(cmd));
switch (cmd) {
case VIDIOC_MSM_VFE_REG_CFG: {
......@@ -423,14 +428,107 @@ 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: {
if (resource_size(vfe_dev->vfe_mem) <
(reg_cfg_cmd->u.rw_info.reg_offset +
reg_cfg_cmd->u.rw_info.len)) {
pr_err("%s: Invalid length\n", __func__);
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,
......@@ -438,14 +536,22 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
break;
}
case VFE_WRITE_MB: {
uint32_t *data_ptr = cfg_data +
reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base +
reg_cfg_cmd->u.rw_info.reg_offset);
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;
......@@ -461,20 +567,10 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
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) {
if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
reg_cfg_cmd->u.dmi_info.len > cmd_len) {
pr_err("Invalid Hi Table out of bounds\n");
return -EINVAL;
}
hi_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4;
}
if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset +
reg_cfg_cmd->u.dmi_info.len > cmd_len) {
pr_err("Invalid Lo Table out of bounds\n");
return -EINVAL;
}
lo_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
......@@ -509,30 +605,18 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
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) {
if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
reg_cfg_cmd->u.dmi_info.len > cmd_len) {
pr_err("Invalid Hi Table out of bounds\n");
return -EINVAL;
}
hi_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4;
}
if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset +
reg_cfg_cmd->u.dmi_info.len > cmd_len) {
pr_err("Invalid Lo Table out of bounds\n");
return -EINVAL;
}
lo_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
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;
}
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);
......@@ -542,6 +626,13 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
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;
}
......@@ -550,12 +641,22 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
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_SOC_HW_VER:
break;
case GET_MAX_CLK_RATE:
break;
}
return 0;
}
......@@ -596,10 +697,17 @@ int msm_isp_proc_cmd(struct vfe_device *vfe_dev, void *arg)
goto copy_cmd_failed;
}
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, &reg_cfg_cmd[i],
cfg_data, proc_cmd->cmd_len);
}
else{
rc = MSM_VFE_REG_CFG_FRAME_ID_NOT_MATCH_ERROR;
pr_err("%s: not match 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;
......
......@@ -40,7 +40,12 @@
#define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY 0x02
#define ISPIF_TIMEOUT_SLEEP_US 1000
#if defined(CONFIG_MACH_VICTORLTE_CTC) || defined(CONFIG_MACH_AFYONLTE_TMO) \
|| defined (CONFIG_MACH_AFYONLTE_MTR) || defined (CONFIG_MACH_AFYONLTE_CAN)
#define ISPIF_TIMEOUT_ALL_US 1000000
#else
#define ISPIF_TIMEOUT_ALL_US 500000
#endif
#define CSID_VERSION_V30 0x30000000
......@@ -95,8 +100,8 @@ static void msm_ispif_io_dump_start_reg(struct ispif_device *ispif)
static inline int msm_ispif_is_intf_valid(uint32_t csid_version,
uint8_t intf_type)
{
return (csid_version <= CSID_VERSION_V2 && intf_type != VFE0) ?
false : true;
return ((csid_version <= CSID_VERSION_V2 && intf_type != VFE0) ||
(intf_type >= VFE_MAX)) ? false : true;
}
static struct msm_cam_clk_info ispif_8974_ahb_clk_info[] = {
......
......@@ -676,7 +676,7 @@ int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
void * __user arg)
{
int is_copy_to_user;
int len;
uint32_t len;
uint32_t m;
struct msm_jpeg_hw_cmds *hw_cmds_p;
struct msm_jpeg_hw_cmd *hw_cmd_p;
......@@ -694,7 +694,7 @@ int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
return -EFAULT;
}
if (copy_from_user(hw_cmds_p, arg, len)) {
if ((len < 0) || copy_from_user(hw_cmds_p, arg, len)) {
JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
kfree(hw_cmds_p);
return -EFAULT;
......
......@@ -29,9 +29,11 @@
#include "msm.h"
#include "msm_vb2.h"
#include "msm_sd.h"
#include <media/msmb_generic_buf_mgr.h>
static struct v4l2_device *msm_v4l2_dev;
static struct list_head ordered_sd_list;
static struct pm_qos_request msm_v4l2_pm_qos_request;
static struct msm_queue_head *msm_session_q;
......@@ -192,6 +194,19 @@ static inline int __msm_queue_find_command_ack_q(void *d1, void *d2)
return (ack->stream_id == *(unsigned int *)d2) ? 1 : 0;
}
static void msm_pm_qos_add_request(void)
{
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)
{
pm_qos_remove_request(&msm_v4l2_pm_qos_request);
}
void msm_pm_qos_update_request(int val)
{
pm_qos_update_request(&msm_v4l2_pm_qos_request, val);
}
struct msm_session *msm_session_find(unsigned int session_id)
{
......@@ -528,6 +543,7 @@ static void msm_remove_session_cmd_ack_q(struct msm_session *session)
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);
......@@ -541,6 +557,12 @@ int msm_destroy_session(unsigned int session_id)
mutex_destroy(&session->lock);
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__);
pr_warn("%s : Succeed", __func__);
......@@ -705,7 +727,11 @@ int msm_post_event(struct v4l2_event *event, int timeout)
struct msm_command *cmd;
int session_id, stream_id;
unsigned long flags = 0;
int wait_count = 2000;
#if defined(CONFIG_MACH_MATISSE3G_OPEN)
unsigned long timeout_jiffies = jiffies + msecs_to_jiffies(timeout);
#else
int wait_count = 2000;
#endif
session_id = event_data->session_id;
stream_id = event_data->stream_id;
......@@ -744,6 +770,36 @@ int msm_post_event(struct v4l2_event *event, int timeout)
pr_err("%s:%d failed\n", __func__, __LINE__);
return rc;
}
#if defined(CONFIG_MACH_MATISSE3G_OPEN)
do {
/* should wait on session based condition for temp. */
rc = wait_event_interruptible_timeout(cmd_ack->wait, !list_empty_careful(&cmd_ack->command_q.list), msecs_to_jiffies(timeout));
if (rc != -ERESTARTSYS)
break;
if (time_after_eq(jiffies, timeout_jiffies)) {
rc = -ERESTARTSYS;
break;
}
else
timeout = jiffies_to_msecs(timeout_jiffies-jiffies);
} while(1);
if (list_empty_careful(&cmd_ack->command_q.list)) {
pr_err("%s:%d failed (rc = %d)\n", __func__, __LINE__, rc);
if (!rc) {
pr_err("%s: Timed out\n", __func__);
msm_print_event_error(event);
rc = -ERESTARTSYS;
}
if (rc < 0) {
msm_print_event_error(event);
pr_err("%s:%d failed\n", __func__, __LINE__);
mutex_unlock(&session->lock);
return rc;
}
}
#else
do {
rc = wait_event_interruptible_timeout(cmd_ack->wait,
!list_empty_careful(&cmd_ack->command_q.list),
......@@ -769,6 +825,7 @@ int msm_post_event(struct v4l2_event *event, int timeout)
return rc;
}
}
#endif
cmd = msm_dequeue(&cmd_ack->command_q,
struct msm_command, list);
if (!cmd) {
......@@ -806,6 +863,8 @@ static int msm_close(struct file *filep)
list_for_each_entry(msm_sd, &ordered_sd_list, list)
__msm_sd_close_subdevs(msm_sd, &sd_close);
pr_err("%s __dbg: \n", __func__); //QC_Patch
/* remove msm_v4l2_pm_qos_request */
msm_pm_qos_remove_request();
/* send v4l2_event to HAL next*/
msm_queue_traverse_action(msm_session_q, struct msm_session, list,
__msm_close_destry_session_notify_apps, NULL);
......@@ -866,6 +925,8 @@ static int msm_open(struct file *filep)
spin_unlock_irqrestore(&msm_eventq_lock, flags);
pr_warn("%s : Succeed!", __func__);
/* register msm_v4l2_pm_qos_request */
msm_pm_qos_add_request();
return rc;
}
......
......@@ -33,6 +33,8 @@
#define MSM_POST_EVT_TIMEOUT 10000
#define MSM_POST_STREAMOFF_EVT_TIMEOUT 9000
#define MSM_POST_EVT_NOTIMEOUT 0xFFFFFFFF
#define CAMERA_DISABLE_PC_LATENCY 100
#define CAMERA_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE
struct msm_video_device {
struct video_device *vdev;
......@@ -101,7 +103,7 @@ struct msm_session {
struct msm_queue_head stream_q;
struct mutex lock;
};
void msm_pm_qos_update_request(int val);
int msm_cam_get_module_init_status(void);
int msm_module_init_status(void);
int msm_post_event(struct v4l2_event *event, int timeout);
......
......@@ -108,14 +108,42 @@ static void msm_buf_mngr_sd_shutdown(struct msm_buf_mngr_device *buf_mngr_dev)
if (!list_empty(&buf_mngr_dev->buf_qhead)) {
list_for_each_entry_safe(bufs,
save, &buf_mngr_dev->buf_qhead, entry) {
pr_err("%s: Delete invalid bufs =%x\n", __func__,
(unsigned int)bufs);
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)
{
......@@ -139,6 +167,12 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
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;
......@@ -152,6 +186,12 @@ 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,
};
......@@ -181,6 +221,8 @@ static int __init msm_buf_mngr_init(void)
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) {
......
......@@ -18,6 +18,19 @@
/* NOTE: this header file should ONLY be included by subdev drivers */
#ifndef EEPROM_CAM_FW
#if defined(CONFIG_MACH_ATLANTIC3GEUR_OPEN) ||\
defined(CONFIG_MACH_ATLANTICLTE_ATT) ||\
defined(CONFIG_SEC_HESTIA_PROJECT) ||\
defined(CONFIG_MACH_MEGA2LTE_KTT) ||\
defined(CONFIG_MACH_VASTALTE_CHN_CMCC_DUOS)
#define EEPROM_CAM_FW
#define EEPROM_FW_OFFSET 48
#define EEPROM_FW_SIZE 11
#endif
#endif
struct msm_sd_close_ioctl {
unsigned int session;
unsigned int stream;
......
......@@ -60,14 +60,15 @@ typedef struct _msm_cpp_timer_data_t {
} msm_cpp_timer_data_t;
typedef struct _msm_cpp_timer_t {
uint8_t used;
atomic_t used;
msm_cpp_timer_data_t data;
struct timer_list cpp_timer;
} msm_cpp_timer_t;
msm_cpp_timer_t cpp_timers[2];
static int del_timer_idx=0;
static int set_timer_idx=0;
msm_cpp_timer_t cpp_timers;
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)
......@@ -625,21 +626,19 @@ void msm_cpp_do_tasklet(unsigned long data)
if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
CPP_DBG("Frame done!!\n");
/* delete CPP timer */
CPP_DBG("deleting cpp_timer %d.\n", del_timer_idx);
del_timer(&cpp_timers[del_timer_idx].cpp_timer);
cpp_timers[del_timer_idx].used = 0;
cpp_timers[del_timer_idx].data.processed_frame = NULL;
del_timer_idx = 1 - del_timer_idx;
CPP_DBG("deleting cpp_timer.\n");
atomic_set(&cpp_timers.used,0);
del_timer(&cpp_timers.cpp_timer);
cpp_timers.data.processed_frame = NULL;
cpp_dev->timeout_trial_cnt = 0;
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("deleting cpp_timer %d.\n", del_timer_idx);
del_timer(&cpp_timers[del_timer_idx].cpp_timer);
cpp_timers[del_timer_idx].used = 0;
cpp_timers[del_timer_idx].data.processed_frame = NULL;
del_timer_idx = 1 - del_timer_idx;
CPP_DBG("deleting cpp_timer.\n");
atomic_set(&cpp_timers.used,0);
del_timer(&cpp_timers.cpp_timer);
cpp_timers.data.processed_frame = NULL;
cpp_dev->timeout_trial_cnt = 0;
msm_cpp_notify_frame_done(cpp_dev);
}
......@@ -751,6 +750,13 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
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 =
......@@ -808,7 +814,12 @@ bus_scale_register_failed:
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 rc=%d\n", rc);
free_irq(cpp_dev->irq->start, cpp_dev);
tasklet_kill(&cpp_dev->cpp_tasklet);
atomic_set(&cpp_dev->irq_cnt, 0);
......@@ -819,11 +830,11 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev)
iounmap(cpp_dev->cpp_hw_base);
msm_cam_clk_enable(&cpp_dev->pdev->dev, cpp_clk_info,
cpp_dev->cpp_clk, ARRAY_SIZE(cpp_clk_info), 0);
if (0) {
regulator_disable(cpp_dev->fs_cpp);
regulator_put(cpp_dev->fs_cpp);
cpp_dev->fs_cpp = NULL;
}
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");
cpp_dev->stream_cnt = 0;
......@@ -1117,39 +1128,33 @@ 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 =
cpp_timers[del_timer_idx].data.processed_frame;
struct msm_cpp_frame_info_t *second_frame = NULL;
struct msm_cpp_frame_info_t *this_frame = NULL;
struct msm_queue_cmd *frame_qcmd = NULL;
struct msm_cpp_frame_info_t *processed_frame = NULL;
struct msm_device_queue *queue = NULL;
mutex_lock(&cpp_timers[0].data.cpp_dev->mutex);
mutex_lock(&cpp_timers.data.cpp_dev->mutex);
pr_err("cpp_timer_callback called idx:%d. (jiffies=%lu)\n",
del_timer_idx, jiffies);
cpp_timers[del_timer_idx].used = 0;
cpp_timers[del_timer_idx].data.processed_frame = NULL;
del_timer_idx = 1 - del_timer_idx;
pr_err("cpp_timer_callback called idx. (jiffies=%lu)\n",
jiffies);
if (!work || !this_frame) {
pr_err("Invalid work:%p, this_frame:%p, del_idx:%d\n",
work, this_frame, del_timer_idx);
mutex_unlock(&cpp_timers[0].data.cpp_dev->mutex);
if (!work) {
pr_err("Invalid work:%p\n",work);
mutex_unlock(&cpp_timers.data.cpp_dev->mutex);
return;
}
/* If cpp_dev state is off we can safely clear the pending frame or
If the trial count exceed max attempts then clean the pending frame */
if ((cpp_timers[0].data.cpp_dev->state != CPP_STATE_ACTIVE) ||
(cpp_timers[0].data.cpp_dev->timeout_trial_cnt >
if ((cpp_timers.data.cpp_dev->state != CPP_STATE_ACTIVE) ||
(cpp_timers.data.cpp_dev->timeout_trial_cnt >
MSM_CPP_MAX_TIMEOUT_TRIAL)) {
pr_err("State:%d\n, timeout_trial_cnt:%d\n",
cpp_timers[0].data.cpp_dev->state,
cpp_timers[0].data.cpp_dev->timeout_trial_cnt);
cpp_timers.data.cpp_dev->state,
cpp_timers.data.cpp_dev->timeout_trial_cnt);
queue = &cpp_timers[0].data.cpp_dev->processing_q;
queue = &cpp_timers.data.cpp_dev->processing_q;
frame_qcmd = msm_dequeue(queue, list_frame);
if (frame_qcmd) {
processed_frame = frame_qcmd->command;
......@@ -1158,82 +1163,56 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
kfree(processed_frame->cpp_cmd_msg);
kfree(processed_frame);
}
mutex_unlock(&cpp_timers[0].data.cpp_dev->mutex);
mutex_unlock(&cpp_timers.data.cpp_dev->mutex);
return;
}
pr_err("fatal: cpp_timer expired for identity=0x%x, frame_id=%03d",
this_frame->identity, this_frame->frame_id);
if (cpp_timers[del_timer_idx].used == 1) {
pr_err("deleting cpp_timer %d.\n", del_timer_idx);
del_timer(&cpp_timers[del_timer_idx].cpp_timer);
cpp_timers[del_timer_idx].used = 0;
second_frame = cpp_timers[del_timer_idx].data.processed_frame;
cpp_timers[del_timer_idx].data.processed_frame = NULL;
del_timer_idx = 1 - del_timer_idx;
if (!atomic_read(&cpp_timers.used)) {
pr_err("Delayed trigger, IRQ serviced\n");
return;
}
disable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
disable_irq(cpp_timers.data.cpp_dev->irq->start);
pr_err("Reloading firmware\n");
cpp_load_fw(cpp_timers[del_timer_idx].data.cpp_dev, NULL);
cpp_load_fw(cpp_timers.data.cpp_dev, NULL);
pr_err("Firmware loading done\n");
enable_irq(cpp_timers[del_timer_idx].data.cpp_dev->irq->start);
msm_camera_io_w_mb(0x8,cpp_timers[del_timer_idx].data.cpp_dev->base +
enable_irq(cpp_timers.data.cpp_dev->irq->start);
msm_camera_io_w_mb(0x8,cpp_timers.data.cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_MASK);
msm_camera_io_w_mb(0xFFFF, cpp_timers[del_timer_idx].data.cpp_dev->base +
msm_camera_io_w_mb(0xFFFF, cpp_timers.data.cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_CLR);
cpp_timers[set_timer_idx].data.processed_frame = this_frame;
cpp_timers[set_timer_idx].used = 1;
pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
setup_timer(&cpp_timers[set_timer_idx].cpp_timer, cpp_timer_callback,
(unsigned long)&cpp_timers[0]);
if (!atomic_read(&cpp_timers.used)) {
pr_err("Delayed trigger, IRQ serviced\n");
return;
}
this_frame = cpp_timers.data.processed_frame;
pr_err("ReInstalling cpp_timer\n");
setup_timer(&cpp_timers.cpp_timer, cpp_timer_callback,
(unsigned long)&cpp_timers);
pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
ret = mod_timer(&cpp_timers.cpp_timer,
jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
if (ret)
pr_err("error in mod_timer\n");
set_timer_idx = 1 - set_timer_idx;
pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n",
this_frame->identity, this_frame->frame_id);
msm_cpp_write(0x6, cpp_timers[set_timer_idx].data.cpp_dev->base);
msm_cpp_write(0x6, cpp_timers.data.cpp_dev->base);
for (i = 0; i < this_frame->msg_len; i++)
msm_cpp_write(this_frame->cpp_cmd_msg[i],
cpp_timers[set_timer_idx].data.cpp_dev->base);
cpp_timers.data.cpp_dev->base);
if (second_frame != NULL) {
cpp_timers[set_timer_idx].data.processed_frame = second_frame;
cpp_timers[set_timer_idx].used = 1;
pr_err("ReInstalling cpp_timer %d\n", set_timer_idx);
setup_timer(&cpp_timers[set_timer_idx].cpp_timer, cpp_timer_callback,
(unsigned long)&cpp_timers[0]);
pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
if (ret)
pr_err("error in mod_timer\n");
set_timer_idx = 1 - set_timer_idx;
pr_err("Rescheduling for identity=0x%x, frame_id=%03d",
second_frame->identity, second_frame->frame_id);
msm_cpp_write(0x6, cpp_timers[set_timer_idx].data.cpp_dev->base);
for (i = 0; i < second_frame->msg_len; i++)
msm_cpp_write(second_frame->cpp_cmd_msg[i],
cpp_timers[set_timer_idx].data.cpp_dev->base);
}
cpp_timers[1 - set_timer_idx].data.cpp_dev->timeout_trial_cnt++;
mutex_unlock(&cpp_timers[0].data.cpp_dev->mutex);
cpp_timers.data.cpp_dev->timeout_trial_cnt++;
mutex_unlock(&cpp_timers.data.cpp_dev->mutex);
return;
}
void cpp_timer_callback(unsigned long data)
{
queue_work(cpp_timers[set_timer_idx].data.cpp_dev->timer_wq,
(struct work_struct *)cpp_timers[set_timer_idx].data.cpp_dev->work);
queue_work(cpp_timers.data.cpp_dev->timer_wq,
(struct work_struct *)cpp_timers.data.cpp_dev->work);
}
static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
......@@ -1249,21 +1228,19 @@ static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
msm_enqueue(&cpp_dev->processing_q,
&frame_qcmd->list_frame);
cpp_timers[set_timer_idx].data.processed_frame = process_frame;
cpp_timers[set_timer_idx].used = 1;
cpp_timers.data.processed_frame = process_frame;
atomic_set(&cpp_timers.used,1);
/* install timer for cpp timeout */
CPP_DBG("Installing cpp_timer %d\n", set_timer_idx);
setup_timer(&cpp_timers[set_timer_idx].cpp_timer, cpp_timer_callback,
(unsigned long)&cpp_timers[0]);
CPP_DBG("Installing cpp_timer\n");
setup_timer(&cpp_timers.cpp_timer, cpp_timer_callback,
(unsigned long)&cpp_timers);
CPP_DBG( "Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
ret = mod_timer(&cpp_timers[set_timer_idx].cpp_timer,
ret = mod_timer(&cpp_timers.cpp_timer,
jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
if (ret)
pr_err("error in mod_timer\n");
set_timer_idx = 1 - set_timer_idx;
msm_cpp_write(0x6, cpp_dev->base);
for (i = 0; i < process_frame->msg_len; i++) {
if ((induce_error) && (i == 1)) {
......@@ -1655,15 +1632,15 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
}
cpp_dev->state = CPP_STATE_ACTIVE;
cpp_dev->timeout_trial_cnt = 0;
if (cpp_timers[0].used == 1) {
del_timer(&cpp_timers[0].cpp_timer);
cpp_timers[0].used = 0;
cpp_timers[0].data.processed_frame = NULL;
if (atomic_read(&cpp_timers.used)) {
del_timer(&cpp_timers.cpp_timer);
atomic_set(&cpp_timers.used,0);
cpp_timers.data.processed_frame = NULL;
}
if (cpp_timers[1].used == 1) {
del_timer(&cpp_timers[1].cpp_timer);
cpp_timers[1].used = 0;
cpp_timers[1].data.processed_frame = NULL;
if (atomic_read(&cpp_timers.used)) {
del_timer(&cpp_timers.cpp_timer);
atomic_set(&cpp_timers.used,0);
cpp_timers.data.processed_frame = NULL;
}
if (cpp_dev->processing_q.len) {
queue = &cpp_dev->processing_q;
......@@ -1676,8 +1653,6 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
kfree(processed_frame);
}
}
del_timer_idx = 0;
set_timer_idx = 0;
}
cpp_dev->stream_cnt++;
pr_err("stream_cnt:%d\n", cpp_dev->stream_cnt);
......@@ -1730,15 +1705,15 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
pr_err("Bandwidth Reset Failed!\n");
cpp_dev->state = CPP_STATE_IDLE;
cpp_dev->timeout_trial_cnt = 0;
if (cpp_timers[0].used == 1) {
del_timer(&cpp_timers[0].cpp_timer);
cpp_timers[0].used = 0;
cpp_timers[0].data.processed_frame = NULL;
if (atomic_read(&cpp_timers.used)) {
del_timer(&cpp_timers.cpp_timer);
atomic_set(&cpp_timers.used,0);
cpp_timers.data.processed_frame = NULL;
}
if (cpp_timers[1].used == 1) {
del_timer(&cpp_timers[1].cpp_timer);
cpp_timers[1].used = 0;
cpp_timers[1].data.processed_frame = NULL;
if (atomic_read(&cpp_timers.used)) {
del_timer(&cpp_timers.cpp_timer);
atomic_set(&cpp_timers.used,0);
cpp_timers.data.processed_frame = NULL;
}
if (cpp_dev->processing_q.len) {
......@@ -1752,8 +1727,6 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
kfree(processed_frame);
}
}
del_timer_idx = 0;
set_timer_idx = 0;
}
} else {
pr_err("error: stream count underflow %d\n", cpp_dev->stream_cnt);
......@@ -2076,16 +2049,20 @@ static int __devinit cpp_probe(struct platform_device *pdev)
cpp_dev->work =
(struct msm_cpp_work_t *)kmalloc(sizeof(struct msm_cpp_work_t),
GFP_KERNEL);
if(!cpp_dev->work) {
pr_err("no enough memory\n");
rc = -ENOMEM;
goto ERROR4;
}
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_timers[0].data.cpp_dev = cpp_dev;
cpp_timers[1].data.cpp_dev = cpp_dev;
cpp_timers[0].used = 0;
cpp_timers[1].used = 0;
cpp_timers.data.cpp_dev = cpp_dev;
atomic_set(&cpp_timers.used,0);
cpp_dev->fw_name_bin = NULL;
return rc;
ERROR4:
destroy_workqueue(cpp_dev->timer_wq);
ERROR3:
release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
ERROR2:
......
......@@ -8,5 +8,6 @@ obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sen
obj-$(CONFIG_S5K4ECGX) += s5k4ecgx_yuv.o
obj-$(CONFIG_SR030PC50) += sr030pc50_yuv.o
obj-$(CONFIG_SR352) += sr352_yuv.o
obj-$(CONFIG_SR200PC20) += sr200pc20_yuv.o
obj-$(CONFIG_SR130PC20) += sr130pc20_yuv.o
obj-$(CONFIG_MSMB_CAMERA) += flash/
/* 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 HYBRID_VCA_H
#define HYBRID_VCA_H
#include <linux/types.h>
#include <linux/i2c.h>
#include "msm_actuator.h"
/*#define HVCA_DEBUG*/
#ifdef HVCA_DEBUG
#undef LOG_TAG
#define LOG_TAG "HVCA"
#define CDBG_HVCA(fmt, args...) printk("hvca_actuator: %s:%d : "fmt, __FUNCTION__, __LINE__, ##args)
#else
#define CDBG_HVCA(fmt, args...)
#endif
int32_t hvca_actuator_init_focus(
struct msm_actuator_ctrl_t *a_ctrl,
uint16_t size, enum msm_actuator_data_type type,
struct reg_settings_t *settings);
int32_t hvca_actuator_init_step_table(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_set_info_t *set_info);
int32_t hvca_actuator_set_default_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params);
void hvca_actuator_set_inf_focus(int);
int32_t hvca_actuator_move_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params);
#endif
/* 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 HYBRID_VCA_H
#define HYBRID_VCA_H
#include <linux/types.h>
#include <linux/i2c.h>
#include "msm_actuator.h"
/*#define HVCA_DEBUG*/
#ifdef HVCA_DEBUG
#undef LOG_TAG
#define LOG_TAG "HVCA"
#define CDBG_HVCA(fmt, args...) printk("hvca_actuator: %s:%d : "fmt, __FUNCTION__, __LINE__, ##args)
#else
#define CDBG_HVCA(fmt, args...)
#endif
int32_t hvca_actuator_init_focus(
struct msm_actuator_ctrl_t *a_ctrl,
uint16_t size, enum msm_actuator_data_type type,
struct reg_settings_t *settings);
int32_t hvca_actuator_init_step_table(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_set_info_t *set_info);
int32_t hvca_actuator_set_default_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params);
void hvca_actuator_set_inf_focus(int);
int32_t hvca_actuator_move_focus(
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params);
#endif
......@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/vmalloc.h>
#include "msm_sd.h"
#include "msm_actuator.h"
#include "msm_cci.h"
......@@ -33,6 +34,7 @@ static struct msm_actuator msm_piezo_actuator_table;
static struct msm_actuator msm_hall_effect_actuator_table;
static struct msm_actuator msm_hvcm_actuator_table;
static struct msm_actuator msm_dw9804_actuator_table;
static uint16_t hvca_inf_position, hvca_mac_position, torg;
static struct msm_actuator *actuators[] = {
......@@ -84,8 +86,25 @@ static void msm_actuator_parse_i2c_params(struct msm_actuator_ctrl_t *a_ctrl,
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;
struct msm_camera_i2c_seq_reg_array *i2c_seq = a_ctrl->i2c_reg_seq_tbl;
CDBG("Enter\n");
for (i = 0; i < size; i++) {
if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC_SEQ) {
value = (next_lens_position <<
write_arr[i].data_shift) |
((hw_dword & write_arr[i].hw_mask) >>
write_arr[i].hw_shift);
i2c_seq[a_ctrl->i2c_tbl_index].reg_addr = write_arr[i].reg_addr;
i2c_seq[a_ctrl->i2c_tbl_index].reg_data[0] = (value & 0xFF00) >> 8;
i2c_seq[a_ctrl->i2c_tbl_index].reg_data[1] = value & 0xFF;
i2c_seq[a_ctrl->i2c_tbl_index].reg_data_size = 2;
CDBG("addr:0x%x 0x%x, 0x%x\n",
i2c_seq[a_ctrl->i2c_tbl_index].reg_addr,
i2c_seq[a_ctrl->i2c_tbl_index].reg_data[0],
i2c_seq[a_ctrl->i2c_tbl_index].reg_data[1]);
a_ctrl->i2c_tbl_index++;
continue;
}
if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
value = (next_lens_position <<
write_arr[i].data_shift) |
......@@ -164,6 +183,75 @@ static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
return rc;
}
static int32_t msm_actuator_vcm_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
uint16_t size, enum msm_actuator_data_type type,
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 int32_t msm_actuator_hall_effect_init_focus(
struct msm_actuator_ctrl_t *a_ctrl,
uint16_t size, enum msm_actuator_data_type type,
......@@ -433,6 +521,7 @@ static int32_t msm_actuator_dw9804_init_focus(struct msm_actuator_ctrl_t *a_ctrl
CDBG("Exit\n");
return rc;
}
static void msm_actuator_write_focus(
struct msm_actuator_ctrl_t *a_ctrl,
uint16_t curr_lens_pos,
......@@ -557,6 +646,7 @@ static int32_t msm_actuator_hall_effect_move_focus(
CDBG("%s exit %d\n", __func__, __LINE__);
return rc;
}
static int msm_actuator_dw9804_write_dac(
struct msm_actuator_ctrl_t *a_ctrl,
uint8_t msb, uint8_t lsb, uint16_t wait_time)
......@@ -724,7 +814,7 @@ static int32_t msm_actuator_move_focus(
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;
CDBG("called, dir %d, num_steps %d\n", dir, num_steps);
......@@ -771,12 +861,22 @@ static int32_t msm_actuator_move_focus(
}
a_ctrl->curr_step_pos = target_step_pos;
}
if (a_ctrl->reg_tbl[0].reg_write_type == MSM_ACTUATOR_WRITE_DAC_SEQ) {
struct msm_camera_i2c_seq_reg_setting reg_setting;
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, &reg_setting);
reg_setting.reg_setting = a_ctrl->i2c_reg_seq_tbl;
reg_setting.addr_type = a_ctrl->i2c_client.addr_type;
reg_setting.size = a_ctrl->i2c_tbl_index;
rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_seq_table(
&a_ctrl->i2c_client, &reg_setting);
} else {
struct msm_camera_i2c_reg_setting reg_setting;
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, &reg_setting);
}
if (rc < 0) {
pr_err("i2c write error:%d\n", rc);
return rc;
......@@ -839,6 +939,78 @@ static int32_t msm_actuator_init_step_table(struct msm_actuator_ctrl_t *a_ctrl,
}
}
}
#ifdef MSM_ACUTUATOR_DEBUG
{
uint16_t i;
CDBG("******** step table **************");
for (i = 0; i < step_index; i++) {
CDBG("[%d] %d(0x%x)", i, a_ctrl->step_position_table[i],
a_ctrl->step_position_table[i]);
}
CDBG("**********************************");
}
#endif
CDBG("Exit\n");
return 0;
}
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;
}
......@@ -963,6 +1135,7 @@ static int32_t msm_actuator_dw9804_init_step_table(struct msm_actuator_ctrl_t *a
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)
......@@ -992,6 +1165,8 @@ static int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl)
a_ctrl->step_position_table = NULL;
kfree(a_ctrl->i2c_reg_tbl);
a_ctrl->i2c_reg_tbl = NULL;
vfree(a_ctrl->i2c_reg_seq_tbl);
a_ctrl->i2c_reg_seq_tbl = NULL;
a_ctrl->i2c_tbl_index = 0;
CDBG("Exit\n");
return rc;
......@@ -1039,6 +1214,67 @@ static int32_t msm_actuator_set_position(
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, &reg_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;
}
/*Added by Justin_Qualcomm for SEMCO Actuator Direct Move : 20130718*/
static int32_t msm_actuator_hvcm_set_position(
struct msm_actuator_ctrl_t *a_ctrl,
......@@ -1121,6 +1357,7 @@ static int32_t msm_actuator_dw9804_set_position(
CDBG("%s exit %d\n", __func__, __LINE__);
return rc;
}
static int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_set_info_t *set_info) {
int32_t rc = -EFAULT;
......@@ -1173,22 +1410,33 @@ static int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl,
return -EFAULT;
}
if (a_ctrl->i2c_reg_tbl != NULL){
kfree(a_ctrl->i2c_reg_tbl);
kfree(a_ctrl->i2c_reg_tbl);
a_ctrl->i2c_reg_tbl = NULL;
}
if (a_ctrl->i2c_reg_seq_tbl != NULL) {
vfree(a_ctrl->i2c_reg_seq_tbl);
a_ctrl->i2c_reg_seq_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;
goto ERROR;
}
a_ctrl->i2c_reg_seq_tbl =
vmalloc(sizeof(struct msm_camera_i2c_seq_reg_array) *
(set_info->af_tuning_params.total_steps + 1));
if (!a_ctrl->i2c_reg_seq_tbl) {
pr_err("kmalloc fail\n");
goto ERROR;
}
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);
return -EFAULT;
goto ERROR;
}
if (set_info->actuator_params.init_setting_size) {
......@@ -1197,29 +1445,35 @@ static int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl,
(set_info->actuator_params.init_setting_size),
GFP_KERNEL);
if (init_settings == NULL) {
kfree(a_ctrl->i2c_reg_tbl);
pr_err("Error allocating memory for init_settings\n");
return -EFAULT;
goto ERROR;
}
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);
pr_err("Error copying init_settings\n");
return -EFAULT;
if (init_settings) {
kfree(init_settings);
init_settings = NULL;
}
goto ERROR;
}
rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl,
set_info->actuator_params.init_setting_size,
a_ctrl->i2c_data_type,
init_settings);
kfree(init_settings);
if (rc < 0) {
kfree(a_ctrl->i2c_reg_tbl);
pr_err("Error actuator_init_focus\n");
return -EFAULT;
pr_err("Error copying init_settings\n");
if (init_settings) {
kfree(init_settings);
init_settings = NULL;
}
goto ERROR;
}
kfree(init_settings);
init_settings = NULL;
}
}
......@@ -1233,6 +1487,16 @@ static int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl,
CDBG("Exit\n");
return rc;
ERROR:
if (a_ctrl->i2c_reg_tbl != NULL) {
kfree(a_ctrl->i2c_reg_tbl);
a_ctrl->i2c_reg_tbl = NULL;
}
if (a_ctrl->i2c_reg_seq_tbl != NULL) {
vfree(a_ctrl->i2c_reg_seq_tbl);
a_ctrl->i2c_reg_seq_tbl = NULL;
}
return -EFAULT;
}
static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
......@@ -1241,6 +1505,10 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_cfg_data *cdata =
(struct msm_actuator_cfg_data *)argp;
int32_t rc = 0;
if (!a_ctrl) {
pr_err("failed\n");
return -EINVAL;
}
mutex_lock(a_ctrl->actuator_mutex);
CDBG("Enter\n");
CDBG("%s type %d\n", __func__, cdata->cfgtype);
......@@ -1279,7 +1547,8 @@ static int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
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);
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);
}
......@@ -1328,8 +1597,70 @@ static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
msm_camera_qup_i2c_write_table_w_microdelay,
};
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;
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)
{
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*/
damping_params = &move_params->ringing_params[2];
damp_delay = damping_params->damping_delay;
damp_step = damping_params->damping_step;
pos_index = damping_params->hw_params;
First_damping_lens_pos = a_ctrl->step_position_table[pos_index];
Second_damping_lens_pos = (First_damping_lens_pos>>2);
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__);
a_ctrl->i2c_tbl_index = 0;
do{
if(lens_pos <= Second_damping_lens_pos) 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, &reg_setting);
if (rc < 0) {
pr_err("%s Failed I2C write Line %d\n", __func__, __LINE__);
return rc;
}
return rc;
}
static int32_t msm_actuator_dw9804_sw_landing(
struct msm_actuator_ctrl_t *a_ctrl)
struct msm_actuator_ctrl_t *a_ctrl,
struct msm_actuator_move_params_t *move_params)
{
int32_t rc = 0;
uint16_t msb, lsb;
......@@ -1337,7 +1668,7 @@ static int32_t msm_actuator_dw9804_sw_landing(
int32_t curr_step_pos;
uint16_t curr_lens_pos;
CDBG("%s Enter %d\n", __func__, __LINE__);
if(a_ctrl == NULL || a_ctrl->step_position_table == NULL)
if(a_ctrl == NULL || a_ctrl->step_position_table == NULL || move_params == NULL)
{
pr_err("%s %d NULL Pointer\n", __func__, __LINE__);
return 0;
......@@ -1381,6 +1712,7 @@ static int32_t msm_actuator_dw9804_sw_landing(
}
return rc;
}
static int msm_actuator_open(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh) {
int rc = 0;
......@@ -1432,6 +1764,8 @@ static int msm_actuator_close(struct v4l2_subdev *sd,
if (rc < 0)
pr_err("cci_init failed\n");
}
vfree(a_ctrl->i2c_reg_seq_tbl);
a_ctrl->i2c_reg_seq_tbl = NULL;
CDBG("Exit\n");
return rc;
}
......@@ -1832,13 +2166,14 @@ static int __init msm_actuator_init_module(void)
static struct msm_actuator msm_vcm_actuator_table = {
.act_type = ACTUATOR_VCM,
.func_tbl = {
.actuator_init_step_table = msm_actuator_init_step_table,
.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_init_focus,
.actuator_init_focus = msm_actuator_vcm_init_focus,
.actuator_parse_i2c_params = msm_actuator_parse_i2c_params,
.actuator_sw_landing = NULL,
.actuator_set_position = msm_actuator_vcm_set_position,
.actuator_sw_landing = msm_actuator_vcm_sw_landing,
},
};
......@@ -1896,6 +2231,8 @@ static struct msm_actuator msm_dw9804_actuator_table = {
.actuator_sw_landing = msm_actuator_dw9804_sw_landing,
},
};
module_init(msm_actuator_init_module);
MODULE_DESCRIPTION("MSM ACTUATOR");
MODULE_LICENSE("GPL v2");
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment