msm: ispif: Soc changes for ispif

Use common functions to query clock information from dtsi
in ispif driver so that it can be easily ported to other
platforms.

CRs-Fixed: 998900
Change-Id: I9c06258234a88e6581ebfc6da9c121cfd276985f
Signed-off-by: Shubhraprakash Das <sadas@codeaurora.org>
This commit is contained in:
Shubhraprakash Das 2016-03-25 14:48:18 -07:00 committed by Jeevan Shriram
parent 8b0214d80b
commit 29595740ab
2 changed files with 130 additions and 187 deletions

View file

@ -28,6 +28,7 @@
#include "msm_sd.h"
#include "msm_camera_io_util.h"
#include "cam_hw_ops.h"
#include "cam_soc_api.h"
#ifdef CONFIG_MSM_ISPIF_V1
#include "msm_ispif_hwreg_v1.h"
@ -58,9 +59,7 @@
static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable);
static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
struct platform_device *pdev,
struct msm_cam_clk_info *ahb_clk_info,
struct msm_cam_clk_info *clk_info);
struct platform_device *pdev);
static void msm_ispif_io_dump_reg(struct ispif_device *ispif)
{
@ -96,9 +95,6 @@ static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = {
{"camss_csi_vfe_clk", NO_SET_RATE},
};
static struct msm_cam_clk_info ispif_ahb_clk_info[ISPIF_CLK_INFO_MAX];
static struct msm_cam_clk_info ispif_clk_info[ISPIF_CLK_INFO_MAX];
static void msm_ispif_put_regulator(struct ispif_device *ispif_dev)
{
int i;
@ -231,13 +227,13 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
if (rc < 0)
return rc;
rc = msm_cam_clk_enable(&ispif->pdev->dev,
ispif_clk_info, ispif->clk,
rc = msm_camera_clk_enable(&ispif->pdev->dev,
ispif->clk_info, ispif->clks,
ispif->num_clk, 1);
if (rc < 0) {
pr_err("%s: cannot enable clock, error = %d\n",
__func__, rc);
rc = msm_cam_clk_enable(&ispif->pdev->dev,
rc = msm_camera_clk_enable(&ispif->pdev->dev,
ispif_8626_reset_clk_info, reset_clk1,
ARRAY_SIZE(ispif_8626_reset_clk_info), 1);
if (rc < 0) {
@ -284,13 +280,13 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
clk_disable:
if (ispif->clk_idx == 1) {
rc = rc ? rc : msm_cam_clk_enable(&ispif->pdev->dev,
ispif_clk_info, ispif->clk,
rc = rc ? rc : msm_camera_clk_enable(&ispif->pdev->dev,
ispif->clk_info, ispif->clks,
ispif->num_clk, 0);
}
if (ispif->clk_idx == 2) {
rc = rc ? rc : msm_cam_clk_enable(&ispif->pdev->dev,
rc = rc ? rc : msm_camera_clk_enable(&ispif->pdev->dev,
ispif_8626_reset_clk_info, reset_clk1,
ARRAY_SIZE(ispif_8626_reset_clk_info), 0);
}
@ -302,86 +298,76 @@ reg_disable:
}
int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
struct platform_device *pdev,
struct msm_cam_clk_info *ahb_clk_info,
struct msm_cam_clk_info *clk_info)
struct platform_device *pdev)
{
uint32_t count, num_ahb_clk = 0, non_ahb_clk = 0;
uint32_t num_ahb_clk = 0, non_ahb_clk = 0;
size_t num_clks;
int i, rc;
uint32_t rates[ISPIF_CLK_INFO_MAX];
const char *clk_ctl = NULL;
const char *clk_name = NULL;
struct msm_cam_clk_info *clk_temp;
int j;
struct clk **clks, **temp_clks;
struct msm_cam_clk_info *clk_info, *temp_clk_info;
struct device_node *of_node;
of_node = pdev->dev.of_node;
count = of_property_count_strings(of_node, "clock-names");
rc = msm_camera_get_clk_info(pdev, &clk_info,
&clks, &num_clks);
CDBG("count = %d\n", count);
if (count == 0) {
pr_err("no clocks found in device tree, count=%d", count);
return 0;
}
if (count > ISPIF_CLK_INFO_MAX) {
pr_err("invalid count=%d, max is %d\n", count,
ISPIF_CLK_INFO_MAX);
return -EINVAL;
}
rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
rates, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
if (rc)
return rc;
/*
* reshuffle the clock arrays so that the ahb clocks are
* at the beginning of array
*/
temp_clks = kcalloc(num_clks, sizeof(struct clk *),
GFP_KERNEL);
temp_clk_info = kcalloc(num_clks, sizeof(struct msm_cam_clk_info),
GFP_KERNEL);
if (!temp_clks || !temp_clk_info) {
rc = -ENOMEM;
kfree(temp_clk_info);
kfree(temp_clks);
goto alloc_fail;
}
for (i = 0; i < count; i++) {
rc = of_property_read_string_index(of_node, "clock-names",
i, &clk_name);
if (rc < 0) {
pr_err("%s reading clock-name failed index %d\n",
__func__, i);
return rc;
}
rc = of_property_read_string_index(of_node,
"qcom,clock-control", i, &clk_ctl);
if (rc < 0) {
pr_err("%s reading clock-control failed index %d\n",
__func__, i);
return rc;
}
if (strnstr(clk_name, "ahb", strlen(clk_name))) {
clk_temp = &ahb_clk_info[num_ahb_clk];
j = 0;
for (i = 0; i < num_clks; i++) {
if (strnstr(clk_info[i].clk_name,
"ahb", strlen(clk_info[i].clk_name))) {
temp_clk_info[j] = clk_info[i];
temp_clks[j] = clks[i];
j++;
num_ahb_clk++;
} else {
clk_temp = &clk_info[non_ahb_clk];
}
}
for (i = 0; i < num_clks; i++) {
if (!strnstr(clk_info[i].clk_name,
"ahb", strlen(clk_info[i].clk_name))) {
temp_clk_info[j] = clk_info[i];
temp_clks[j] = clks[i];
j++;
non_ahb_clk++;
}
clk_temp->clk_name = clk_name;
if (!strcmp(clk_ctl, "NO_SET_RATE"))
clk_temp->clk_rate = NO_SET_RATE;
else if (!strcmp(clk_ctl, "INIT_RATE"))
clk_temp->clk_rate = INIT_RATE;
else if (!strcmp(clk_ctl, "SET_RATE"))
clk_temp->clk_rate = rates[i];
else {
pr_err("%s: error: clock control has invalid value\n",
__func__);
return -EBUSY;
}
CDBG("%s: clock-name= %s, clk_rate = %ld clock-control = %s\n",
__func__, clk_temp->clk_name, clk_temp->clk_rate,
clk_ctl);
}
for (i = 0; i < num_clks; i++) {
clk_info[i] = temp_clk_info[i];
clks[i] = temp_clks[i];
}
kfree(temp_clk_info);
kfree(temp_clks);
ispif_dev->ahb_clk = clks;
ispif_dev->ahb_clk_info = clk_info;
ispif_dev->num_ahb_clk = num_ahb_clk;
ispif_dev->clk_info = clk_info + num_ahb_clk;
ispif_dev->clks = clks + num_ahb_clk;
ispif_dev->num_clk = non_ahb_clk;
return 0;
alloc_fail:
msm_camera_put_clk_info(pdev, &clk_info, &clks, num_clks);
return rc;
}
static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable)
@ -389,7 +375,7 @@ static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable)
int rc = 0;
rc = msm_cam_clk_enable(&ispif->pdev->dev,
ispif_ahb_clk_info, ispif->ahb_clk,
ispif->ahb_clk_info, ispif->ahb_clk,
ispif->num_ahb_clk, enable);
if (rc < 0) {
pr_err("%s: cannot enable clock, error = %d",
@ -729,7 +715,7 @@ static int msm_ispif_config(struct ispif_device *ispif,
}
if (ispif->csid_version >= CSID_VERSION_V30)
msm_ispif_select_clk_mux(ispif, intftype,
msm_ispif_select_clk_mux(ispif, intftype,
params->entries[i].csid, vfe_intf);
rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf);
@ -934,8 +920,8 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
if (rc < 0)
return -EFAULT;
rc = msm_cam_clk_enable(&ispif->pdev->dev,
ispif_clk_info, ispif->clk,
rc = msm_camera_clk_enable(&ispif->pdev->dev,
ispif->clk_info, ispif->clks,
ispif->num_clk, 1);
if (rc < 0)
goto disable_regulator;
@ -969,8 +955,8 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
}
pr_info("%s: ISPIF reset hw done, Restarting", __func__);
rc = msm_cam_clk_enable(&ispif->pdev->dev,
ispif_clk_info, ispif->clk,
rc = msm_camera_clk_enable(&ispif->pdev->dev,
ispif->clk_info, ispif->clks,
ispif->num_clk, 0);
if (rc < 0)
goto disable_regulator;
@ -1026,8 +1012,8 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
return rc;
disable_clk:
msm_cam_clk_enable(&ispif->pdev->dev,
ispif_clk_info, ispif->clk,
msm_camera_clk_enable(&ispif->pdev->dev,
ispif->clk_info, ispif->clks,
ispif->num_clk, 0);
disable_regulator:
/* Turn OFF regulators */
@ -1325,41 +1311,18 @@ static int msm_ispif_init(struct ispif_device *ispif,
ispif->csid_version = csid_version;
if (ispif->csid_version >= CSID_VERSION_V30) {
if (!ispif->clk_mux_mem || !ispif->clk_mux_io) {
pr_err("%s csi clk mux mem %p io %p\n", __func__,
ispif->clk_mux_mem, ispif->clk_mux_io);
rc = -ENOMEM;
return rc;
}
ispif->clk_mux_base = ioremap(ispif->clk_mux_mem->start,
resource_size(ispif->clk_mux_mem));
if (!ispif->clk_mux_base) {
pr_err("%s: clk_mux_mem ioremap failed\n", __func__);
rc = -ENOMEM;
return rc;
}
}
ispif->base = ioremap(ispif->mem->start,
resource_size(ispif->mem));
if (!ispif->base) {
rc = -ENOMEM;
pr_err("%s: nomem\n", __func__);
goto end;
}
rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
IRQF_TRIGGER_RISING, "ispif", ispif);
if (rc) {
pr_err("%s: request_irq error = %d\n", __func__, rc);
goto error_irq;
if (ispif->csid_version >= CSID_VERSION_V30 && !ispif->clk_mux_base) {
ispif->clk_mux_base = msm_camera_get_reg_base(ispif->pdev,
"csi_clk_mux", 1);
if (!ispif->clk_mux_base)
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__);
goto ahb_vote_fail;
return rc;
}
rc = msm_ispif_reset_hw(ispif);
@ -1367,22 +1330,15 @@ static int msm_ispif_init(struct ispif_device *ispif,
goto error_ahb;
rc = msm_ispif_reset(ispif);
if (rc == 0) {
ispif->ispif_state = ISPIF_POWER_UP;
CDBG("%s: power up done\n", __func__);
goto end;
}
if (rc)
goto error_ahb;
ispif->ispif_state = ISPIF_POWER_UP;
return 0;
error_ahb:
if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_ISPIF,
CAM_AHB_SUSPEND_VOTE) < 0)
pr_err("%s: failed to remove vote for AHB\n", __func__);
ahb_vote_fail:
free_irq(ispif->irq->start, ispif);
error_irq:
iounmap(ispif->base);
end:
return rc;
}
@ -1390,27 +1346,10 @@ static void msm_ispif_release(struct ispif_device *ispif)
{
BUG_ON(!ispif);
if (!ispif->base) {
pr_err("%s: ispif base is NULL\n", __func__);
return;
}
if (ispif->ispif_state != ISPIF_POWER_UP) {
pr_err("%s: ispif invalid state %d\n", __func__,
ispif->ispif_state);
return;
}
/* make sure no streaming going on */
msm_ispif_reset(ispif);
msm_ispif_reset_hw(ispif);
disable_irq(ispif->irq->start);
free_irq(ispif->irq->start, ispif);
iounmap(ispif->base);
iounmap(ispif->clk_mux_base);
msm_camera_enable_irq(ispif->irq, 0);
ispif->ispif_state = ISPIF_POWER_DOWN;
@ -1460,7 +1399,8 @@ static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
msm_ispif_io_dump_reg(ispif);
break;
case ISPIF_RELEASE:
msm_ispif_release(ispif);
msm_ispif_reset(ispif);
msm_ispif_reset_hw(ispif);
break;
case ISPIF_SET_VFE_INFO:
rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info);
@ -1526,15 +1466,22 @@ static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
ispif->ispif_vdd_count, 1);
if (rc)
goto unlock;
rc = msm_ispif_clk_ahb_enable(ispif, 1);
if (rc) {
msm_ispif_set_regulators(ispif->ispif_vdd,
ispif->ispif_vdd_count, 0);
goto unlock;
}
if (rc)
goto ahb_clk_enable_fail;
rc = msm_camera_enable_irq(ispif->irq, 1);
if (rc)
goto irq_enable_fail;
}
/* mem remap is done in init when the clock is on */
ispif->open_cnt++;
mutex_unlock(&ispif->mutex);
return rc;
ahb_clk_enable_fail:
msm_ispif_set_regulators(ispif->ispif_vdd, ispif->ispif_vdd_count, 0);
irq_enable_fail:
msm_ispif_clk_ahb_enable(ispif, 0);
unlock:
mutex_unlock(&ispif->mutex);
return rc;
@ -1606,46 +1553,35 @@ static int ispif_probe(struct platform_device *pdev)
rc = msm_ispif_get_regulator_info(ispif, pdev);
if (rc < 0)
return -EFAULT;
goto regulator_fail;
rc = msm_ispif_get_clk_info(ispif, pdev,
ispif_ahb_clk_info, ispif_clk_info);
rc = msm_ispif_get_clk_info(ispif, pdev);
if (rc < 0) {
pr_err("%s: msm_isp_get_clk_info() failed", __func__);
return -EFAULT;
rc = -EFAULT;
goto get_clk_fail;
}
mutex_init(&ispif->mutex);
ispif->mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "ispif");
if (!ispif->mem) {
pr_err("%s: no mem resource?\n", __func__);
rc = -ENODEV;
goto error;
ispif->base = msm_camera_get_reg_base(pdev, "ispif", 1);
if (!ispif->base) {
rc = -ENOMEM;
goto reg_base_fail;
}
ispif->irq = platform_get_resource_byname(pdev,
IORESOURCE_IRQ, "ispif");
ispif->irq = msm_camera_get_irq(pdev, "ispif");
if (!ispif->irq) {
pr_err("%s: no irq resource?\n", __func__);
rc = -ENODEV;
goto error;
goto get_irq_fail;
}
ispif->io = request_mem_region(ispif->mem->start,
resource_size(ispif->mem), pdev->name);
if (!ispif->io) {
pr_err("%s: no valid mem region\n", __func__);
rc = -EBUSY;
goto error;
}
ispif->clk_mux_mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "csi_clk_mux");
if (ispif->clk_mux_mem) {
ispif->clk_mux_io = request_mem_region(
ispif->clk_mux_mem->start,
resource_size(ispif->clk_mux_mem),
ispif->clk_mux_mem->name);
if (!ispif->clk_mux_io)
pr_err("%s: no valid csi_mux region\n", __func__);
rc = msm_camera_register_irq(pdev, ispif->irq, msm_io_ispif_irq,
IRQF_TRIGGER_RISING, "ispif", ispif);
if (rc) {
rc = -ENODEV;
goto get_irq_fail;
}
rc = msm_camera_enable_irq(ispif->irq, 0);
if (rc)
goto sd_reg_fail;
ispif->pdev = pdev;
@ -1667,7 +1603,7 @@ static int ispif_probe(struct platform_device *pdev)
rc = msm_sd_register(&ispif->msm_sd);
if (rc) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
goto error;
goto sd_reg_fail;
}
msm_cam_copy_v4l2_subdev_fops(&msm_ispif_v4l2_subdev_fops);
msm_ispif_v4l2_subdev_fops.unlocked_ioctl =
@ -1684,8 +1620,17 @@ static int ispif_probe(struct platform_device *pdev)
atomic_set(&ispif->reset_trig[VFE1], 0);
return 0;
error:
sd_reg_fail:
msm_camera_unregister_irq(pdev, ispif->irq, ispif);
get_irq_fail:
msm_camera_put_reg_base(pdev, ispif->base, "ispif", 1);
reg_base_fail:
msm_camera_put_clk_info(pdev, &ispif->ahb_clk_info,
&ispif->ahb_clk,
ispif->num_ahb_clk + ispif->num_clk);
get_clk_fail:
msm_ispif_put_regulator(ispif);
regulator_fail:
mutex_destroy(&ispif->mutex);
kfree(ispif);
return rc;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2016, 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
@ -47,11 +47,7 @@ struct ispif_intf_cmd {
struct ispif_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
struct resource *mem;
struct resource *clk_mux_mem;
struct resource *irq;
struct resource *io;
struct resource *clk_mux_io;
void __iomem *base;
void __iomem *clk_mux_base;
struct mutex mutex;
@ -63,8 +59,10 @@ struct ispif_device {
struct ispif_intf_cmd applied_intf_cmd[VFE_MAX];
enum msm_ispif_state_t ispif_state;
struct msm_ispif_vfe_info vfe_info;
struct clk *ahb_clk[ISPIF_CLK_INFO_MAX];
struct clk *clk[ISPIF_CLK_INFO_MAX];
struct clk **ahb_clk;
struct msm_cam_clk_info *ahb_clk_info;
struct clk **clks;
struct msm_cam_clk_info *clk_info;
struct completion reset_complete[VFE_MAX];
atomic_t reset_trig[VFE_MAX];
uint32_t hw_num_isps;