blob: acab45e5f9d72ad0f04360e397fa76822826f324 [file] [log] [blame]
/* Copyright (c) 2013-2018, 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 "msm_sensor_init.h"
#include "msm_sensor_driver.h"
#include "msm_sensor.h"
#include "msm_sd.h"
/* Logging macro */
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
static struct msm_sensor_init_t *s_init;
static struct v4l2_file_operations msm_sensor_init_v4l2_subdev_fops;
/* 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 = 20000;
if (s_init->module_init_status == 1) {
CDBG("msm_cam_get_module_init_status -2\n");
return 0;
}
rc = wait_event_timeout(s_init->state_wait,
(s_init->module_init_status == 1), msecs_to_jiffies(tm));
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 %pK cfg %pK", 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,
&cfg->probed_info,
cfg->entity_name);
mutex_unlock(&s_init->imutex);
if (rc < 0)
pr_err_ratelimited("%s failed (non-fatal) rc %d",
__func__, 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)
{
long 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 %pK", 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;
}
#ifdef CONFIG_COMPAT
static long msm_sensor_init_subdev_do_ioctl(
struct file *file, unsigned int cmd, void *arg)
{
int32_t rc = 0;
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct sensor_init_cfg_data32 *u32 =
(struct sensor_init_cfg_data32 *)arg;
struct sensor_init_cfg_data sensor_init_data;
switch (cmd) {
case VIDIOC_MSM_SENSOR_INIT_CFG32:
memset(&sensor_init_data, 0, sizeof(sensor_init_data));
sensor_init_data.cfgtype = u32->cfgtype;
sensor_init_data.cfg.setting =
(__force void *)compat_ptr(u32->cfg.setting);
cmd = VIDIOC_MSM_SENSOR_INIT_CFG;
rc = msm_sensor_init_subdev_ioctl(sd, cmd, &sensor_init_data);
if (rc < 0) {
pr_err_ratelimited("%s:%d VIDIOC_MSM_SENSOR_INIT_CFG failed (non-fatal)",
__func__, __LINE__);
return rc;
}
u32->probed_info = sensor_init_data.probed_info;
strlcpy(u32->entity_name, sensor_init_data.entity_name,
sizeof(sensor_init_data.entity_name));
return 0;
default:
return msm_sensor_init_subdev_ioctl(sd, cmd, arg);
}
}
static long msm_sensor_init_subdev_fops_ioctl(
struct file *file, unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, msm_sensor_init_subdev_do_ioctl);
}
#endif
static int __init msm_sensor_init_module(void)
{
int ret = 0;
/* Allocate memory for msm_sensor_init control structure */
s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL);
if (!s_init)
return -ENOMEM;
CDBG("MSM_SENSOR_INIT_MODULE %pK", 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;
media_entity_pads_init(&s_init->msm_sd.sd.entity, 0, NULL);
s_init->msm_sd.sd.entity.function = 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;
ret = msm_sd_register(&s_init->msm_sd);
if (ret) {
CDBG("%s: msm_sd_register error = %d\n", __func__, ret);
goto error;
}
msm_cam_copy_v4l2_subdev_fops(&msm_sensor_init_v4l2_subdev_fops);
#ifdef CONFIG_COMPAT
msm_sensor_init_v4l2_subdev_fops.compat_ioctl32 =
msm_sensor_init_subdev_fops_ioctl;
#endif
s_init->msm_sd.sd.devnode->fops =
&msm_sensor_init_v4l2_subdev_fops;
init_waitqueue_head(&s_init->state_wait);
return 0;
error:
mutex_destroy(&s_init->imutex);
kfree(s_init);
return ret;
}
static void __exit msm_sensor_exit_module(void)
{
msm_sd_unregister(&s_init->msm_sd);
mutex_destroy(&s_init->imutex);
kfree(s_init);
}
module_init(msm_sensor_init_module);
module_exit(msm_sensor_exit_module);
MODULE_DESCRIPTION("msm_sensor_init");
MODULE_LICENSE("GPL v2");