624 lines
17 KiB
C
Executable File
624 lines
17 KiB
C
Executable File
/* 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 <linux/delay.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/irqreturn.h>
|
|
#include "msm_csid.h"
|
|
#include "msm_csid_hwreg.h"
|
|
#include "msm_sd.h"
|
|
#include "msm_camera_io_util.h"
|
|
|
|
#define V4L2_IDENT_CSID 50002
|
|
#define CSID_VERSION_V2 0x02000011
|
|
#define CSID_VERSION_V3 0x30000000
|
|
#define MSM_CSID_DRV_NAME "msm_csid"
|
|
|
|
#define DBG_CSID 0
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#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 int msm_csid_cid_lut(
|
|
struct msm_camera_csid_lut_params *csid_lut_params,
|
|
void __iomem *csidbase)
|
|
{
|
|
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, dt = %x, df = %d\n",
|
|
__func__,
|
|
csid_lut_params->num_cid,
|
|
csid_lut_params->vc_cfg[i]->cid,
|
|
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(csidbase + 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, csidbase + 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, csidbase + 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(void __iomem *csidbase,
|
|
struct msm_camera_csid_params *csid_params)
|
|
{
|
|
uint32_t val = 0;
|
|
val = ((1 << csid_params->lane_cnt) - 1) << 20;
|
|
msm_camera_io_w(0xffffffff | val, csidbase + CSID_IRQ_MASK_ADDR);
|
|
msm_camera_io_w(0xffffffff | val, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
|
|
}
|
|
#else
|
|
static void msm_csid_set_debug_reg(void __iomem *csidbase,
|
|
struct msm_camera_csid_params *csid_params) {}
|
|
#endif
|
|
|
|
static void msm_csid_reset(struct csid_device *csid_dev)
|
|
{
|
|
msm_camera_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
|
|
wait_for_completion_interruptible(&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 = %x, phy sel = %d\n",
|
|
__func__,
|
|
csid_params->lane_cnt,
|
|
csid_params->lane_assign,
|
|
csid_params->phy_sel);
|
|
|
|
msm_csid_reset(csid_dev);
|
|
|
|
val = csid_params->lane_cnt - 1;
|
|
val |= csid_params->lane_assign << CSID_DL_INPUT_SEL_SHIFT;
|
|
if (csid_dev->hw_version < 0x30000000) {
|
|
val |= (0xF << 10);
|
|
msm_camera_io_w(val, csidbase + CSID_CORE_CTRL_0_ADDR);
|
|
} else {
|
|
msm_camera_io_w(val, csidbase + CSID_CORE_CTRL_0_ADDR);
|
|
val = csid_params->phy_sel << CSID_PHY_SEL_SHIFT;
|
|
val |= 0xF;
|
|
msm_camera_io_w(val, csidbase + CSID_CORE_CTRL_1_ADDR);
|
|
}
|
|
|
|
rc = msm_csid_cid_lut(&csid_params->lut_params, csidbase);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
msm_csid_set_debug_reg(csidbase, csid_params);
|
|
return rc;
|
|
}
|
|
|
|
static irqreturn_t msm_csid_irq(int irq_num, void *data)
|
|
{
|
|
uint32_t irq;
|
|
struct csid_device *csid_dev ;//prevent
|
|
void __iomem *csidbase;
|
|
|
|
if (!data) {
|
|
pr_err("%s:%d data NULL\n", __func__, __LINE__);
|
|
return IRQ_HANDLED;
|
|
}//prevent
|
|
|
|
csid_dev = data;
|
|
|
|
if (!csid_dev || ! 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_IRQ_STATUS_ADDR);
|
|
CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x unmapped = %x\n",
|
|
__func__, csid_dev->pdev->id, irq, msm_camera_io_r(csid_dev->base + 0x68));
|
|
if (irq & (0x1 << CSID_RST_DONE_IRQ_BITSHIFT))
|
|
complete(&csid_dev->reset_complete);
|
|
msm_camera_io_w(irq, csid_dev->base + 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 struct msm_cam_clk_info csid_8960_clk_info[] = {
|
|
{"csi_src_clk", 177780000},
|
|
{"csi_clk", -1},
|
|
{"csi_phy_clk", -1},
|
|
{"csi_pclk", -1},
|
|
};
|
|
|
|
static struct msm_cam_clk_info csid_8974_clk_info[] = {
|
|
{"camss_top_ahb_clk", -1},
|
|
{"ispif_ahb_clk", -1},
|
|
{"csi_ahb_clk", -1},
|
|
{"csi_src_clk", 200000000},
|
|
{"csi_clk", -1},
|
|
{"csi_phy_clk", -1},
|
|
{"csi_pix_clk", -1},
|
|
{"csi_rdi_clk", -1},
|
|
};
|
|
|
|
static struct camera_vreg_t csid_8960_vreg_info[] = {
|
|
{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
|
|
};
|
|
|
|
static struct camera_vreg_t csid_vreg_info[] = {
|
|
{"qcom,mipi-csi-vdd", REG_LDO, 0, 0, 12000},
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
if (CSID_VERSION <= CSID_VERSION_V2) {
|
|
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);
|
|
if (rc < 0) {
|
|
pr_err("%s: regulator on failed\n", __func__);
|
|
goto vreg_config_failed;
|
|
}
|
|
|
|
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);
|
|
if (rc < 0) {
|
|
pr_err("%s: regulator enable failed\n", __func__);
|
|
goto vreg_enable_failed;
|
|
}
|
|
|
|
rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
|
|
csid_8960_clk_info, csid_dev->csid_clk,
|
|
ARRAY_SIZE(csid_8960_clk_info), 1);
|
|
if (rc < 0) {
|
|
pr_err("%s: clock enable failed\n", __func__);
|
|
goto clk_enable_failed;
|
|
}
|
|
} else if (CSID_VERSION >= CSID_VERSION_V3) {
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
|
|
csid_8974_clk_info, csid_dev->csid_clk,
|
|
ARRAY_SIZE(csid_8974_clk_info), 1);
|
|
if (rc < 0) {
|
|
pr_err("%s: clock enable failed\n", __func__);
|
|
goto clk_enable_failed;
|
|
}
|
|
}
|
|
CDBG("%s:%d called\n", __func__, __LINE__);
|
|
csid_dev->hw_version =
|
|
msm_camera_io_r(csid_dev->base + 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_VERSION <= CSID_VERSION_V2) {
|
|
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 if (CSID_VERSION >= CSID_VERSION_V3) {
|
|
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_VERSION <= CSID_VERSION_V2) {
|
|
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_VERSION >= CSID_VERSION_V3) {
|
|
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;
|
|
}
|
|
|
|
irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
|
|
msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
|
|
msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
|
|
|
|
disable_irq(csid_dev->irq->start);
|
|
|
|
if (csid_dev->hw_version <= CSID_VERSION_V2) {
|
|
msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8960_clk_info,
|
|
csid_dev->csid_clk, ARRAY_SIZE(csid_8960_clk_info), 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_V3) {
|
|
msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8974_clk_info,
|
|
csid_dev->csid_clk, ARRAY_SIZE(csid_8974_clk_info), 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);
|
|
}
|
|
|
|
iounmap(csid_dev->base);
|
|
csid_dev->base = NULL;
|
|
csid_dev->csid_state = CSID_POWER_DOWN;
|
|
return 0;
|
|
}
|
|
|
|
static long 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 %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;
|
|
int32_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;
|
|
}
|
|
for (i = 0; i < csid_params.lut_params.num_cid; i++) {
|
|
vc_cfg = kzalloc(csid_params.lut_params.num_cid *
|
|
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],
|
|
(csid_params.lut_params.num_cid *
|
|
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("%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 __devinit 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;
|
|
}
|
|
|
|
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__);
|
|
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__);
|
|
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;
|
|
}
|
|
|
|
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);
|
|
new_csid_dev->csid_state = CSID_POWER_DOWN;
|
|
return 0;
|
|
|
|
csid_no_resource:
|
|
mutex_destroy(&new_csid_dev->mutex);
|
|
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");
|