kernel_samsung_a53x/drivers/media/platform/exynos/camera/pablo-device-camif-subblks.c
2024-06-15 16:02:09 -03:00

387 lines
8.7 KiB
C
Executable file

// SPDX-License-Identifier: GPL-2.0
/*
* Samsung Exynos SoC series Pablo driver
*
* Copyright (c) 2021 Samsung Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/of_platform.h>
#include "is-hw.h"
#include "is-debug.h"
#include "pablo-device-camif-subblks.h"
/* BNS */
static struct pablo_camif_bns *pablo_bns;
#if IS_ENABLED(CONFIG_PABLO_CAMIF_BNS)
struct pablo_camif_bns *pablo_camif_bns_get(void)
{
return pablo_bns;
}
void pablo_camif_bns_cfg(struct pablo_camif_bns *bns,
struct is_sensor_cfg *sensor_cfg,
u32 ch)
{
bns->en = csi_hw_s_bns_cfg(bns->regs, sensor_cfg,
&bns->width, &bns->height);
if (!bns->en)
return;
csi_hw_s_bns_ch(bns->mux_regs, ch);
if (unlikely(is_get_debug_param(IS_DEBUG_PARAM_CSI)))
csi_hw_bns_dump(bns->regs);
}
void pablo_camif_bns_reset(struct pablo_camif_bns *bns)
{
if (!bns->en)
return;
csi_hw_reset_bns(bns->regs);
bns->en = false;
if (unlikely(is_get_debug_param(IS_DEBUG_PARAM_CSI)))
csi_hw_bns_dump(bns->regs);
}
#endif
static int pablo_camif_bns_probe(struct platform_device *pdev,
struct pablo_camif_subblks_data *data)
{
int ret;
struct device *dev = &pdev->dev;
struct device_node *dnode = dev->of_node;
struct resource *res;
u32 elems;
pablo_bns = devm_kzalloc(dev, sizeof(*pablo_bns), GFP_KERNEL);
if (!pablo_bns) {
dev_err(dev, "failed to allocate drv_data\n");
return -ENOMEM;
}
pablo_bns->dev = &pdev->dev;
pablo_bns->data = data;
pablo_bns->en = false;
/* Get BNS base address */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctl");
if (!res) {
dev_err(dev, "failed to get ctl IORESOURCE_MEM");
ret = -ENOMEM;
goto ioremap_ctl_err;
}
pablo_bns->regs = devm_ioremap(dev, res->start, resource_size(res));
if (IS_ERR_OR_NULL(pablo_bns->regs)) {
dev_err(dev, "failed to ioremap for ctl\n");
ret = -ENOMEM;
goto ioremap_ctl_err;
}
/* Get BNS In/Out mux address */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mux");
if (!res) {
dev_err(dev, "failed to get mux IORESOURCE_MEM");
ret = -ENOMEM;
goto ioremap_mux_err;
}
pablo_bns->mux_regs = devm_ioremap(dev, res->start, resource_size(res));
if (IS_ERR_OR_NULL(pablo_bns->regs)) {
dev_err(dev, "failed to ioremap for ctl\n");
ret = -ENOMEM;
goto ioremap_mux_err;
}
/* Get BNS In/Out mux values */
ret = of_property_count_u32_elems(dnode, "mux");
if (ret < 0) {
dev_err(dev, "failed to get mux_val\n");
goto mux_val_err;
}
elems = ret;
pablo_bns->mux_val = devm_kcalloc(dev, elems, sizeof(*pablo_bns->mux_val), GFP_KERNEL);
if (!pablo_bns->mux_val) {
dev_err(dev, "failed to allocate mux_val memory\n");
ret = -ENOMEM;
goto mux_val_err;
}
ret = of_property_read_u32_array(dnode, "mux", pablo_bns->mux_val, elems);
if (ret) {
dev_err(dev, "failed to get mux_val resource\n");
goto mux_val_read_err;
}
ret = of_property_read_u32(dnode, "dma_mux", &pablo_bns->dma_mux_val);
if (ret) {
dev_err(dev, "failed to get dma_mux_val resource\n");
goto mux_val_read_err;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mux");
platform_set_drvdata(pdev, pablo_bns);
dev_info(dev, "%s done\n", __func__);
return 0;
mux_val_read_err:
devm_kfree(dev, pablo_bns->mux_val);
mux_val_err:
devm_iounmap(dev, pablo_bns->mux_regs);
ioremap_mux_err:
devm_iounmap(dev, pablo_bns->regs);
ioremap_ctl_err:
devm_kfree(dev, pablo_bns);
return ret;
}
static struct pablo_camif_subblks_data bns_data = {
.slock = __SPIN_LOCK_UNLOCKED(bns_data.slock),
.probe = pablo_camif_bns_probe,
};
/* MCB */
static struct pablo_camif_mcb *camif_mcb;
struct pablo_camif_mcb *pablo_camif_mcb_get(void)
{
return camif_mcb;
}
static int pablo_camif_mcb_probe(struct platform_device *pdev,
struct pablo_camif_subblks_data *data)
{
struct device *dev = &pdev->dev;
struct resource *res;
int ret;
camif_mcb = devm_kzalloc(dev, sizeof(*camif_mcb), GFP_KERNEL);
if (!camif_mcb) {
dev_err(dev, "failed to alloc memory\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
probe_err("failed to get memory resource for MCB");
ret = -ENODEV;
goto err_get_res;
}
camif_mcb->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(camif_mcb->regs)) {
dev_err(dev, "failed to get & ioremap for MCB control\n");
ret = PTR_ERR(camif_mcb->regs);
goto err_get_ioremap_ctl;
}
camif_mcb->active_ch = 0;
mutex_init(&camif_mcb->lock);
dev_info(dev, "%s done\n", __func__);
return 0;
err_get_ioremap_ctl:
err_get_res:
devm_kfree(dev, camif_mcb);
return ret;
}
static struct pablo_camif_subblks_data mcb_data = {
.probe = pablo_camif_mcb_probe,
};
/* EBUF */
static struct pablo_camif_ebuf *camif_ebuf;
struct pablo_camif_ebuf *pablo_camif_ebuf_get(void)
{
return camif_ebuf;
}
static int pablo_camif_ebuf_probe(struct platform_device *pdev,
struct pablo_camif_subblks_data *data)
{
struct device *dev = &pdev->dev;
struct device_node *dnode = dev->of_node;
struct resource *res;
int ret;
camif_ebuf = devm_kzalloc(dev, sizeof(*camif_ebuf), GFP_KERNEL);
if (!camif_ebuf) {
dev_err(dev, "failed to alloc memory\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
probe_err("failed to get memory resource for EUBF");
ret = -ENODEV;
goto err_get_res;
}
camif_ebuf->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(camif_ebuf->regs)) {
dev_err(dev, "failed to get & ioremap for EBUF control\n");
ret = PTR_ERR(camif_ebuf->regs);
goto err_get_ioremap_ctl;
}
camif_ebuf->irq = platform_get_irq(pdev, 0);
if (camif_ebuf->irq < 0) {
dev_err(dev, "failed to get IRQ for EBUF: %d\n", camif_ebuf->irq);
ret = camif_ebuf->irq;
goto err_get_irq;
}
ret = of_property_read_u32(dnode, "num_of_ebuf", &camif_ebuf->num_of_ebuf);
if (ret) {
dev_err(dev, "failed to get num_of_ebuf property\n");
goto err_get_num_of_ebuf;
}
mutex_init(&camif_ebuf->lock);
dev_info(dev, "%s done\n", __func__);
return 0;
err_get_num_of_ebuf:
err_get_irq:
devm_iounmap(dev, camif_ebuf->regs);
err_get_ioremap_ctl:
err_get_res:
devm_kfree(dev, camif_ebuf);
return ret;
}
static struct pablo_camif_subblks_data ebuf_data = {
.probe = pablo_camif_ebuf_probe,
};
/* COMMON */
static const struct of_device_id pablo_camif_subblks_of_table[] = {
{
.name = "camif-bns",
.compatible = "samsung,camif-bns",
.data = &bns_data,
},
{
.name = "camif-mcb",
.compatible = "samsung,camif-mcb",
.data = &mcb_data,
},
{
.name = "camif-ebuf",
.compatible = "samsung,camif-ebuf",
.data = &ebuf_data,
},
{},
};
MODULE_DEVICE_TABLE(of, pablo_camif_subblks_of_table);
static int pablo_camif_subblks_suspend(struct device *dev)
{
return 0;
}
static int pablo_camif_subblks_resume(struct device *dev)
{
return 0;
}
int pablo_camif_subblks_runtime_suspend(struct device *dev)
{
return 0;
}
int pablo_camif_subblks_runtime_resume(struct device *dev)
{
return 0;
}
static const struct dev_pm_ops pablo_camif_subblks_pm_ops = {
.suspend = pablo_camif_subblks_suspend,
.resume = pablo_camif_subblks_resume,
.runtime_suspend = pablo_camif_subblks_runtime_suspend,
.runtime_resume = pablo_camif_subblks_runtime_resume,
};
static int pablo_camif_subblks_pdev_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
struct pablo_camif_subblks_data *data;
of_id = of_match_device(of_match_ptr(pablo_camif_subblks_of_table), dev);
if (!of_id)
return -EINVAL;
data = (struct pablo_camif_subblks_data *)of_id->data;
return data->probe(pdev, data);
}
static int pablo_camif_subblks_pdev_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
struct pablo_camif_subblks_data *data;
of_id = of_match_device(of_match_ptr(pablo_camif_subblks_of_table), dev);
if (!of_id)
return -EINVAL;
data = (struct pablo_camif_subblks_data *)of_id->data;
return data->remove(pdev, data);
}
struct platform_driver pablo_camif_subblks_driver = {
.probe = pablo_camif_subblks_pdev_probe,
.remove = pablo_camif_subblks_pdev_remove,
.driver = {
.name = "pablo-camif-subblks",
.owner = THIS_MODULE,
.of_match_table = pablo_camif_subblks_of_table,
.pm = &pablo_camif_subblks_pm_ops,
}
};
#ifndef MODULE
static int __init pablo_camif_subblks_init(void)
{
int ret;
ret = platform_driver_probe(&pablo_camif_subblks_driver,
pablo_camif_subblks_pdev_probe);
if (ret)
pr_err("failed to probe %s driver: %d\n",
"pablo-camif-subblks", ret);
return ret;
}
device_initcall_sync(pablo_camif_subblks_init);
#endif
MODULE_DESCRIPTION("Samsung EXYNOS SoC Pablo CAMIF Sub-blocks driver");
MODULE_ALIAS("platform:samsung-pablo-camif-subblks");
MODULE_LICENSE("GPL v2");