Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57c62991 authored by Jeyaprakash Soundrapandian's avatar Jeyaprakash Soundrapandian Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: cpas: Turn off clocks only after IRQs are handled" into dev/msm-4.9-camx

parents d7a27d8c ade07e51
Loading
Loading
Loading
Loading
+34 −4
Original line number Diff line number Diff line
@@ -903,9 +903,11 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
		goto done;

	if (cpas_core->streamon_clients == 0) {
		atomic_set(&cpas_core->irq_count, 1);
		rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info,
			applied_level);
		if (rc) {
			atomic_set(&cpas_core->irq_count, 0);
			CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc);
			goto done;
		}
@@ -913,14 +915,17 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
		if (cpas_core->internal_ops.power_on) {
			rc = cpas_core->internal_ops.power_on(cpas_hw);
			if (rc) {
				atomic_set(&cpas_core->irq_count, 0);
				cam_cpas_soc_disable_resources(
					&cpas_hw->soc_info);
					&cpas_hw->soc_info, true, true);
				CAM_ERR(CAM_CPAS,
					"failed in power_on settings rc=%d",
					rc);
				goto done;
			}
		}
		CAM_DBG(CAM_CPAS, "irq_count=%d\n",
			atomic_read(&cpas_core->irq_count));
		cpas_hw->hw_state = CAM_HW_STATE_POWER_UP;
	}

@@ -935,6 +940,10 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
	return rc;
}

static int _check_irq_count(struct cam_cpas *cpas_core)
{
	return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1;
}

static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
	uint32_t arg_size)
@@ -947,6 +956,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
	struct cam_ahb_vote ahb_vote;
	struct cam_axi_vote axi_vote;
	int rc = 0;
	long result;

	if (!hw_priv || !stop_args) {
		CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
@@ -995,11 +1005,29 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
			}
		}

		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
		rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info);
		if (rc) {
			CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc);
			goto done;
		}

		/* Wait for any IRQs still being handled */
		atomic_dec(&cpas_core->irq_count);
		result = wait_event_timeout(cpas_core->irq_count_wq,
			_check_irq_count(cpas_core), HZ);
		if (result == 0) {
			CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d",
				atomic_read(&cpas_core->irq_count));
		}

		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info,
			true, false);
		if (rc) {
			CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc);
			goto done;
		}
		CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n",
			atomic_read(&cpas_core->irq_count));
		cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
	}

@@ -1450,6 +1478,8 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
	soc_private = (struct cam_cpas_private_soc *)
		cpas_hw->soc_info.soc_private;
	cpas_core->num_clients = soc_private->num_clients;
	atomic_set(&cpas_core->irq_count, 0);
	init_waitqueue_head(&cpas_core->irq_count_wq);

	if (internal_ops->setup_regbase) {
		rc = internal_ops->setup_regbase(&cpas_hw->soc_info,
@@ -1505,7 +1535,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
	if (rc)
		goto disable_soc_res;

	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
	if (rc) {
		CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc);
		goto remove_default_vote;
@@ -1523,7 +1553,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
	return 0;

disable_soc_res:
	cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
	cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
remove_default_vote:
	cam_cpas_util_vote_default_ahb_axi(cpas_hw, false);
axi_cleanup:
+3 −1
Original line number Diff line number Diff line
/* 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
@@ -187,6 +187,8 @@ struct cam_cpas {
	struct list_head axi_ports_list_head;
	struct cam_cpas_internal_ops internal_ops;
	struct workqueue_struct *work_queue;
	atomic_t irq_count;
	wait_queue_head_t irq_count_wq;
};

int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);
+16 −3
Original line number Diff line number Diff line
/* 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
@@ -209,13 +209,26 @@ int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info,
	return rc;
}

int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info)
int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info,
	bool disable_clocks, bool disble_irq)
{
	int rc = 0;

	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
	rc = cam_soc_util_disable_platform_resource(soc_info,
		disable_clocks, disble_irq);
	if (rc)
		CAM_ERR(CAM_CPAS, "disable platform failed, rc=%d", rc);

	return rc;
}

int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info)
{
	int rc = 0;

	rc = cam_soc_util_irq_disable(soc_info);
	if (rc)
		CAM_ERR(CAM_CPAS, "disable irq failed, rc=%d", rc);

	return rc;
}
+4 −2
Original line number Diff line number Diff line
/* 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
@@ -61,5 +61,7 @@ int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info);
int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info,
	enum cam_vote_level default_level);
int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info);
int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info,
	bool disable_clocks, bool disble_irq);
int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info);
#endif /* _CAM_CPAS_SOC_H_ */
+18 −2
Original line number Diff line number Diff line
/* 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
@@ -354,6 +354,11 @@ static void cam_cpastop_work(struct work_struct *work)
	cpas_core = (struct cam_cpas *) cpas_hw->core_info;
	soc_info = &cpas_hw->soc_info;

	if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
		CAM_ERR(CAM_CPAS, "CPAS off");
		return;
	}

	for (i = 0; i < camnoc_info->irq_err_size; i++) {
		if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) &&
			(camnoc_info->irq_err[i].enable)) {
@@ -398,6 +403,9 @@ static void cam_cpastop_work(struct work_struct *work)
				~camnoc_info->irq_err[i].sbm_port;
		}
	}
	atomic_dec(&cpas_core->irq_count);
	wake_up(&cpas_core->irq_count_wq);
	CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count));

	if (payload->irq_status)
		CAM_ERR(CAM_CPAS, "IRQ not handled irq_status=0x%x",
@@ -414,9 +422,14 @@ static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
	int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
	struct cam_cpas_work_payload *payload;

	if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
		CAM_ERR(CAM_CPAS, "CPAS off");
		return IRQ_HANDLED;
	}

	payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC);
	if (!payload)
		return IRQ_HANDLED;
		goto done;

	payload->irq_status = cam_io_r_mb(
		soc_info->reg_map[camnoc_index].mem_base +
@@ -433,6 +446,9 @@ static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
	cam_cpastop_reset_irq(cpas_hw);

	queue_work(cpas_core->work_queue, &payload->work);
done:
	atomic_dec(&cpas_core->irq_count);
	wake_up(&cpas_core->irq_count_wq);

	return IRQ_HANDLED;
}