mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
media: rockchip: cif: add subdev as interface for isp
Signed-off-by: Hu Kejun <william.hu@rock-chips.com> Change-Id: Iebf7545485a84a7817c76f9b3c81884aeac5a974
This commit is contained in:
@@ -4,4 +4,5 @@ video_rkcif-objs += dev.o \
|
||||
capture.o \
|
||||
mipi-csi2.o \
|
||||
cif-luma.o \
|
||||
hw.o
|
||||
hw.o \
|
||||
subdev-itf.o
|
||||
|
||||
@@ -676,7 +676,6 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
|
||||
{
|
||||
struct device *dev = cif_dev->dev;
|
||||
struct v4l2_device *v4l2_dev;
|
||||
char name[V4L2_DEVICE_NAME_SIZE] = {'\0'};
|
||||
int ret;
|
||||
|
||||
cif_dev->hdr.mode = NO_HDR;
|
||||
@@ -710,17 +709,12 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int
|
||||
cif_dev->workmode = RKCIF_WORKMODE_PINGPONG;
|
||||
#endif
|
||||
|
||||
if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE)
|
||||
strncpy(name, "rkcif_lite", strlen("rkcif_lite"));
|
||||
else
|
||||
strncpy(name, "rkcif", strlen("rkcif"));
|
||||
|
||||
strlcpy(cif_dev->media_dev.model, name,
|
||||
strlcpy(cif_dev->media_dev.model, dev_name(dev),
|
||||
sizeof(cif_dev->media_dev.model));
|
||||
cif_dev->media_dev.dev = dev;
|
||||
v4l2_dev = &cif_dev->v4l2_dev;
|
||||
v4l2_dev->mdev = &cif_dev->media_dev;
|
||||
strlcpy(v4l2_dev->name, name, sizeof(v4l2_dev->name));
|
||||
strlcpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name));
|
||||
|
||||
ret = v4l2_device_register(cif_dev->dev, &cif_dev->v4l2_dev);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "cif-luma.h"
|
||||
#include "mipi-csi2.h"
|
||||
#include "hw.h"
|
||||
#include "subdev-itf.h"
|
||||
|
||||
#define CIF_DRIVER_NAME "rkcif"
|
||||
#define CIF_VIDEODEVICE_NAME "stream_cif"
|
||||
@@ -370,6 +371,8 @@ struct rkcif_device {
|
||||
struct rkcif_hw *hw_dev;
|
||||
irqreturn_t (*isr_hdl)(int irq, struct rkcif_device *cif_dev);
|
||||
int inf_id;
|
||||
|
||||
struct sditf_priv *sditf;
|
||||
};
|
||||
|
||||
extern struct platform_driver rkcif_plat_drv;
|
||||
|
||||
@@ -735,8 +735,10 @@ static int rkcif_plat_probe(struct platform_device *pdev)
|
||||
rkcif_hw_soft_reset(cif_hw, true);
|
||||
|
||||
if (data->chip_id == CHIP_RK1808_CIF ||
|
||||
data->chip_id == CHIP_RV1126_CIF)
|
||||
data->chip_id == CHIP_RV1126_CIF) {
|
||||
platform_driver_register(&rkcif_plat_drv);
|
||||
platform_driver_register(&rkcif_subdev_driver);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
268
drivers/media/platform/rockchip/cif/subdev-itf.c
Normal file
268
drivers/media/platform/rockchip/cif/subdev-itf.c
Normal file
@@ -0,0 +1,268 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Rockchip CIF Driver
|
||||
*
|
||||
* Copyright (C) 2020 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include "dev.h"
|
||||
|
||||
static inline struct sditf_priv *to_sditf_priv(struct v4l2_subdev *subdev)
|
||||
{
|
||||
return container_of(subdev, struct sditf_priv, sd);
|
||||
}
|
||||
|
||||
static int sditf_g_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *fi)
|
||||
{
|
||||
struct sditf_priv *priv = to_sditf_priv(sd);
|
||||
struct rkcif_device *cif_dev = priv->cif_dev;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
|
||||
if (cif_dev->active_sensor) {
|
||||
sensor_sd = cif_dev->active_sensor->sd;
|
||||
return v4l2_subdev_call(sensor_sd, video, g_frame_interval, fi);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int sditf_g_mbus_config(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_config *config)
|
||||
{
|
||||
struct sditf_priv *priv = to_sditf_priv(sd);
|
||||
struct rkcif_device *cif_dev = priv->cif_dev;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
|
||||
if (cif_dev->active_sensor) {
|
||||
sensor_sd = cif_dev->active_sensor->sd;
|
||||
return v4l2_subdev_call(sensor_sd, video, g_mbus_config, config);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int sditf_get_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct sditf_priv *priv = to_sditf_priv(sd);
|
||||
struct rkcif_device *cif_dev = priv->cif_dev;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
|
||||
if (cif_dev->active_sensor) {
|
||||
sensor_sd = cif_dev->active_sensor->sd;
|
||||
return v4l2_subdev_call(sensor_sd, pad, get_fmt, NULL, fmt);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int sditf_get_selection(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_selection *sel)
|
||||
{
|
||||
struct sditf_priv *priv = to_sditf_priv(sd);
|
||||
struct rkcif_device *cif_dev = priv->cif_dev;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
|
||||
if (cif_dev->active_sensor) {
|
||||
sensor_sd = cif_dev->active_sensor->sd;
|
||||
return v4l2_subdev_call(sensor_sd, pad, get_selection, NULL, sel);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct sditf_priv *priv = to_sditf_priv(sd);
|
||||
struct rkcif_device *cif_dev = priv->cif_dev;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
|
||||
if (cif_dev->terminal_sensor) {
|
||||
sensor_sd = cif_dev->terminal_sensor;
|
||||
return v4l2_subdev_call(sensor_sd, core, ioctl, cmd, arg);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long sditf_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct sditf_priv *priv = to_sditf_priv(sd);
|
||||
struct rkcif_device *cif_dev = priv->cif_dev;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
|
||||
if (cif_dev->terminal_sensor) {
|
||||
sensor_sd = cif_dev->terminal_sensor;
|
||||
return v4l2_subdev_call(sensor_sd, core, compat_ioctl32, cmd, arg);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct v4l2_subdev_pad_ops sditf_subdev_pad_ops = {
|
||||
.set_fmt = sditf_get_set_fmt,
|
||||
.get_fmt = sditf_get_set_fmt,
|
||||
.get_selection = sditf_get_selection,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops sditf_video_ops = {
|
||||
.g_frame_interval = sditf_g_frame_interval,
|
||||
.g_mbus_config = sditf_g_mbus_config,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops sditf_core_ops = {
|
||||
.ioctl = sditf_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl32 = sditf_compat_ioctl32,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops sditf_subdev_ops = {
|
||||
.core = &sditf_core_ops,
|
||||
.video = &sditf_video_ops,
|
||||
.pad = &sditf_subdev_pad_ops,
|
||||
};
|
||||
|
||||
static int rkcif_sditf_attach_cifdev(struct sditf_priv *sditf)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct platform_device *pdev;
|
||||
struct rkcif_device *cif_dev;
|
||||
|
||||
np = of_parse_phandle(sditf->dev->of_node, "rockchip,cif", 0);
|
||||
if (!np || !of_device_is_available(np)) {
|
||||
dev_err(sditf->dev, "failed to get cif dev node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdev = of_find_device_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!pdev) {
|
||||
dev_err(sditf->dev, "failed to get cif dev from node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cif_dev = platform_get_drvdata(pdev);
|
||||
if (!cif_dev) {
|
||||
dev_err(sditf->dev, "failed attach cif dev\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cif_dev->sditf = sditf;
|
||||
sditf->cif_dev = cif_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkcif_subdev_media_init(struct sditf_priv *priv)
|
||||
{
|
||||
struct rkcif_device *cif_dev = priv->cif_dev;
|
||||
int ret;
|
||||
|
||||
priv->pads.flags = MEDIA_PAD_FL_SOURCE;
|
||||
priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_COMPOSER;
|
||||
ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pads);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
strncpy(priv->sd.name, dev_name(cif_dev->dev), sizeof(priv->sd.name));
|
||||
return v4l2_async_register_subdev(&priv->sd);
|
||||
}
|
||||
|
||||
static int rkcif_subdev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct v4l2_subdev *sd;
|
||||
struct sditf_priv *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
priv->dev = dev;
|
||||
|
||||
sd = &priv->sd;
|
||||
v4l2_subdev_init(sd, &sditf_subdev_ops);
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
snprintf(sd->name, sizeof(sd->name), "rockchip-cif-sditf");
|
||||
sd->dev = dev;
|
||||
|
||||
platform_set_drvdata(pdev, &sd->entity);
|
||||
|
||||
rkcif_sditf_attach_cifdev(priv);
|
||||
ret = rkcif_subdev_media_init(priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkcif_subdev_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct media_entity *me = platform_get_drvdata(pdev);
|
||||
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
|
||||
|
||||
media_entity_cleanup(&sd->entity);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sditf_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sditf_runtime_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rkcif_subdev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(sditf_runtime_suspend,
|
||||
sditf_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id rkcif_subdev_match_id[] = {
|
||||
{
|
||||
.compatible = "rockchip,rkcif-sditf",
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rkcif_subdev_match_id);
|
||||
|
||||
struct platform_driver rkcif_subdev_driver = {
|
||||
.probe = rkcif_subdev_probe,
|
||||
.remove = rkcif_subdev_remove,
|
||||
.driver = {
|
||||
.name = "rkcif_sditf",
|
||||
.pm = &rkcif_subdev_pm_ops,
|
||||
.of_match_table = rkcif_subdev_match_id,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(rkcif_subdev_driver);
|
||||
|
||||
MODULE_AUTHOR("Rockchip Camera/ISP team");
|
||||
MODULE_DESCRIPTION("Rockchip CIF platform driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
30
drivers/media/platform/rockchip/cif/subdev-itf.h
Normal file
30
drivers/media/platform/rockchip/cif/subdev-itf.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip CIF Driver
|
||||
*
|
||||
* Copyright (C) 2020 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _RKCIF_SDITF_H
|
||||
#define _RKCIF_SDITF_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <media/media-device.h>
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/videobuf2-v4l2.h>
|
||||
#include <media/v4l2-mc.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include "hw.h"
|
||||
|
||||
struct sditf_priv {
|
||||
struct device *dev;
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pads;
|
||||
struct rkcif_device *cif_dev;
|
||||
};
|
||||
|
||||
extern struct platform_driver rkcif_subdev_driver;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user