
Due to the asynchronous nature of platform probes, inter dependency between drivers needs to be taken care during kernel boot up. Component helper provides the facility of adding matching drivers in a list ordered in the way we want to bind those drivers. The CRM driver acts as component master to make sure all slave drivers are bound before it returns from its own bind call. Add support for serializing platform probes through component framework. CRs-Fixed: 2584631 Change-Id: I345da1d2b9cccf6021ac6fc899143013b7714ec4 Signed-off-by: Mukund Madhusudan Atre <matre@codeaurora.org>
400 lines
9.7 KiB
C
400 lines
9.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/build_bug.h>
|
|
|
|
#include "cam_req_mgr_dev.h"
|
|
#include "cam_sync_api.h"
|
|
#include "cam_smmu_api.h"
|
|
#include "cam_cpas_hw_intf.h"
|
|
#include "cam_cdm_intf_api.h"
|
|
|
|
#include "cam_ife_csid_dev.h"
|
|
#include "cam_vfe.h"
|
|
#include "cam_isp_dev.h"
|
|
|
|
#include "cam_res_mgr_api.h"
|
|
#include "cam_cci_dev.h"
|
|
#include "cam_sensor_dev.h"
|
|
#include "cam_actuator_dev.h"
|
|
#include "cam_csiphy_dev.h"
|
|
#include "cam_eeprom_dev.h"
|
|
#include "cam_ois_dev.h"
|
|
|
|
#if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2)
|
|
#include "cam_flash_dev.h"
|
|
#endif
|
|
|
|
#include "a5_core.h"
|
|
#include "ipe_core.h"
|
|
#include "bps_core.h"
|
|
#include "cam_icp_subdev.h"
|
|
|
|
#include "jpeg_dma_core.h"
|
|
#include "jpeg_enc_core.h"
|
|
#include "cam_jpeg_dev.h"
|
|
|
|
#include "cam_fd_hw_intf.h"
|
|
#include "cam_fd_dev.h"
|
|
|
|
#include "cam_lrme_hw_intf.h"
|
|
#include "cam_lrme_dev.h"
|
|
|
|
#include "cam_custom_dev.h"
|
|
#include "cam_custom_csid_dev.h"
|
|
#include "cam_custom_sub_mod_dev.h"
|
|
|
|
#include "cam_debug_util.h"
|
|
|
|
#include "ope_dev_intf.h"
|
|
|
|
#include "cam_top_tpg_v1.h"
|
|
#include "cam_tfe_dev.h"
|
|
#include "cam_tfe_csid530.h"
|
|
#include "camera_main.h"
|
|
|
|
struct camera_submodule_component {
|
|
int (*init)(void);
|
|
void (*exit)(void);
|
|
};
|
|
|
|
struct camera_submodule {
|
|
char *name;
|
|
uint num_component;
|
|
const struct camera_submodule_component *component;
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_base[] = {
|
|
{&cam_req_mgr_init, &cam_req_mgr_exit},
|
|
{&cam_sync_init, &cam_sync_exit},
|
|
{&cam_smmu_init_module, &cam_smmu_exit_module},
|
|
{&cam_cpas_dev_init_module, &cam_cpas_dev_exit_module},
|
|
{&cam_cdm_intf_init_module, &cam_cdm_intf_exit_module},
|
|
{&cam_hw_cdm_init_module, &cam_hw_cdm_exit_module},
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_isp[] = {
|
|
#ifdef CONFIG_SPECTRA_ISP
|
|
{&cam_ife_csid17x_init_module, &cam_ife_csid17x_exit_module},
|
|
{&cam_ife_csid_lite_init_module, &cam_ife_csid_lite_exit_module},
|
|
{&cam_vfe_init_module, &cam_vfe_exit_module},
|
|
{&cam_isp_dev_init_module, &cam_isp_dev_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_tfe[] = {
|
|
#if IS_ENABLED(CONFIG_SPECTRA_TFE)
|
|
{&cam_top_tpg_v1_init_module, &cam_top_tpg_v1_exit_module},
|
|
{&cam_tfe_init_module, &cam_tfe_exit_module},
|
|
{&cam_tfe_csid530_init_module, &cam_tfe_csid530_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_sensor[] = {
|
|
#ifdef CONFIG_SPECTRA_SENSOR
|
|
{&cam_res_mgr_init, &cam_res_mgr_exit},
|
|
{&cam_cci_init_module, &cam_cci_exit_module},
|
|
{&cam_csiphy_init_module, &cam_csiphy_exit_module},
|
|
{&cam_actuator_driver_init, &cam_actuator_driver_exit},
|
|
{&cam_sensor_driver_init, &cam_sensor_driver_exit},
|
|
{&cam_eeprom_driver_init, &cam_eeprom_driver_exit},
|
|
{&cam_ois_driver_init, &cam_ois_driver_exit},
|
|
#if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2)
|
|
{&cam_flash_init_module, &cam_flash_exit_module},
|
|
#endif
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_icp[] = {
|
|
#ifdef CONFIG_SPECTRA_ICP
|
|
{&cam_a5_init_module, &cam_a5_exit_module},
|
|
{&cam_ipe_init_module, &cam_ipe_exit_module},
|
|
{&cam_bps_init_module, &cam_bps_exit_module},
|
|
{&cam_icp_init_module, &cam_icp_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_ope[] = {
|
|
#ifdef CONFIG_SPECTRA_OPE
|
|
{&cam_ope_init_module, &cam_ope_exit_module},
|
|
{&cam_ope_subdev_init_module, &cam_ope_subdev_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_jpeg[] = {
|
|
#ifdef CONFIG_SPECTRA_JPEG
|
|
{&cam_jpeg_enc_init_module, &cam_jpeg_enc_exit_module},
|
|
{&cam_jpeg_dma_init_module, &cam_jpeg_dma_exit_module},
|
|
{&cam_jpeg_dev_init_module, &cam_jpeg_dev_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_fd[] = {
|
|
#ifdef CONFIG_SPECTRA_FD
|
|
{&cam_fd_hw_init_module, &cam_fd_hw_exit_module},
|
|
{&cam_fd_dev_init_module, &cam_fd_dev_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_lrme[] = {
|
|
#ifdef CONFIG_SPECTRA_LRME
|
|
{&cam_lrme_hw_init_module, &cam_lrme_hw_exit_module},
|
|
{&cam_lrme_dev_init_module, &cam_lrme_dev_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule_component camera_custom[] = {
|
|
#ifdef CONFIG_SPECTRA_CUSTOM
|
|
{&cam_custom_hw_sub_module_init, &cam_custom_hw_sub_module_exit},
|
|
{&cam_custom_csid_driver_init, &cam_custom_csid_driver_exit},
|
|
{&cam_custom_dev_init_module, &cam_custom_dev_exit_module},
|
|
#endif
|
|
};
|
|
|
|
static const struct camera_submodule submodule_table[] = {
|
|
{
|
|
.name = "Camera BASE",
|
|
.num_component = ARRAY_SIZE(camera_base),
|
|
.component = camera_base,
|
|
},
|
|
{
|
|
.name = "Camera ISP",
|
|
.num_component = ARRAY_SIZE(camera_isp),
|
|
.component = camera_isp,
|
|
},
|
|
{
|
|
.name = "Camera TFE",
|
|
.num_component = ARRAY_SIZE(camera_tfe),
|
|
.component = camera_tfe,
|
|
},
|
|
{
|
|
.name = "Camera SENSOR",
|
|
.num_component = ARRAY_SIZE(camera_sensor),
|
|
.component = camera_sensor
|
|
},
|
|
{
|
|
.name = "Camera ICP",
|
|
.num_component = ARRAY_SIZE(camera_icp),
|
|
.component = camera_icp,
|
|
},
|
|
{
|
|
.name = "Camera OPE",
|
|
.num_component = ARRAY_SIZE(camera_ope),
|
|
.component = camera_ope,
|
|
},
|
|
{
|
|
.name = "Camera JPEG",
|
|
.num_component = ARRAY_SIZE(camera_jpeg),
|
|
.component = camera_jpeg,
|
|
},
|
|
{
|
|
.name = "Camera FD",
|
|
.num_component = ARRAY_SIZE(camera_fd),
|
|
.component = camera_fd,
|
|
},
|
|
{
|
|
.name = "Camera LRME",
|
|
.num_component = ARRAY_SIZE(camera_lrme),
|
|
.component = camera_lrme,
|
|
},
|
|
{
|
|
.name = "Camera CUSTOM",
|
|
.num_component = ARRAY_SIZE(camera_custom),
|
|
.component = camera_custom,
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Drivers to be bound by component framework in this order with
|
|
* CRM as master
|
|
*/
|
|
static struct platform_driver *const cam_component_drivers[] = {
|
|
/* BASE */
|
|
&cam_sync_driver,
|
|
&cam_smmu_driver,
|
|
&cam_cpas_driver,
|
|
&cam_cdm_intf_driver,
|
|
&cam_hw_cdm_driver,
|
|
#ifdef CONFIG_SPECTRA_ISP
|
|
&cam_ife_csid17x_driver,
|
|
&cam_ife_csid_lite_driver,
|
|
&cam_vfe_driver,
|
|
&isp_driver,
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_TFE
|
|
&cam_top_tpg_v1_driver,
|
|
&cam_tfe_driver,
|
|
&cam_tfe_csid530_driver,
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_SENSOR
|
|
&cam_res_mgr_driver,
|
|
&cci_driver,
|
|
&csiphy_driver,
|
|
&cam_actuator_platform_driver,
|
|
&cam_sensor_platform_driver,
|
|
&cam_eeprom_platform_driver,
|
|
&cam_ois_platform_driver,
|
|
#if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2)
|
|
&cam_flash_platform_driver,
|
|
#endif
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_ICP
|
|
&cam_a5_driver,
|
|
&cam_ipe_driver,
|
|
&cam_bps_driver,
|
|
&cam_icp_driver,
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_OPE
|
|
&cam_ope_driver,
|
|
&cam_ope_subdev_driver,
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_JPEG
|
|
&cam_jpeg_enc_driver,
|
|
&cam_jpeg_dma_driver,
|
|
&jpeg_driver,
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_FD
|
|
&cam_fd_hw_driver,
|
|
&cam_fd_driver,
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_LRME
|
|
&cam_lrme_hw_driver,
|
|
&cam_lrme_driver,
|
|
#endif
|
|
#ifdef CONFIG_SPECTRA_CUSTOM
|
|
&cam_custom_hw_sub_mod_driver,
|
|
&cam_custom_csid_driver,
|
|
&custom_driver,
|
|
#endif
|
|
};
|
|
|
|
/* Callback to compare device from match list before adding as component */
|
|
static int camera_component_compare_dev(struct device *dev, void *data)
|
|
{
|
|
return dev == data;
|
|
}
|
|
|
|
/* Add component matches to list for master of aggregate driver */
|
|
int camera_component_match_add_drivers(struct device *master_dev,
|
|
struct component_match **match_list)
|
|
{
|
|
int i, rc = 0;
|
|
struct platform_device *pdev = NULL;
|
|
|
|
if (!master_dev || !match_list) {
|
|
CAM_ERR(CAM_UTIL, "Invalid parameters for component match add");
|
|
rc = -EINVAL;
|
|
goto end;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(cam_component_drivers); i++) {
|
|
struct device_driver *drv = &cam_component_drivers[i]->driver;
|
|
struct device *start_dev = NULL, *match_dev;
|
|
|
|
while ((match_dev = bus_find_device(&platform_bus_type,
|
|
start_dev, drv, (void *)platform_bus_type.match))) {
|
|
put_device(start_dev);
|
|
pdev = to_platform_device(match_dev);
|
|
CAM_DBG(CAM_UTIL, "Adding matched component:%s",
|
|
pdev->name);
|
|
component_match_add(master_dev, match_list,
|
|
camera_component_compare_dev, match_dev);
|
|
start_dev = match_dev;
|
|
}
|
|
put_device(start_dev);
|
|
}
|
|
|
|
end:
|
|
return rc;
|
|
}
|
|
|
|
static int camera_verify_submodules(void)
|
|
{
|
|
int rc = 0;
|
|
int i, j, num_components;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(submodule_table); i++) {
|
|
num_components = submodule_table[i].num_component;
|
|
for (j = 0; j < num_components; j++) {
|
|
if (!submodule_table[i].component[j].init ||
|
|
!submodule_table[i].component[j].exit) {
|
|
CAM_ERR(CAM_UTIL,
|
|
"%s module has init = %ps, exit = %ps",
|
|
submodule_table[i].name,
|
|
submodule_table[i].component[j].init,
|
|
submodule_table[i].component[j].exit);
|
|
rc = -EINVAL;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
|
|
end:
|
|
return rc;
|
|
}
|
|
|
|
static void __camera_exit(int i, int j)
|
|
{
|
|
uint num_exits;
|
|
|
|
/* Exit from current submodule */
|
|
for (j -= 1; j >= 0; j--)
|
|
submodule_table[i].component[j].exit();
|
|
|
|
/* Exit remaining submodules */
|
|
for (i -= 1; i >= 0; i--) {
|
|
num_exits = submodule_table[i].num_component;
|
|
for (j = num_exits - 1; j >= 0; j--)
|
|
submodule_table[i].component[j].exit();
|
|
}
|
|
}
|
|
|
|
static int camera_init(void)
|
|
{
|
|
int rc;
|
|
uint i, j, num_inits;
|
|
|
|
rc = camera_verify_submodules();
|
|
if (rc)
|
|
goto end_init;
|
|
|
|
/* For Probing all available submodules */
|
|
for (i = 0; i < ARRAY_SIZE(submodule_table); i++) {
|
|
num_inits = submodule_table[i].num_component;
|
|
CAM_DBG(CAM_UTIL, "Number of %s components: %u",
|
|
submodule_table[i].name, num_inits);
|
|
for (j = 0; j < num_inits; j++) {
|
|
rc = submodule_table[i].component[j].init();
|
|
if (rc) {
|
|
CAM_ERR(CAM_UTIL,
|
|
"%s module failure at %ps rc = %d",
|
|
submodule_table[i].name,
|
|
submodule_table[i].component[j].init,
|
|
rc);
|
|
__camera_exit(i, j);
|
|
goto end_init;
|
|
}
|
|
}
|
|
}
|
|
|
|
CAM_INFO(CAM_UTIL, "Spectra camera driver initialized!");
|
|
|
|
end_init:
|
|
return rc;
|
|
}
|
|
|
|
static void camera_exit(void)
|
|
{
|
|
__camera_exit(ARRAY_SIZE(submodule_table), 0);
|
|
|
|
CAM_INFO(CAM_UTIL, "Spectra camera driver exited!");
|
|
}
|
|
|
|
module_init(camera_init);
|
|
module_exit(camera_exit);
|
|
|
|
MODULE_DESCRIPTION("Spectra camera driver");
|
|
MODULE_LICENSE("GPL v2");
|