blob: 1a4e14525bc30253e6de3c679e6de2259ee9c554 [file] [log] [blame]
/* Copyright (c) 2019, 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/mod_devicetable.h>
#include <linux/of_device.h>
#include "cam_isp_hw.h"
#include "cam_hw_intf.h"
#include "cam_csid_ppi_core.h"
#include "cam_csid_ppi_dev.h"
#include "cam_debug_util.h"
static struct cam_hw_intf *cam_csid_ppi_hw_list[CAM_CSID_PPI_HW_MAX] = {
0, 0, 0, 0};
static char ppi_dev_name[8];
int cam_csid_ppi_probe(struct platform_device *pdev)
{
struct cam_hw_intf *ppi_hw_intf;
struct cam_hw_info *ppi_hw_info;
struct cam_csid_ppi_hw *ppi_dev = NULL;
const struct of_device_id *match_dev = NULL;
struct cam_csid_ppi_hw_info *ppi_hw_data = NULL;
uint32_t ppi_dev_idx;
int rc = 0;
CAM_DBG(CAM_ISP, "PPI probe called");
ppi_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
if (!ppi_hw_intf) {
rc = -ENOMEM;
goto err;
}
ppi_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
if (!ppi_hw_info) {
rc = -ENOMEM;
goto free_hw_intf;
}
ppi_dev = kzalloc(sizeof(struct cam_csid_ppi_hw), GFP_KERNEL);
if (!ppi_dev) {
rc = -ENOMEM;
goto free_hw_info;
}
/* get csid ppi hw index */
of_property_read_u32(pdev->dev.of_node, "cell-index", &ppi_dev_idx);
/* get csid ppi hw information */
match_dev = of_match_device(pdev->dev.driver->of_match_table,
&pdev->dev);
if (!match_dev) {
CAM_ERR(CAM_ISP, "No matching table for the CSID PPI HW!");
rc = -EINVAL;
goto free_dev;
}
memset(ppi_dev_name, 0, sizeof(ppi_dev_name));
snprintf(ppi_dev_name, sizeof(ppi_dev_name), "ppi%1u", ppi_dev_idx);
ppi_hw_intf->hw_idx = ppi_dev_idx;
ppi_hw_intf->hw_priv = ppi_hw_info;
ppi_hw_info->core_info = ppi_dev;
ppi_hw_info->soc_info.pdev = pdev;
ppi_hw_info->soc_info.dev = &pdev->dev;
ppi_hw_info->soc_info.dev_name = ppi_dev_name;
ppi_hw_info->soc_info.index = ppi_dev_idx;
ppi_hw_data = (struct cam_csid_ppi_hw_info *)match_dev->data;
/* need to setup the pdev before call the csid ppi hw probe init */
ppi_dev->ppi_info = ppi_hw_data;
rc = cam_csid_ppi_hw_probe_init(ppi_hw_intf, ppi_dev_idx);
if (rc) {
CAM_ERR(CAM_ISP, "PPI: Probe init failed!");
goto free_dev;
}
platform_set_drvdata(pdev, ppi_dev);
CAM_DBG(CAM_ISP, "PPI:%d probe successful",
ppi_hw_intf->hw_idx);
if (ppi_hw_intf->hw_idx < CAM_CSID_PPI_HW_MAX)
cam_csid_ppi_hw_list[ppi_hw_intf->hw_idx] = ppi_hw_intf;
else
goto free_dev;
return 0;
free_dev:
kfree(ppi_dev);
free_hw_info:
kfree(ppi_hw_info);
free_hw_intf:
kfree(ppi_hw_intf);
err:
return rc;
}
int cam_csid_ppi_remove(struct platform_device *pdev)
{
struct cam_csid_ppi_hw *ppi_dev = NULL;
struct cam_hw_intf *ppi_hw_intf;
struct cam_hw_info *ppi_hw_info;
ppi_dev = (struct cam_csid_ppi_hw *)platform_get_drvdata(pdev);
ppi_hw_intf = ppi_dev->hw_intf;
ppi_hw_info = ppi_dev->hw_info;
CAM_DBG(CAM_ISP, "PPI:%d remove", ppi_dev->hw_intf->hw_idx);
cam_csid_ppi_hw_deinit(ppi_dev);
/* release the ppi device memory */
kfree(ppi_dev);
kfree(ppi_hw_info);
kfree(ppi_hw_intf);
return 0;
}
int cam_csid_ppi_hw_init(struct cam_hw_intf **csid_ppi_hw,
uint32_t hw_idx)
{
int rc = 0;
if (cam_csid_ppi_hw_list[hw_idx]) {
*csid_ppi_hw = cam_csid_ppi_hw_list[hw_idx];
} else {
*csid_ppi_hw = NULL;
rc = -1;
}
return rc;
}
EXPORT_SYMBOL(cam_csid_ppi_hw_init);