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

Commit f8dc33a3 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: cam: camera: Add camera core interface" into msm-4.9

parents b951f3d1 076a309e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2,4 +2,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr

obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
+3 −0
Original line number Diff line number Diff line
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr

obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_node.o cam_subdev.o
+361 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, 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/slab.h>
#include <linux/uaccess.h>
#include "cam_context.h"

static int cam_context_handle_hw_event(void *context, uint32_t evt_id,
	void *evt_data)
{
	int rc = 0;
	struct cam_context *ctx = (struct cam_context *)context;

	if (!ctx || !ctx->state_machine) {
		pr_err("%s: Context is not ready.\n", __func__);
		return -EINVAL;
	}

	if (ctx->state_machine[ctx->state].irq_ops)
		rc = ctx->state_machine[ctx->state].irq_ops(ctx, evt_id,
			evt_data);
	else
		pr_debug("%s: No function to handle event %d in dev %d, state %d\n",
				__func__, evt_id, ctx->dev_hdl, ctx->state);
	return rc;
}

int cam_context_handle_get_dev_info(struct cam_context *ctx,
	struct cam_req_mgr_device_info *info)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready.\n'", __func__);
		return -EINVAL;
	}

	if (!info) {
		pr_err("%s: Invalid get device info payload.\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].crm_ops.get_dev_info) {
		rc = ctx->state_machine[ctx->state].crm_ops.get_dev_info(
			ctx, info);
	} else {
		pr_err("%s: No get device info in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_link(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *link)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready.\n", __func__);
		return -EINVAL;
	}

	if (!link) {
		pr_err("%s: Invalid link payload.\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].crm_ops.link) {
		rc = ctx->state_machine[ctx->state].crm_ops.link(ctx, link);
	} else {
		pr_err("%s: No crm link in dev %d, state %d\n", __func__,
			ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_unlink(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *unlink)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready!\n", __func__);
		return -EINVAL;
	}

	if (!unlink) {
		pr_err("%s: Invalid unlink payload.\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].crm_ops.unlink) {
		rc = ctx->state_machine[ctx->state].crm_ops.unlink(
			ctx, unlink);
	} else {
		pr_err("%s: No crm unlink in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_apply_req(struct cam_context *ctx,
	struct cam_req_mgr_apply_request *apply)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready.\n'", __func__);
		return -EINVAL;
	}

	if (!apply) {
		pr_err("%s: Invalid apply request payload.\n'", __func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].crm_ops.apply_req) {
		rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx,
			apply);
	} else {
		pr_err("%s: No crm apply req in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}


int cam_context_handle_acquire_dev(struct cam_context *ctx,
	struct cam_acquire_dev_cmd *cmd)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready.\n", __func__);
		return -EINVAL;
	}

	if (!cmd) {
		pr_err("%s: Invalid acquire device command payload.\n",
			__func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].ioctl_ops.acquire_dev) {
		rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_dev(
			ctx, cmd);
	} else {
		pr_err("%s: No acquire device in dev %d, state %d\n",
			__func__, cmd->dev_handle, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_release_dev(struct cam_context *ctx,
	struct cam_release_dev_cmd *cmd)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready.\n", __func__);
		return -EINVAL;
	}

	if (!cmd) {
		pr_err("%s: Invalid release device command payload.\n",
			__func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) {
		rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev(
			ctx, cmd);
	} else {
		pr_err("%s: No release device in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_config_dev(struct cam_context *ctx,
	struct cam_config_dev_cmd *cmd)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: context is not ready\n'", __func__);
		return -EINVAL;
	}

	if (!cmd) {
		pr_err("%s: Invalid config device command payload.\n",
			__func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].ioctl_ops.config_dev) {
		rc = ctx->state_machine[ctx->state].ioctl_ops.config_dev(
			ctx, cmd);
	} else {
		pr_err("%s: No config device in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_start_dev(struct cam_context *ctx,
	struct cam_start_stop_dev_cmd *cmd)
{
	int rc = 0;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready.\n", __func__);
		return -EINVAL;
	}

	if (!cmd) {
		pr_err("%s: Invalid start device command payload.\n",
			__func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].ioctl_ops.start_dev)
		rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev(
			ctx, cmd);
	else
		/* start device can be optional for some driver */
		pr_debug("%s: No start device in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);

	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_stop_dev(struct cam_context *ctx,
	struct cam_start_stop_dev_cmd *cmd)
{
	int rc = 0;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready.\n'", __func__);
		return -EINVAL;
	}

	if (!cmd) {
		pr_err("%s: Invalid stop device command payload.\n",
			__func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev)
		rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev(
			ctx, cmd);
	else
		/* stop device can be optional for some driver */
		pr_warn("%s: No stop device in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_init(struct cam_context *ctx,
	struct cam_req_mgr_kmd_ops *crm_node_intf,
	struct cam_hw_mgr_intf *hw_mgr_intf,
	struct cam_ctx_request *req_list,
	uint32_t req_size)
{
	int i;

	/* crm_node_intf is optinal */
	if (!ctx || !hw_mgr_intf || !req_list) {
		pr_err("%s: Invalid input parameters\n", __func__);
		return -EINVAL;
	}

	memset(ctx, 0, sizeof(*ctx));

	INIT_LIST_HEAD(&ctx->list);
	mutex_init(&ctx->ctx_mutex);
	spin_lock_init(&ctx->lock);

	ctx->ctx_crm_intf = NULL;
	ctx->crm_ctx_intf = crm_node_intf;
	ctx->hw_mgr_intf = hw_mgr_intf;
	ctx->irq_cb_intf = cam_context_handle_hw_event;

	INIT_LIST_HEAD(&ctx->active_req_list);
	INIT_LIST_HEAD(&ctx->wait_req_list);
	INIT_LIST_HEAD(&ctx->pending_req_list);
	INIT_LIST_HEAD(&ctx->free_req_list);
	ctx->req_list = req_list;
	ctx->req_size = req_size;
	for (i = 0; i < req_size; i++) {
		INIT_LIST_HEAD(&ctx->req_list[i].list);
		list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list);
	}
	ctx->state = CAM_CTX_AVAILABLE;
	ctx->state_machine = NULL;
	ctx->ctx_priv = NULL;

	return 0;
}

int cam_context_deinit(struct cam_context *ctx)
{
	if (!ctx)
		return -EINVAL;

	/**
	 * This is called from platform device remove.
	 * Everyting should be released at this moment.
	 * so we just free the memory for the context
	 */
	if (ctx->state != CAM_CTX_AVAILABLE)
		pr_err("%s: Device did not shutdown cleanly.\n", __func__);

	memset(ctx, 0, sizeof(*ctx));

	return 0;
}
+302 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, 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 _CAM_CONTEXT_H_
#define _CAM_CONTEXT_H_

#include <linux/spinlock.h>
#include "cam_req_mgr_interface.h"
#include "cam_hw_mgr_intf.h"

/* Forward declarations */
struct cam_context;

/* max request number */
#define CAM_CTX_REQ_MAX              20

/**
 * enum cam_ctx_state -  context top level states
 *
 */
enum cam_context_state {
	CAM_CTX_UNINIT               = 0,
	CAM_CTX_AVAILABLE            = 1,
	CAM_CTX_ACQUIRED             = 2,
	CAM_CTX_READY                = 3,
	CAM_CTX_ACTIVATED            = 4,
	CAM_CTX_STATE_MAX            = 5,
};

/**
 * struct cam_ctx_request - Common request structure for the context
 *
 * @list:                  Link list entry
 * @status:                Request status
 * @request_id:            Request id
 * @req_priv:              Derived request object
 *
 */
struct cam_ctx_request {
	struct list_head   list;
	uint32_t           status;
	uint64_t           request_id;
	void              *req_priv;
};

/**
 * struct cam_ctx_ioctl_ops - Function table for handling IOCTL calls
 *
 * @acquire_dev:           Function pointer for acquire device
 * @release_dev:           Function pointer for release device
 * @config_dev:            Function pointer for config device
 * @start_dev:             Function pointer for start device
 * @stop_dev:              Function pointer for stop device
 *
 */
struct cam_ctx_ioctl_ops {
	int (*acquire_dev)(struct cam_context *ctx,
			struct cam_acquire_dev_cmd *cmd);
	int (*release_dev)(struct cam_context *ctx,
			struct cam_release_dev_cmd *cmd);
	int (*config_dev)(struct cam_context *ctx,
			struct cam_config_dev_cmd *cmd);
	int (*start_dev)(struct cam_context *ctx,
			struct cam_start_stop_dev_cmd *cmd);
	int (*stop_dev)(struct cam_context *ctx,
			struct cam_start_stop_dev_cmd *cmd);
};

/**
 * struct cam_ctx_crm_ops -  Function table for handling CRM to context calls
 *
 * @get_dev_info:          Get device informaiton
 * @link:                  Link the context
 * @unlink:                Unlink the context
 * @apply_req:             Apply setting for the context
 *
 */
struct cam_ctx_crm_ops {
	int (*get_dev_info)(struct cam_context *ctx,
			struct cam_req_mgr_device_info *);
	int (*link)(struct cam_context *ctx,
			struct cam_req_mgr_core_dev_link_setup *link);
	int (*unlink)(struct cam_context *ctx,
			struct cam_req_mgr_core_dev_link_setup *unlink);
	int (*apply_req)(struct cam_context *ctx,
			struct cam_req_mgr_apply_request *apply);
};


/**
 * struct cam_ctx_ops - Collection of the interface funciton tables
 *
 * @ioctl_ops:             Ioctl funciton table
 * @crm_ops:               CRM to context interface function table
 * @irq_ops:               Hardware event handle function
 *
 */
struct cam_ctx_ops {
	struct cam_ctx_ioctl_ops     ioctl_ops;
	struct cam_ctx_crm_ops       crm_ops;
	cam_hw_event_cb_func         irq_ops;
};

/**
 * struct cam_context - camera context object for the subdevice node
 *
 * @list:                  Link list entry
 * @sessoin_hdl:           Session handle
 * @dev_hdl:               Device handle
 * @link_hdl:              Link handle
 * @ctx_mutex:             Mutex for ioctl calls
 * @lock:                  Spin lock
 * @active_req_list:       Requests pending for done event
 * @pending_req_list:      Requests pending for reg upd event
 * @wait_req_list:         Requests waiting for apply
 * @free_req_list:         Requests that are free
 * @req_list:              Reference to the request storage
 * @req_size:              Size of the request storage
 * @hw_mgr_intf:           Context to HW interface
 * @ctx_crm_intf:          Context to CRM interface
 * @crm_ctx_intf:          CRM to context interface
 * @irq_cb_intf:           HW to context callback interface
 * @state:                 Current state for top level state machine
 * @state_machine:         Top level state machine
 * @ctx_priv:              Private context pointer
 *
 */
struct cam_context {
	struct list_head             list;
	int32_t                      session_hdl;
	int32_t                      dev_hdl;
	int32_t                      link_hdl;

	struct mutex                 ctx_mutex;
	spinlock_t                   lock;

	struct list_head             active_req_list;
	struct list_head             pending_req_list;
	struct list_head             wait_req_list;
	struct list_head             free_req_list;
	struct cam_ctx_request      *req_list;
	uint32_t                     req_size;

	struct cam_hw_mgr_intf      *hw_mgr_intf;
	struct cam_req_mgr_crm_cb   *ctx_crm_intf;
	struct cam_req_mgr_kmd_ops  *crm_ctx_intf;
	cam_hw_event_cb_func         irq_cb_intf;

	enum cam_context_state       state;
	struct cam_ctx_ops          *state_machine;

	void                        *ctx_priv;
};

/**
 * cam_context_handle_get_dev_info()
 *
 * @brief:        Handle get device information command
 *
 * @ctx:                   Object pointer for cam_context
 * @info:                  Device information returned
 *
 */
int cam_context_handle_get_dev_info(struct cam_context *ctx,
		struct cam_req_mgr_device_info *info);

/**
 * cam_context_handle_link()
 *
 * @brief:        Handle link command
 *
 * @ctx:                   Object pointer for cam_context
 * @link:                  Link command payload
 *
 */
int cam_context_handle_link(struct cam_context *ctx,
		struct cam_req_mgr_core_dev_link_setup *link);

/**
 * cam_context_handle_unlink()
 *
 * @brief:        Handle unlink command
 *
 * @ctx:                   Object pointer for cam_context
 * @unlink:                Unlink command payload
 *
 */
int cam_context_handle_unlink(struct cam_context *ctx,
		struct cam_req_mgr_core_dev_link_setup *unlink);

/**
 * cam_context_handle_apply_req()
 *
 * @brief:        Handle apply request command
 *
 * @ctx:                   Object pointer for cam_context
 * @apply:                 Apply request command payload
 *
 */
int cam_context_handle_apply_req(struct cam_context *ctx,
		struct cam_req_mgr_apply_request *apply);


/**
 * cam_context_handle_acquire_dev()
 *
 * @brief:        Handle acquire device command
 *
 * @ctx:                   Object pointer for cam_context
 * @cmd:                   Acquire device command payload
 *
 */
int cam_context_handle_acquire_dev(struct cam_context *ctx,
		struct cam_acquire_dev_cmd *cmd);

/**
 * cam_context_handle_release_dev()
 *
 * @brief:        Handle release device command
 *
 * @ctx:                   Object pointer for cam_context
 * @cmd:                   Release device command payload
 *
 */
int cam_context_handle_release_dev(struct cam_context *ctx,
		struct cam_release_dev_cmd *cmd);

/**
 * cam_context_handle_config_dev()
 *
 * @brief:        Handle config device command
 *
 * @ctx:                   Object pointer for cam_context
 * @cmd:                   Config device command payload
 *
 */
int cam_context_handle_config_dev(struct cam_context *ctx,
		struct cam_config_dev_cmd *cmd);

/**
 * cam_context_handle_start_dev()
 *
 * @brief:        Handle start device command
 *
 * @ctx:                   Object pointer for cam_context
 * @cmd:                   Start device command payload
 *
 */
int cam_context_handle_start_dev(struct cam_context *ctx,
		struct cam_start_stop_dev_cmd *cmd);

/**
 * cam_context_handle_stop_dev()
 *
 * @brief:        Handle stop device command
 *
 * @ctx:                   Object pointer for cam_context
 * @cmd:                   Stop device command payload
 *
 */
int cam_context_handle_stop_dev(struct cam_context *ctx,
		struct cam_start_stop_dev_cmd *cmd);

/**
 * cam_context_deinit()
 *
 * @brief:        Camera context deinitialize function
 *
 * @ctx:                   Object pointer for cam_context
 *
 */
int cam_context_deinit(struct cam_context *ctx);

/**
 * cam_context_init()
 *
 * @brief:        Camera context initialize function
 *
 * @ctx:                   Object pointer for cam_context
 * @crm_node_intf:         Function table for crm to context interface
 * @hw_mgr_intf:           Function table for context to hw interface
 * @req_list:              Requests storage
 * @req_size:              Size of the request storage
 *
 */
int cam_context_init(struct cam_context *ctx,
		struct cam_req_mgr_kmd_ops *crm_node_intf,
		struct cam_hw_mgr_intf *hw_mgr_intf,
		struct cam_ctx_request *req_list,
		uint32_t req_size);


#endif  /* _CAM_CONTEXT_H_ */
+53 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, 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 _CAM_HW_H_
#define _CAM_HW_H_

#include "cam_soc_util.h"

/*
 * This file declares Enums, Structures and APIs to be used as template
 * when writing any HW driver in the camera subsystem.
 */

/* Hardware state enum */
enum cam_hw_state {
	CAM_HW_STATE_POWER_DOWN,
	CAM_HW_STATE_POWER_UP,
};

/**
 * struct cam_hw_info - Common hardware information
 *
 * @hw_mutex:              Hardware mutex
 * @hw_lock:               Hardware spinlock
 * @hw_complete:           Hardware Completion
 * @open_count:            Count to track the HW enable from the client
 * @hw_state:              Hardware state
 * @soc_info:              Platform SOC properties for hardware
 * @node_info:             Private HW data related to nodes
 * @core_info:             Private HW data related to core logic
 *
 */
struct cam_hw_info {
	struct mutex                    hw_mutex;
	spinlock_t                      hw_lock;
	struct completion               hw_complete;
	uint32_t                        open_count;
	enum cam_hw_state               hw_state;
	struct cam_hw_soc_info          soc_info;
	void                           *node_info;
	void                           *core_info;
};

#endif /* _CAM_HW_H_ */
Loading