diff --git a/drivers/media/platform/msm/ais/Makefile b/drivers/media/platform/msm/ais/Makefile index b09636a72413..4387b96f01d0 100644 --- a/drivers/media/platform/msm/ais/Makefile +++ b/drivers/media/platform/msm/ais/Makefile @@ -21,4 +21,5 @@ obj-$(CONFIG_MSM_AIS) += ispif/ obj-$(CONFIG_MSM_AIS_JPEG) += jpeg_10/ obj-$(CONFIG_MSM_AIS_JPEGDMA) += jpeg_dma/ obj-$(CONFIG_MSM_AIS) += msm_buf_mgr/ +obj-$(CONFIG_MSM_AIS) += msm_ais_mgr/ obj-$(CONFIG_MSM_AIS_FD) += fd/ diff --git a/drivers/media/platform/msm/ais/isp/msm_isp47.c b/drivers/media/platform/msm/ais/isp/msm_isp47.c index 04e879fc3bcf..1215713ea8c2 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp47.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp47.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -306,19 +306,12 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev) vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = vfe_dev->vfe_base; - rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - MSM_ISP_MIN_AB, MSM_ISP_MIN_IB); - if (rc) - goto bw_enable_fail; - rc = msm_camera_enable_irq(vfe_dev->vfe_irq, 1); if (rc < 0) goto irq_enable_fail; return rc; irq_enable_fail: - msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, 0, 0); -bw_enable_fail: vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL; if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0) pr_err("%s: failed to remove vote for AHB\n", __func__); @@ -347,8 +340,6 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev) vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL; - msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, 0, 0); - if (vfe_dev->pdev->id == 0) id = CAM_AHB_CLIENT_VFE0; else diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c index a85ee30769c4..c0a36843d7ff 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_axi_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -1106,9 +1106,11 @@ void msm_isp_calculate_bandwidth( int bpp = 0; if (stream_info->stream_src < RDI_INTF_0) { + stream_info->max_width = max(stream_info->max_width, + axi_data->src_info[VFE_PIX_0].width); stream_info->bandwidth = - (axi_data->src_info[VFE_PIX_0].pixel_clock / - axi_data->src_info[VFE_PIX_0].width) * + (axi_data->src_info[VFE_PIX_0].pixel_clock * + axi_data->src_info[VFE_PIX_0].width) / stream_info->max_width; stream_info->bandwidth = (unsigned long)stream_info->bandwidth * stream_info->format_factor / ISP_Q2; @@ -2272,8 +2274,7 @@ int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev, total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth; rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, - (total_bandwidth + vfe_dev->hw_info->min_ab), - (total_bandwidth + vfe_dev->hw_info->min_ib)); + total_bandwidth, total_bandwidth); if (rc < 0) pr_err("%s: update failed\n", __func__); diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_util.c index 9e5317eb2920..0f749ec03132 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -2217,6 +2217,7 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); long rc = 0; + enum cam_ahb_clk_client id; ISP_DBG("%s open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt); @@ -2291,6 +2292,17 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) cam_smmu_reg_client_page_fault_handler( vfe_dev->buf_mgr->iommu_hdl, msm_vfe_iommu_fault_handler, vfe_dev); + + /* Disable vfe clks and allow device to go XO shutdown mode */ + if (vfe_dev->pdev->id == 0) + id = CAM_AHB_CLIENT_VFE0; + else + id = CAM_AHB_CLIENT_VFE1; + if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0) + pr_err("%s: failed to remove vote for AHB\n", __func__); + vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 0); + vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0); + mutex_unlock(&vfe_dev->core_mutex); mutex_unlock(&vfe_dev->realtime_mutex); return 0; @@ -2313,11 +2325,22 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) long rc = 0; int wm; struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd); + enum cam_ahb_clk_client id; ISP_DBG("%s E open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt); mutex_lock(&vfe_dev->realtime_mutex); mutex_lock(&vfe_dev->core_mutex); + /* Enable vfe clks to wake up from XO shutdown mode */ + if (vfe_dev->pdev->id == 0) + id = CAM_AHB_CLIENT_VFE0; + else + id = CAM_AHB_CLIENT_VFE1; + if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE) < 0) + pr_err("%s: failed to vote for AHB\n", __func__); + vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 1); + if (!vfe_dev->vfe_open_cnt) { pr_err("%s invalid state open cnt %d\n", __func__, vfe_dev->vfe_open_cnt); diff --git a/drivers/media/platform/msm/ais/ispif/msm_ispif.c b/drivers/media/platform/msm/ais/ispif/msm_ispif.c index bb75e69ea215..a72ac566bb8c 100644 --- a/drivers/media/platform/msm/ais/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/ais/ispif/msm_ispif.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -1437,13 +1437,6 @@ static int msm_ispif_init(struct ispif_device *ispif, return -ENOMEM; } - rc = cam_config_ahb_clk(NULL, 0, - CAM_AHB_CLIENT_ISPIF, CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - return rc; - } - rc = msm_ispif_reset_hw(ispif); if (rc) goto error_ahb; @@ -1608,6 +1601,11 @@ static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) rc = msm_camera_enable_irq(ispif->irq, 1); if (rc) goto irq_enable_fail; + + /* Disable ispif clk and allow device to go XO shutdown */ + msm_ispif_clk_ahb_enable(ispif, 0); + msm_ispif_set_regulators(ispif->ispif_vdd, + ispif->ispif_vdd_count, 0); } /* mem remap is done in init when the clock is on */ ispif->open_cnt++; @@ -1640,6 +1638,10 @@ static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) } ispif->open_cnt--; if (ispif->open_cnt == 0) { + /* Enable ispif clk to wake up from XO shutdown mode */ + msm_ispif_clk_ahb_enable(ispif, 1); + msm_ispif_set_regulators(ispif->ispif_vdd, + ispif->ispif_vdd_count, 1); msm_ispif_release(ispif); /* disable clocks and regulator on last close */ msm_ispif_clk_ahb_enable(ispif, 0); diff --git a/drivers/media/platform/msm/ais/msm_ais_mgr/Makefile b/drivers/media/platform/msm/ais/msm_ais_mgr/Makefile new file mode 100644 index 000000000000..b7a078738489 --- /dev/null +++ b/drivers/media/platform/msm/ais/msm_ais_mgr/Makefile @@ -0,0 +1,5 @@ +ccflags-y += -Idrivers/media/platform/msm/ais +ccflags-y += -Idrivers/media/platform/msm/ais/common +ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io +ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci +obj-$(CONFIG_MSM_AIS) += msm_ais_mgr.o diff --git a/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mgr.c b/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mgr.c new file mode 100644 index 000000000000..9391c1d0d4ab --- /dev/null +++ b/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mgr.c @@ -0,0 +1,147 @@ +/* Copyright (c) 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) "CAM-BUFMGR %s:%d " fmt, __func__, __LINE__ + +#include +#include "msm_ais_mngr.h" +#include "msm_early_cam.h" + +#undef CDBG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) + +static struct msm_ais_mngr_device *msm_ais_mngr_dev; + +static long msm_ais_hndl_ioctl(struct v4l2_subdev *sd, void *arg) +{ + long rc = 0; + struct clk_mgr_cfg_data *pcdata = (struct clk_mgr_cfg_data *)arg; + struct msm_ais_mngr_device *clk_mngr_dev = + (struct msm_ais_mngr_device *)v4l2_get_subdevdata(sd); + + if (WARN_ON(!clk_mngr_dev) || WARN_ON(!pcdata)) { + rc = -EINVAL; + return rc; + } + + mutex_lock(&clk_mngr_dev->cont_mutex); + CDBG(pr_fmt("cfg_type = %d\n"), pcdata->cfg_type); + switch (pcdata->cfg_type) { + case AIS_CLK_ENABLE: + rc = msm_ais_enable_clocks(); + break; + case AIS_CLK_DISABLE: + rc = msm_ais_disable_clocks(); + break; + + default: + pr_err("invalid cfg_type\n"); + rc = -EINVAL; + } + mutex_unlock(&clk_mngr_dev->cont_mutex); + return rc; +} + +static long msm_ais_mngr_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + + CDBG(pr_fmt("Enter\n")); + switch (cmd) { + case VIDIOC_MSM_AIS_CLK_CFG: + rc = msm_ais_hndl_ioctl(sd, arg); + if (rc) + pr_err("msm_ais_mngr_subdev_ioctl failed\n"); + break; + default: + rc = -ENOIOCTLCMD; + } + CDBG(pr_fmt("Exit\n")); + return rc; +} + +static struct v4l2_subdev_core_ops msm_ais_mngr_subdev_core_ops = { + .ioctl = msm_ais_mngr_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_ais_mngr_subdev_ops = { + .core = &msm_ais_mngr_subdev_core_ops, +}; + +static struct v4l2_file_operations msm_ais_v4l2_subdev_fops; + +static long msm_clkmgr_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); +} + + +static long msm_ais_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, msm_clkmgr_subdev_do_ioctl); +} + +static int32_t __init msm_ais_mngr_init(void) +{ + int32_t rc = 0; + + msm_ais_mngr_dev = kzalloc(sizeof(*msm_ais_mngr_dev), + GFP_KERNEL); + if (!msm_ais_mngr_dev) + return -ENOMEM; + + /* Sub-dev */ + v4l2_subdev_init(&msm_ais_mngr_dev->subdev.sd, + &msm_ais_mngr_subdev_ops); + msm_cam_copy_v4l2_subdev_fops(&msm_ais_v4l2_subdev_fops); + msm_ais_v4l2_subdev_fops.unlocked_ioctl = msm_ais_subdev_fops_ioctl; + + snprintf(msm_ais_mngr_dev->subdev.sd.name, + ARRAY_SIZE(msm_ais_mngr_dev->subdev.sd.name), "msm_ais_mngr"); + msm_ais_mngr_dev->subdev.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_set_subdevdata(&msm_ais_mngr_dev->subdev.sd, msm_ais_mngr_dev); + + media_entity_init(&msm_ais_mngr_dev->subdev.sd.entity, 0, NULL, 0); + msm_ais_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + msm_ais_mngr_dev->subdev.sd.entity.group_id = + MSM_CAMERA_SUBDEV_AIS_MNGR; + msm_ais_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY; + rc = msm_sd_register(&msm_ais_mngr_dev->subdev); + if (rc != 0) { + pr_err("msm_sd_register error = %d\n", rc); + kfree(msm_ais_mngr_dev); + return rc; + } + + msm_ais_mngr_dev->subdev.sd.devnode->fops = &msm_ais_v4l2_subdev_fops; + mutex_init(&msm_ais_mngr_dev->cont_mutex); + + return rc; +} + +static void __exit msm_ais_mngr_exit(void) +{ + msm_sd_unregister(&msm_ais_mngr_dev->subdev); + mutex_destroy(&msm_ais_mngr_dev->cont_mutex); + kfree(msm_ais_mngr_dev); +} + +module_init(msm_ais_mngr_init); +module_exit(msm_ais_mngr_exit); +MODULE_DESCRIPTION("MSM AIS Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mngr.h b/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mngr.h new file mode 100644 index 000000000000..a41a2ca7a48c --- /dev/null +++ b/drivers/media/platform/msm/ais/msm_ais_mgr/msm_ais_mngr.h @@ -0,0 +1,31 @@ +/* Copyright (c) 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. + */ + +#ifndef __MSM_CLK_GENERIC_MNGR_H__ +#define __MSM_CLK_GENERIC_MNGR_H__ + +#include +#include +#include +#include +#include +#include + +#include "msm.h" +#include "msm_sd.h" + +struct msm_ais_mngr_device { + struct msm_sd_subdev subdev; + struct mutex cont_mutex; +}; + +#endif diff --git a/drivers/media/platform/msm/ais/sensor/cci/Makefile b/drivers/media/platform/msm/ais/sensor/cci/Makefile index b8b8c83bc6de..2bb64c16f67d 100644 --- a/drivers/media/platform/msm/ais/sensor/cci/Makefile +++ b/drivers/media/platform/msm/ais/sensor/cci/Makefile @@ -1,5 +1,6 @@ ccflags-y += -Idrivers/media/platform/msm/ais ccflags-y += -Idrivers/media/platform/msm/ais/common ccflags-y += -Idrivers/media/platform/msm/ais/sensor/io +ccflags-y += -Idrivers/media/platform/msm/ais/sensor/cci obj-$(CONFIG_MSM_AIS) += msm_cci.o obj-$(CONFIG_MSM_AIS) += msm_early_cam.o diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c b/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c index 00ec613e7303..fa7a93345575 100644 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c +++ b/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-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 @@ -112,6 +112,199 @@ int msm_early_cam_disable_clocks(void) pr_debug("Turned OFF camera clocks\n"); return 0; +} + +int msm_ais_enable_clocks(void) +{ + int rc = 0; + + CDBG("%s:\n", __func__); + /* Vote ON for clocks */ + if (new_early_cam_dev == NULL) { + rc = -EINVAL; + pr_err("%s: clock structure uninitialised %d\n", __func__, + rc); + return rc; + } + + /* Vote for camera abh clocks */ + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, + CAM_AHB_SVS_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote for AHB\n", __func__); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID, + CAM_AHB_SVS_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote for AHB\n", __func__); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF, + CAM_AHB_SVS_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote for AHB\n", __func__); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_VFE0, + CAM_AHB_SVS_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote for AHB\n", __func__); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_VFE1, + CAM_AHB_SVS_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote for AHB\n", __func__); + return rc; + } + + if (new_early_cam_dev->pdev->dev.of_node) + of_property_read_u32((&new_early_cam_dev->pdev->dev)->of_node, + "cell-index", &new_early_cam_dev->pdev->id); + + rc = msm_camera_get_clk_info_and_rates(new_early_cam_dev->pdev, + &new_early_cam_dev->early_cam_clk_info, + &new_early_cam_dev->early_cam_clk, + &new_early_cam_dev->early_cam_clk_rates, + &new_early_cam_dev->num_clk_cases, + &new_early_cam_dev->num_clk); + if (rc < 0) { + pr_err("%s: msm_early_cam_get_clk_info() failed", __func__); + return -EFAULT; + } + + rc = msm_camera_get_dt_vreg_data( + new_early_cam_dev->pdev->dev.of_node, + &(new_early_cam_dev->early_cam_vreg), + &(new_early_cam_dev->regulator_count)); + if (rc < 0) { + pr_err("%s: msm_camera_get_dt_vreg_data fail\n", __func__); + rc = -EFAULT; + return rc; + } + + if ((new_early_cam_dev->regulator_count < 0) || + (new_early_cam_dev->regulator_count > MAX_REGULATOR)) { + pr_err("%s: invalid reg count = %d, max is %d\n", __func__, + new_early_cam_dev->regulator_count, MAX_REGULATOR); + rc = -EFAULT; + return rc; + } + + rc = msm_camera_config_vreg(&new_early_cam_dev->pdev->dev, + new_early_cam_dev->early_cam_vreg, + new_early_cam_dev->regulator_count, + NULL, + 0, + &new_early_cam_dev->early_cam_reg_ptr[0], 1); + if (rc < 0) + pr_err("%s:%d early_cam config_vreg failed\n", __func__, + __LINE__); + + rc = msm_camera_enable_vreg(&new_early_cam_dev->pdev->dev, + new_early_cam_dev->early_cam_vreg, + new_early_cam_dev->regulator_count, + NULL, + 0, + &new_early_cam_dev->early_cam_reg_ptr[0], 1); + if (rc < 0) + pr_err("%s:%d early_cam enable_vreg failed\n", __func__, + __LINE__); + + rc = msm_camera_clk_enable(&new_early_cam_dev->pdev->dev, + new_early_cam_dev->early_cam_clk_info, + new_early_cam_dev->early_cam_clk, + new_early_cam_dev->num_clk, true); + + if (rc < 0) { + pr_err("%s: clk enable failed %d\n", __func__, rc); + rc = 0; + return rc; + } + pr_debug("Turned ON camera clocks\n"); + return 0; + +} + +int msm_ais_disable_clocks(void) +{ + int rc = 0; + + CDBG("%s:\n", __func__); + /* Vote OFF for clocks */ + if (new_early_cam_dev == NULL) { + rc = -EINVAL; + pr_err("%s: clock structure uninitialised %d\n", __func__, + rc); + return rc; + } + + if ((new_early_cam_dev->pdev == NULL) || + (new_early_cam_dev->early_cam_clk_info == NULL) || + (new_early_cam_dev->early_cam_clk == NULL) || + (new_early_cam_dev->num_clk == 0)) { + rc = -EINVAL; + pr_err("%s: Clock details uninitialised %d\n", __func__, + rc); + return rc; + } + + rc = msm_camera_clk_enable(&new_early_cam_dev->pdev->dev, + new_early_cam_dev->early_cam_clk_info, + new_early_cam_dev->early_cam_clk, + new_early_cam_dev->num_clk, false); + if (rc < 0) { + pr_err("%s: clk disable failed %d\n", __func__, rc); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY, + CAM_AHB_SUSPEND_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote OFF AHB_CLIENT_CSIPHY %d\n", + __func__, rc); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID, + CAM_AHB_SUSPEND_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote OFF AHB_CLIENT_CSID %d\n", + __func__, rc); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF, + CAM_AHB_SUSPEND_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote OFF AHB_CLIENT_ISPIF %d\n", + __func__, rc); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_VFE0, + CAM_AHB_SUSPEND_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote OFF AHB_CLIENT_VFE0 %d\n", + __func__, rc); + return rc; + } + + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_VFE1, + CAM_AHB_SUSPEND_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote OFF AHB_CLIENT_VFE0 %d\n", + __func__, rc); + return rc; + } + pr_debug("Turned OFF camera clocks\n"); + return 0; + } static int msm_early_cam_probe(struct platform_device *pdev) { diff --git a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.h b/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.h index a40ab2d1ebc3..e2530d05955c 100644 --- a/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.h +++ b/drivers/media/platform/msm/ais/sensor/cci/msm_early_cam.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -20,6 +20,7 @@ #include #include #include +#include #include "msm_sd.h" #include "cam_soc_api.h" @@ -50,4 +51,6 @@ struct early_cam_device { }; int msm_early_cam_disable_clocks(void); +int msm_ais_enable_clocks(void); +int msm_ais_disable_clocks(void); #endif diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c index d94f082e6765..643ba556db0d 100644 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c +++ b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -1733,3 +1733,50 @@ int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl, return 0; } +int msm_camera_cci_power_up(enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client) +{ + int rc = 0; + + CDBG("%s:%d\n", __func__, __LINE__); + if (!sensor_i2c_client) { + pr_err("failed sensor_i2c_client %pK\n", + sensor_i2c_client); + return -EINVAL; + } + + if (device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = sensor_i2c_client->i2c_func_tbl->i2c_util( + sensor_i2c_client, MSM_CCI_INIT); + if (rc < 0) { + pr_err("%s cci_init failed\n", __func__); + return rc; + } + } + CDBG("%s exit\n", __func__); + return rc; +} + +int msm_camera_cci_power_down(enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client) +{ + int rc = 0; + + CDBG("%s:%d\n", __func__, __LINE__); + if (!sensor_i2c_client) { + pr_err("failed sensor_i2c_client %pK\n", + sensor_i2c_client); + return -EINVAL; + } + + if (device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = sensor_i2c_client->i2c_func_tbl->i2c_util( + sensor_i2c_client, MSM_CCI_RELEASE); + if (rc < 0) { + pr_err("%s MSM_CCI_RELEASE failed\n", __func__); + return rc; + } + } + CDBG("%s exit\n", __func__); + return rc; +} diff --git a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.h index fdeeb4aebf00..560a03d34696 100644 --- a/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.h +++ b/drivers/media/platform/msm/ais/sensor/io/msm_camera_dt_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -68,4 +68,10 @@ int msm_cam_sensor_handle_reg_gpio(int seq_val, int32_t msm_sensor_driver_get_gpio_data( struct msm_camera_gpio_conf **gpio_conf, struct device_node *of_node); + +int msm_camera_cci_power_up(enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client); + +int msm_camera_cci_power_down(enum msm_camera_device_type_t device_type, + struct msm_camera_i2c_client *sensor_i2c_client); #endif diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor.c b/drivers/media/platform/msm/ais/sensor/msm_sensor.c index 9655fad5b62b..2801fc3ed34e 100644 --- a/drivers/media/platform/msm/ais/sensor/msm_sensor.c +++ b/drivers/media/platform/msm/ais/sensor/msm_sensor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -875,6 +875,30 @@ static int msm_sensor_config32(struct msm_sensor_ctrl_t *s_ctrl, rc = -EFAULT; } break; + case CFG_CCI_POWER_UP: + if (s_ctrl->is_csid_tg_mode) + goto DONE; + + rc = msm_camera_cci_power_up(s_ctrl->sensor_device_type, + s_ctrl->sensor_i2c_client); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + break; + case CFG_CCI_POWER_DOWN: + if (s_ctrl->is_csid_tg_mode) + goto DONE; + + rc = msm_camera_cci_power_down(s_ctrl->sensor_device_type, + s_ctrl->sensor_i2c_client); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + break; case CFG_SET_STOP_STREAM_SETTING: { struct msm_camera_i2c_reg_setting32 stop_setting32; struct msm_camera_i2c_reg_setting *stop_setting = @@ -1364,6 +1388,32 @@ int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void *argp) } break; + case CFG_CCI_POWER_UP: + if (s_ctrl->is_csid_tg_mode) + goto DONE; + + rc = msm_camera_cci_power_up(s_ctrl->sensor_device_type, + s_ctrl->sensor_i2c_client); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + break; + + case CFG_CCI_POWER_DOWN: + if (s_ctrl->is_csid_tg_mode) + goto DONE; + + rc = msm_camera_cci_power_down(s_ctrl->sensor_device_type, + s_ctrl->sensor_i2c_client); + if (rc < 0) { + pr_err("%s:%d failed rc %d\n", __func__, + __LINE__, rc); + break; + } + break; + case CFG_SET_STOP_STREAM_SETTING: { struct msm_camera_i2c_reg_setting *stop_setting = &s_ctrl->stop_setting; diff --git a/include/uapi/media/ais/Kbuild b/include/uapi/media/ais/Kbuild index 121e3a61560f..c8d50c7d077c 100644 --- a/include/uapi/media/ais/Kbuild +++ b/include/uapi/media/ais/Kbuild @@ -4,3 +4,4 @@ header-y += msm_ais_isp.h header-y += msm_ais_ispif.h header-y += msm_ais_sensor.h header-y += msm_ais_sensor_sdk.h +header-y += msm_ais_mgr.h diff --git a/include/uapi/media/ais/msm_ais.h b/include/uapi/media/ais/msm_ais.h index 9156ca0c9083..c393a2a7f636 100644 --- a/include/uapi/media/ais/msm_ais.h +++ b/include/uapi/media/ais/msm_ais.h @@ -52,6 +52,7 @@ #define MSM_CAMERA_SUBDEV_IR_LED 18 #define MSM_CAMERA_SUBDEV_IR_CUT 19 #define MSM_CAMERA_SUBDEV_EXT 20 +#define MSM_CAMERA_SUBDEV_AIS_MNGR 21 #define MSM_MAX_CAMERA_SENSORS 5 diff --git a/include/uapi/media/ais/msm_ais_mgr.h b/include/uapi/media/ais/msm_ais_mgr.h new file mode 100644 index 000000000000..43ae16df65f9 --- /dev/null +++ b/include/uapi/media/ais/msm_ais_mgr.h @@ -0,0 +1,28 @@ +#ifndef __UAPI_MEDIA_MSM_AIS_MGR_H__ +#define __UAPI_MEDIA_MSM_AIS_MGR_H__ + +#include + +enum clk_mgr_cfg_type_t { + AIS_CLK_ENABLE, + AIS_CLK_DISABLE, +}; + +#define AIS_CLK_ENABLE AIS_CLK_ENABLE +#define AIS_CLK_DISABLE AIS_CLK_DISABLE + +struct clk_mgr_cfg_data_ext { + enum clk_mgr_cfg_type_t cfg_type; +}; + +struct clk_mgr_cfg_data { + enum clk_mgr_cfg_type_t cfg_type; +}; + +#define VIDIOC_MSM_AIS_CLK_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct clk_mgr_cfg_data) + +#define VIDIOC_MSM_AIS_CLK_CFG_EXT \ + _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct clk_mgr_cfg_data_ext) + +#endif /* __UAPI_MEDIA_MSM_AIS_MGR_H__ */ diff --git a/include/uapi/media/ais/msm_ais_sensor.h b/include/uapi/media/ais/msm_ais_sensor.h index eb9c24024383..59c20c8e84ae 100644 --- a/include/uapi/media/ais/msm_ais_sensor.h +++ b/include/uapi/media/ais/msm_ais_sensor.h @@ -369,8 +369,13 @@ enum msm_sensor_cfg_type_t { CFG_WRITE_I2C_ARRAY_ASYNC, CFG_WRITE_I2C_ARRAY_SYNC, CFG_WRITE_I2C_ARRAY_SYNC_BLOCK, + CFG_CCI_POWER_UP, + CFG_CCI_POWER_DOWN, }; +#define CFG_CCI_POWER_UP CFG_CCI_POWER_UP +#define CFG_CCI_POWER_DOWN CFG_CCI_POWER_DOWN + enum msm_actuator_cfg_type_t { CFG_GET_ACTUATOR_INFO, CFG_SET_ACTUATOR_INFO,