1297 lines
38 KiB
C

/*
* Rockchip isp1 driver
*
* Copyright (C) 2017 Rockchip Electronics Co., Ltd.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <soc/rockchip/rockchip-system-status.h>
#include "common.h"
#include "isp_ispp.h"
#include "regs.h"
#include "rkisp.h"
#include "version.h"
#include "csi.h"
#define RKISP_VERNO_LEN 10
int rkisp_debug;
module_param_named(debug, rkisp_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
bool rkisp_monitor;
module_param_named(monitor, rkisp_monitor, bool, 0644);
MODULE_PARM_DESC(monitor, "rkisp abnormal restart monitor");
bool rkisp_irq_dbg;
module_param_named(irq_dbg, rkisp_irq_dbg, bool, 0644);
MODULE_PARM_DESC(irq_dbg, "rkisp interrupt runtime");
bool rkisp_buf_dbg;
module_param_named(buf_dbg, rkisp_buf_dbg, bool, 0644);
MODULE_PARM_DESC(buf_dbg, "rkisp check output buf");
static bool rkisp_rdbk_auto;
module_param_named(rdbk_auto, rkisp_rdbk_auto, bool, 0644);
MODULE_PARM_DESC(irq_dbg, "rkisp and vicap auto readback mode");
static bool rkisp_clk_dbg;
module_param_named(clk_dbg, rkisp_clk_dbg, bool, 0644);
MODULE_PARM_DESC(clk_dbg, "rkisp clk set by user");
static bool rkisp_m_online[DEV_MAX];
module_param_array_named(m_online, rkisp_m_online, bool, NULL, 0644);
MODULE_PARM_DESC(m_online, "rkisp multi sensor online mode");
static char rkisp_version[RKISP_VERNO_LEN];
module_param_string(version, rkisp_version, RKISP_VERNO_LEN, 0444);
MODULE_PARM_DESC(version, "version number");
u64 rkisp_debug_reg = 0xFFFFFFFFFLL;
module_param_named(debug_reg, rkisp_debug_reg, ullong, 0644);
MODULE_PARM_DESC(debug_reg, "rkisp debug register");
static unsigned int rkisp_wait_line;
module_param_named(wait_line, rkisp_wait_line, uint, 0644);
MODULE_PARM_DESC(wait_line, "rkisp wait line to buf done early");
static unsigned int rkisp_wrap_line;
module_param_named(wrap_line, rkisp_wrap_line, uint, 0644);
MODULE_PARM_DESC(wrap_line, "rkisp wrap line for mpp");
unsigned int rkisp_vicap_buf[DEV_MAX];
module_param_array_named(vicap_raw_buf, rkisp_vicap_buf, uint, NULL, 0644);
MODULE_PARM_DESC(vicap_raw_buf, "rkisp and vicap auto readback mode raw buf count");
unsigned int rkisp_hdr_wrap_line[DEV_MAX];
module_param_array_named(hdr_wrap_line, rkisp_hdr_wrap_line, uint, NULL, 0644);
MODULE_PARM_DESC(hdr_wrap_line, "rkisp and vicap online hdr wrap line");
static DEFINE_MUTEX(rkisp_dev_mutex);
static LIST_HEAD(rkisp_device_list);
void rkisp_set_clk_rate(struct clk *clk, unsigned long rate)
{
if (rkisp_clk_dbg)
return;
clk_set_rate(clk, rate);
}
static int __maybe_unused __rkisp_clr_unready_dev(void)
{
struct rkisp_device *isp_dev;
mutex_lock(&rkisp_dev_mutex);
list_for_each_entry(isp_dev, &rkisp_device_list, list)
v4l2_async_notifier_clr_unready_dev(&isp_dev->notifier);
mutex_unlock(&rkisp_dev_mutex);
return 0;
}
static int rkisp_clr_unready_dev_param_set(const char *val, const struct kernel_param *kp)
{
#ifdef MODULE
__rkisp_clr_unready_dev();
#endif
return 0;
}
module_param_call(clr_unready_dev, rkisp_clr_unready_dev_param_set, NULL, NULL, 0200);
MODULE_PARM_DESC(clr_unready_dev, "clear unready devices");
/**************************** pipeline operations *****************************/
static int __isp_pipeline_prepare(struct rkisp_pipeline *p,
struct media_entity *me)
{
struct rkisp_device *dev = container_of(p, struct rkisp_device, pipe);
struct v4l2_subdev *sd;
int i;
p->num_subdevs = 0;
memset(p->subdevs, 0, sizeof(p->subdevs));
if (!(dev->isp_inp & (INP_CSI | INP_DVP | INP_LVDS | INP_CIF)))
return 0;
while (1) {
struct media_pad *pad = NULL;
/* Find remote source pad */
for (i = 0; i < me->num_pads; i++) {
struct media_pad *spad = &me->pads[i];
if (!(spad->flags & MEDIA_PAD_FL_SINK))
continue;
pad = rkisp_media_entity_remote_pad(spad);
if (pad)
break;
}
if (!pad)
break;
sd = media_entity_to_v4l2_subdev(pad->entity);
if (sd != &dev->isp_sdev.sd)
p->subdevs[p->num_subdevs++] = sd;
me = &sd->entity;
if (me->num_pads == 1)
break;
}
if (!p->num_subdevs)
return -EINVAL;
return 0;
}
static int __isp_pipeline_s_isp_clk(struct rkisp_pipeline *p)
{
struct rkisp_device *dev = container_of(p, struct rkisp_device, pipe);
struct rkisp_hw_dev *hw_dev = dev->hw_dev;
struct v4l2_subdev *sd;
struct v4l2_ctrl *ctrl;
u64 data_rate = 0;
int i, fps, size;
hw_dev->isp_size[dev->dev_id].is_on = true;
if (hw_dev->is_runing) {
if (dev->isp_ver >= ISP_V30 && !rkisp_clk_dbg)
hw_dev->is_dvfs = true;
return 0;
}
if (dev->isp_inp & (INP_RAWRD0 | INP_RAWRD1 | INP_RAWRD2) ||
(dev->is_pre_on && hw_dev->dev_num > 1)) {
if (dev->isp_ver < ISP_V30 || dev->is_pre_on) {
/* isp with mipi no support dvfs, calculate max data rate */
for (i = 0; i < hw_dev->dev_num; i++) {
fps = hw_dev->isp_size[i].fps;
if (!fps)
fps = 30;
size = hw_dev->isp_size[i].size * hw_dev->isp[i]->unite_div;
data_rate += (fps * size);
}
} else {
i = dev->dev_id;
fps = hw_dev->isp_size[i].fps;
if (!fps)
fps = 30;
size = hw_dev->isp_size[i].size * dev->unite_div;
data_rate = fps * size;
}
goto end;
}
if (dev->isp_inp == INP_DMARX_ISP && dev->hw_dev->clks[0]) {
rkisp_set_clk_rate(hw_dev->clks[0], 400 * 1000000UL);
return 0;
}
/* find the subdev of active sensor or vicap itf */
sd = p->subdevs[0];
for (i = 0; i < p->num_subdevs; i++) {
sd = p->subdevs[i];
if (sd->entity.function == MEDIA_ENT_F_CAM_SENSOR ||
sd->entity.function == MEDIA_ENT_F_PROC_VIDEO_COMPOSER)
break;
}
if (i == p->num_subdevs) {
v4l2_warn(&dev->v4l2_dev, "No active sensor\n");
hw_dev->isp_size[dev->dev_id].is_on = false;
return -EPIPE;
}
ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
if (!ctrl) {
v4l2_warn(&dev->v4l2_dev, "No pixel rate control in subdev\n");
hw_dev->isp_size[dev->dev_id].is_on = false;
return -EPIPE;
}
/* calculate data rate */
data_rate = v4l2_ctrl_g_ctrl_int64(ctrl) *
dev->isp_sdev.in_fmt.bus_width;
data_rate >>= 3;
end:
do_div(data_rate, 1000 * 1000);
if (hw_dev->unite == ISP_UNITE_ONE)
data_rate *= 4;
/* increase 25% margin */
data_rate += data_rate >> 2;
/* compare with isp clock adjustment table */
for (i = 0; i < hw_dev->num_clk_rate_tbl; i++)
if (data_rate <= hw_dev->clk_rate_tbl[i].clk_rate)
break;
if (i == hw_dev->num_clk_rate_tbl)
i--;
/* set isp clock rate */
rkisp_set_clk_rate(hw_dev->clks[0], hw_dev->clk_rate_tbl[i].clk_rate * 1000000UL);
if (hw_dev->unite == ISP_UNITE_TWO)
rkisp_set_clk_rate(hw_dev->clks[5], hw_dev->clk_rate_tbl[i].clk_rate * 1000000UL);
/* aclk equal to core clk */
if (dev->isp_ver == ISP_V32 || dev->isp_ver == ISP_V33)
rkisp_set_clk_rate(hw_dev->clks[1], hw_dev->clk_rate_tbl[i].clk_rate * 1000000UL);
dev_info(hw_dev->dev, "set isp clk = %luHz\n", clk_get_rate(hw_dev->clks[0]));
return 0;
}
static int rkisp_pipeline_open(struct rkisp_pipeline *p,
struct media_entity *me,
bool prepare)
{
struct rkisp_device *dev = container_of(p, struct rkisp_device, pipe);
struct rkisp_hw_dev *hw = dev->hw_dev;
int ret;
if (WARN_ON(!p || !me))
return -EINVAL;
if (atomic_inc_return(&p->power_cnt) > 1)
return 0;
dev->hdr_wrap_line = 0;
if (hw->is_assigned_clk)
rkisp_clk_dbg = true;
if (!(dev->isp_inp & (INP_RAWRD0 | INP_RAWRD2))) {
dev->is_rdbk_auto = rkisp_rdbk_auto;
if (dev->is_aiisp_en)
dev->is_rdbk_auto = true;
if (rkisp_vicap_buf[dev->dev_id] > RKISP_VICAP_BUF_CNT_MAX)
rkisp_vicap_buf[dev->dev_id] = RKISP_VICAP_BUF_CNT_MAX;
dev->vicap_buf_cnt = rkisp_vicap_buf[dev->dev_id];
dev->is_m_online = rkisp_m_online[dev->dev_id];
if (hw->isp_ver != ISP_V33 || hw->is_single)
dev->is_m_online = false;
if (hw->isp_ver == ISP_V33) {
if (dev->unite_div != ISP_UNITE_DIV1)
rkisp_hdr_wrap_line[dev->dev_id] = 0;
dev->hdr_wrap_line = rkisp_hdr_wrap_line[dev->dev_id];
}
}
dev->cap_dev.wait_line = rkisp_wait_line;
/* go through media graphic and get subdevs */
if (prepare) {
ret = __isp_pipeline_prepare(p, me);
if (ret < 0)
goto err;
}
ret = __isp_pipeline_s_isp_clk(p);
if (ret < 0)
goto err;
if (!dev->hw_dev->monitor.is_en)
dev->hw_dev->monitor.is_en = rkisp_monitor;
if (dev->isp_inp & (INP_CSI | INP_RAWRD0 | INP_RAWRD1 | INP_RAWRD2 | INP_CIF))
rkisp_csi_config_patch(dev, false);
return 0;
err:
atomic_dec(&p->power_cnt);
return ret;
}
static int rkisp_pipeline_close(struct rkisp_pipeline *p)
{
struct rkisp_device *dev = container_of(p, struct rkisp_device, pipe);
if (atomic_dec_return(&p->power_cnt))
return 0;
rkisp_rx_buf_pool_free(dev);
dev->hw_dev->isp_size[dev->dev_id].is_on = false;
if (dev->hw_dev->is_runing && (dev->isp_ver >= ISP_V30) && !rkisp_clk_dbg)
dev->hw_dev->is_dvfs = true;
dev->is_rdbk_auto = false;
dev->is_m_online = false;
return 0;
}
/*
* stream-on order: isp_subdev, mipi dphy, sensor
* stream-off order: mipi dphy, sensor, isp_subdev
*/
static int rkisp_pipeline_set_stream(struct rkisp_pipeline *p, bool on)
{
struct rkisp_device *dev = container_of(p, struct rkisp_device, pipe);
int i, ret, open_num = 0;
if ((on && atomic_inc_return(&p->stream_cnt) > 1) ||
(!on && atomic_dec_return(&p->stream_cnt) > 0))
return 0;
if (on) {
if (dev->vs_irq >= 0)
enable_irq(dev->vs_irq);
rockchip_set_system_status(SYS_STATUS_ISP);
ret = v4l2_subdev_call(&dev->isp_sdev.sd, video, s_stream, true);
if (ret < 0)
goto err;
if (dev->is_m_online && !dev->is_pre_on &&
atomic_read(&dev->hw_dev->refcnt) == 1) {
i = 1;
v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_HW_LINK, &i);
}
/* phy -> sensor */
for (i = 0; i < p->num_subdevs; ++i) {
if (((dev->vicap_in.merge_num > 1) &&
(p->subdevs[i]->entity.function == MEDIA_ENT_F_CAM_SENSOR)) ||
((dev->isp_inp & (INP_CIF | INP_RAWRD2)) == (INP_CIF | INP_RAWRD2)) ||
dev->is_pre_on)
continue;
ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
goto err_stream_off;
}
} else {
for (i = 0; i < dev->hw_dev->dev_num; i++) {
if (dev->hw_dev->isp_size[i].is_on)
open_num++;
}
if (dev->hw_dev->monitor.is_en && open_num == 1) {
dev->hw_dev->monitor.is_en = 0;
dev->hw_dev->monitor.state = ISP_STOP;
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
}
/* sensor -> phy */
for (i = p->num_subdevs - 1; i >= 0; --i) {
if (((dev->vicap_in.merge_num > 1) &&
(p->subdevs[i]->entity.function == MEDIA_ENT_F_CAM_SENSOR)) ||
((dev->isp_inp & (INP_CIF | INP_RAWRD2)) == (INP_CIF | INP_RAWRD2)))
continue;
v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
}
if (dev->vs_irq >= 0)
disable_irq(dev->vs_irq);
v4l2_subdev_call(&dev->isp_sdev.sd, video, s_stream, false);
rockchip_clear_system_status(SYS_STATUS_ISP);
}
return 0;
err_stream_off:
for (--i; i >= 0; --i)
v4l2_subdev_call(p->subdevs[i], video, s_stream, false);
v4l2_subdev_call(&dev->isp_sdev.sd, video, s_stream, false);
err:
rockchip_clear_system_status(SYS_STATUS_ISP);
atomic_dec_return(&p->stream_cnt);
return ret;
}
/***************************** media controller *******************************/
/* See http://opensource.rock-chips.com/wiki_Rockchip-isp1 for Topology */
static int rkisp_create_links(struct rkisp_device *dev)
{
unsigned int s, pad;
int ret = 0;
/* sensor links(or mipi-phy) */
for (s = 0; s < dev->num_sensors; ++s) {
struct rkisp_sensor_info *sensor = &dev->sensors[s];
u32 type = sensor->sd->entity.function;
bool en = s ? 0 : true;
for (pad = 0; pad < sensor->sd->entity.num_pads; pad++)
if (sensor->sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)
break;
if (pad == sensor->sd->entity.num_pads) {
dev_err(dev->dev, "failed to find src pad for %s\n",
sensor->sd->name);
return -ENXIO;
}
/* sensor link -> isp */
if (type == MEDIA_ENT_F_CAM_SENSOR) {
dev->isp_inp = INP_DVP;
ret = media_create_pad_link(&sensor->sd->entity, pad,
&dev->isp_sdev.sd.entity, RKISP_ISP_PAD_SINK, en);
} else if (type == MEDIA_ENT_F_PROC_VIDEO_COMPOSER) {
dev->isp_inp = INP_CIF;
ret = media_create_pad_link(&sensor->sd->entity, pad,
&dev->isp_sdev.sd.entity, RKISP_ISP_PAD_SINK, en);
} else {
v4l2_subdev_call(sensor->sd, pad,
get_mbus_config, 0, &sensor->mbus);
if (sensor->mbus.type == V4L2_MBUS_CCP2) {
/* mipi-phy lvds link -> isp */
dev->isp_inp = INP_LVDS;
ret = media_create_pad_link(&sensor->sd->entity, pad,
&dev->isp_sdev.sd.entity, RKISP_ISP_PAD_SINK, en);
} else {
/* mipi-phy link -> csi -> isp */
dev->isp_inp = INP_CSI;
ret = media_create_pad_link(&sensor->sd->entity,
pad, &dev->csi_dev.sd.entity, CSI_SINK, en);
ret |= media_create_pad_link(&dev->csi_dev.sd.entity, CSI_SRC_CH0,
&dev->isp_sdev.sd.entity, RKISP_ISP_PAD_SINK, en);
dev->csi_dev.sink[0].linked = en;
dev->csi_dev.sink[0].index = BIT(0);
}
}
if (ret)
dev_err(dev->dev, "failed to create link for %s\n", sensor->sd->name);
}
return ret;
}
static int _set_pipeline_default_fmt(struct rkisp_device *dev, bool is_init)
{
struct v4l2_subdev *isp;
struct v4l2_subdev_format fmt;
struct v4l2_subdev_selection sel;
u32 width, height, code;
memset(&sel, 0, sizeof(sel));
memset(&fmt, 0, sizeof(fmt));
isp = &dev->isp_sdev.sd;
if (dev->active_sensor) {
fmt = dev->active_sensor->fmt[0];
if (!is_init &&
fmt.format.code == dev->isp_sdev.in_frm.code &&
fmt.format.width == dev->isp_sdev.in_frm.width &&
fmt.format.height == dev->isp_sdev.in_frm.height)
return 0;
} else {
fmt.format = dev->isp_sdev.in_frm;
}
code = fmt.format.code;
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt.pad = RKISP_ISP_PAD_SINK;
/* isp input format information from sensor */
v4l2_subdev_call(isp, pad, set_fmt, NULL, &fmt);
rkisp_align_sensor_resolution(dev, &sel.r, false);
width = sel.r.width;
height = sel.r.height;
sel.target = V4L2_SEL_TGT_CROP;
sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sel.pad = RKISP_ISP_PAD_SINK;
/* image resolution processed by isp */
v4l2_subdev_call(isp, pad, set_selection, NULL, &sel);
/* change fmt&size for RKISP_ISP_PAD_SOURCE_PATH */
if ((code & RKISP_MEDIA_BUS_FMT_MASK) == RKISP_MEDIA_BUS_FMT_BAYER)
fmt.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
sel.r.left = 0;
sel.r.top = 0;
fmt.format.width = width;
fmt.format.height = height;
fmt.pad = RKISP_ISP_PAD_SOURCE_PATH;
sel.pad = RKISP_ISP_PAD_SOURCE_PATH;
v4l2_subdev_call(isp, pad, set_fmt, NULL, &fmt);
v4l2_subdev_call(isp, pad, set_selection, NULL, &sel);
/* change fmt&size of MP/SP */
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_MP,
width, height, V4L2_PIX_FMT_NV12);
if (dev->isp_ver != ISP_V10_1)
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_SP,
width, height, V4L2_PIX_FMT_NV12);
if ((dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) &&
dev->isp_inp == INP_CSI && dev->active_sensor) {
width = dev->active_sensor->fmt[1].format.width;
height = dev->active_sensor->fmt[1].format.height;
code = dev->active_sensor->fmt[1].format.code;
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX0,
width, height, rkisp_mbus_pixelcode_to_v4l2(code));
width = dev->active_sensor->fmt[3].format.width;
height = dev->active_sensor->fmt[3].format.height;
code = dev->active_sensor->fmt[3].format.code;
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX2,
width, height, rkisp_mbus_pixelcode_to_v4l2(code));
width = dev->active_sensor->fmt[4].format.width;
height = dev->active_sensor->fmt[4].format.height;
code = dev->active_sensor->fmt[4].format.code;
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX3,
width, height, rkisp_mbus_pixelcode_to_v4l2(code));
}
if (dev->isp_ver == ISP_V20 &&
dev->isp_inp == INP_CSI && dev->active_sensor) {
width = dev->active_sensor->fmt[2].format.width;
height = dev->active_sensor->fmt[2].format.height;
code = dev->active_sensor->fmt[2].format.code;
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_DMATX1,
width, height, rkisp_mbus_pixelcode_to_v4l2(code));
}
if (dev->isp_ver == ISP_V30) {
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_FBC,
width, height, V4L2_PIX_FMT_FBC0);
#ifdef RKISP_STREAM_BP_EN
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_BP,
width, height, V4L2_PIX_FMT_NV12);
#endif
}
if (dev->isp_ver == ISP_V32) {
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_BP,
width, height, V4L2_PIX_FMT_NV12);
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_MPDS,
width / 4, height / 4, V4L2_PIX_FMT_NV12);
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_BPDS,
width / 4, height / 4, V4L2_PIX_FMT_NV12);
}
if (dev->isp_ver == ISP_V39)
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_LDC, width, height, V4L2_PIX_FMT_NV12);
if (dev->isp_ver == ISP_V33)
rkisp_set_stream_def_fmt(dev, RKISP_STREAM_BP,
width, height, V4L2_PIX_FMT_NV12);
return 0;
}
static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
{
struct rkisp_device *dev;
int ret;
dev = container_of(notifier, struct rkisp_device, notifier);
ret = rkisp_create_links(dev);
if (ret < 0)
goto err;
ret = v4l2_device_register_subdev_nodes(&dev->v4l2_dev);
if (ret < 0)
goto err;
if (dev->isp_inp) {
ret = rkisp_update_sensor_info(dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "update sensor failed\n");
goto err;
}
dev->is_hw_link = true;
}
ret = _set_pipeline_default_fmt(dev, true);
if (ret < 0)
goto err;
v4l2_info(&dev->v4l2_dev, "Async subdev notifier completed\n");
err:
if (!ret && dev->is_thunderboot)
schedule_work(&dev->cap_dev.fast_work);
return ret;
}
struct rkisp_async_subdev {
struct v4l2_async_subdev asd;
struct v4l2_mbus_config mbus;
};
static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
{
struct rkisp_device *isp_dev = container_of(notifier,
struct rkisp_device, notifier);
struct rkisp_async_subdev *s_asd = container_of(asd,
struct rkisp_async_subdev, asd);
if (isp_dev->num_sensors == ARRAY_SIZE(isp_dev->sensors))
return -EBUSY;
isp_dev->sensors[isp_dev->num_sensors].mbus = s_asd->mbus;
isp_dev->sensors[isp_dev->num_sensors].sd = subdev;
++isp_dev->num_sensors;
v4l2_dbg(1, rkisp_debug, subdev, "Async registered subdev\n");
return 0;
}
static int rkisp_fwnode_parse(struct device *dev,
struct v4l2_fwnode_endpoint *vep,
struct v4l2_async_subdev *asd)
{
struct rkisp_async_subdev *rk_asd =
container_of(asd, struct rkisp_async_subdev, asd);
/*
* MIPI sensor is linked with a mipi dphy and its media bus config can
* not be get in here
*/
if (vep->bus_type != V4L2_MBUS_BT656 &&
vep->bus_type != V4L2_MBUS_PARALLEL)
return 0;
rk_asd->mbus.type = vep->bus_type;
return 0;
}
static void subdev_notifier_unbind(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
{
struct rkisp_device *isp_dev = container_of(notifier, struct rkisp_device, notifier);
struct rkisp_isp_subdev *isp_sdev = &isp_dev->isp_sdev;
struct v4l2_subdev *isp_sd = &isp_sdev->sd;
int i;
for (i = 0; i < isp_dev->num_sensors; i++) {
if (isp_dev->sensors[i].sd == subdev) {
media_entity_call(&isp_sd->entity, link_setup,
isp_sd->entity.pads, subdev->entity.pads, 0);
isp_dev->sensors[i].sd = NULL;
}
}
}
static const struct v4l2_async_notifier_operations subdev_notifier_ops = {
.bound = subdev_notifier_bound,
.complete = subdev_notifier_complete,
.unbind = subdev_notifier_unbind,
};
static int isp_subdev_notifier(struct rkisp_device *isp_dev)
{
struct v4l2_async_notifier *ntf = &isp_dev->notifier;
struct device *dev = isp_dev->dev;
int ret;
v4l2_async_nf_init(ntf);
ret = v4l2_async_nf_parse_fwnode_endpoints(
dev, ntf, sizeof(struct rkisp_async_subdev),
rkisp_fwnode_parse);
if (ret < 0)
return ret;
ntf->ops = &subdev_notifier_ops;
return v4l2_async_nf_register(&isp_dev->v4l2_dev, ntf);
}
/***************************** platform deive *******************************/
static int rkisp_register_platform_subdevs(struct rkisp_device *dev)
{
int ret;
ret = rkisp_register_isp_subdev(dev, &dev->v4l2_dev);
if (ret < 0)
return ret;
ret = rkisp_register_csi_subdev(dev, &dev->v4l2_dev);
if (ret < 0)
goto err_unreg_isp_subdev;
ret = rkisp_register_bridge_subdev(dev, &dev->v4l2_dev);
if (ret < 0)
goto err_unreg_csi_subdev;
ret = rkisp_register_stream_vdevs(dev);
if (ret < 0)
goto err_unreg_bridge_subdev;
ret = rkisp_register_dmarx_vdev(dev);
if (ret < 0)
goto err_unreg_stream_vdev;
ret = rkisp_register_stats_vdev(&dev->stats_vdev, &dev->v4l2_dev, dev);
if (ret < 0)
goto err_unreg_dmarx_vdev;
ret = rkisp_register_params_vdev(&dev->params_vdev, &dev->v4l2_dev, dev);
if (ret < 0)
goto err_unreg_stats_vdev;
ret = rkisp_register_luma_vdev(&dev->luma_vdev, &dev->v4l2_dev, dev);
if (ret < 0)
goto err_unreg_params_vdev;
ret = rkisp_register_pdaf_vdev(dev);
if (ret < 0)
goto err_unreg_luma_vdev;
ret = isp_subdev_notifier(dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"Failed to register subdev notifier(%d)\n", ret);
goto err_unreg_pdaf_vdev;
}
return 0;
err_unreg_pdaf_vdev:
rkisp_unregister_pdaf_vdev(dev);
err_unreg_luma_vdev:
rkisp_unregister_luma_vdev(&dev->luma_vdev);
err_unreg_params_vdev:
rkisp_unregister_params_vdev(&dev->params_vdev);
err_unreg_stats_vdev:
rkisp_unregister_stats_vdev(&dev->stats_vdev);
err_unreg_dmarx_vdev:
rkisp_unregister_dmarx_vdev(dev);
err_unreg_stream_vdev:
rkisp_unregister_stream_vdevs(dev);
err_unreg_bridge_subdev:
rkisp_unregister_bridge_subdev(dev);
err_unreg_csi_subdev:
rkisp_unregister_csi_subdev(dev);
err_unreg_isp_subdev:
rkisp_unregister_isp_subdev(dev);
return ret;
}
static int rkisp_vs_irq_parse(struct device *dev)
{
int ret;
int vs_irq;
unsigned long vs_irq_flags;
struct gpio_desc *vs_irq_gpio;
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
/* this irq recevice the message of sensor vs from preisp */
isp_dev->vs_irq = -1;
vs_irq_gpio = devm_gpiod_get(dev, "vsirq", GPIOD_IN);
if (!IS_ERR(vs_irq_gpio)) {
vs_irq_flags = IRQF_TRIGGER_RISING |
IRQF_ONESHOT | IRQF_SHARED;
vs_irq = gpiod_to_irq(vs_irq_gpio);
if (vs_irq < 0) {
dev_err(dev, "GPIO to interrupt failed\n");
return vs_irq;
}
dev_info(dev, "register_irq: %d\n", vs_irq);
ret = devm_request_irq(dev,
vs_irq,
rkisp_vs_isr_handler,
vs_irq_flags,
"vs_irq_gpio_int",
dev);
if (ret) {
dev_err(dev, "devm_request_irq failed: %d\n", ret);
return ret;
} else {
disable_irq(vs_irq);
isp_dev->vs_irq = vs_irq;
isp_dev->vs_irq_gpio = vs_irq_gpio;
dev_info(dev, "vs_gpio_int interrupt is hooked\n");
}
}
return 0;
}
static const struct media_device_ops rkisp_media_ops = {
.link_notify = v4l2_pipeline_link_notify,
};
static int rkisp_get_reserved_mem(struct rkisp_device *isp_dev)
{
struct device *dev = isp_dev->dev;
struct device_node *np;
struct resource r;
int ret;
/* Get reserved memory region from Device-tree */
np = of_parse_phandle(dev->of_node, "memory-region-thunderboot", 0);
if (!np) {
dev_info(dev, "No memory-region-thunderboot specified\n");
return 0;
}
ret = of_address_to_resource(np, 0, &r);
if (ret) {
dev_err(dev, "No memory address assigned to the region\n");
return ret;
}
isp_dev->resmem_pa = r.start;
isp_dev->resmem_size = resource_size(&r);
isp_dev->resmem_addr = dma_map_single(dev, phys_to_virt(r.start),
sizeof(struct rkisp_thunderboot_resmem_head),
DMA_BIDIRECTIONAL);
ret = dma_mapping_error(dev, isp_dev->resmem_addr);
isp_dev->is_thunderboot = true;
isp_dev->is_rtt_suspend = false;
isp_dev->is_rtt_first = true;
if (device_property_read_bool(dev, "rtt-suspend")) {
isp_dev->is_rtt_suspend = true;
if (!isp_dev->hw_dev->is_thunderboot) {
isp_dev->is_thunderboot = false;
isp_dev->is_rtt_first = false;
}
}
dev_info(dev, "Allocated reserved memory, paddr: 0x%x\n", (u32)isp_dev->resmem_pa);
return ret;
}
static int rkisp_plat_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct v4l2_device *v4l2_dev;
struct rkisp_device *isp_dev;
int i, ret, mult = 1;
snprintf(rkisp_version, sizeof(rkisp_version),
"v%02x.%02x.%02x",
RKISP_DRIVER_VERSION >> 16,
(RKISP_DRIVER_VERSION & 0xff00) >> 8,
RKISP_DRIVER_VERSION & 0x00ff);
dev_info(dev, "rkisp driver version: %s\n", rkisp_version);
isp_dev = devm_kzalloc(dev, sizeof(*isp_dev), GFP_KERNEL);
if (!isp_dev)
return -ENOMEM;
dev_set_drvdata(dev, isp_dev);
isp_dev->dev = dev;
ret = rkisp_attach_hw(isp_dev);
if (ret)
return ret;
if (isp_dev->hw_dev->unite)
mult = ISP_UNITE_MAX;
isp_dev->sw_base_addr = devm_kzalloc(dev, RKISP_ISP_SW_MAX_SIZE * mult, GFP_KERNEL);
if (!isp_dev->sw_base_addr)
return -ENOMEM;
ret = rkisp_vs_irq_parse(dev);
if (ret)
return ret;
snprintf(isp_dev->media_dev.model, sizeof(isp_dev->media_dev.model),
"%s%d", DRIVER_NAME, isp_dev->dev_id);
if (!isp_dev->hw_dev->unite)
strscpy(isp_dev->name, dev_name(dev), sizeof(isp_dev->name));
else
snprintf(isp_dev->name, sizeof(isp_dev->name),
"%s%d", "rkisp-unite", isp_dev->dev_id);
strscpy(isp_dev->media_dev.driver_name, isp_dev->name,
sizeof(isp_dev->media_dev.driver_name));
ret = rkisp_get_reserved_mem(isp_dev);
if (ret)
return ret;
mutex_init(&isp_dev->apilock);
mutex_init(&isp_dev->iqlock);
atomic_set(&isp_dev->pipe.power_cnt, 0);
atomic_set(&isp_dev->pipe.stream_cnt, 0);
init_waitqueue_head(&isp_dev->sync_onoff);
isp_dev->pipe.open = rkisp_pipeline_open;
isp_dev->pipe.close = rkisp_pipeline_close;
isp_dev->pipe.set_stream = rkisp_pipeline_set_stream;
if (isp_dev->isp_ver == ISP_V20 || isp_dev->isp_ver == ISP_V21) {
atomic_set(&isp_dev->hdr.refcnt, 0);
for (i = 0; i < HDR_DMA_MAX; i++) {
INIT_LIST_HEAD(&isp_dev->hdr.q_tx[i]);
INIT_LIST_HEAD(&isp_dev->hdr.q_rx[i]);
}
}
isp_dev->media_dev.dev = dev;
isp_dev->media_dev.ops = &rkisp_media_ops;
v4l2_dev = &isp_dev->v4l2_dev;
v4l2_dev->mdev = &isp_dev->media_dev;
strlcpy(v4l2_dev->name, isp_dev->name, sizeof(v4l2_dev->name));
v4l2_ctrl_handler_init(&isp_dev->ctrl_handler, 5);
v4l2_dev->ctrl_handler = &isp_dev->ctrl_handler;
ret = v4l2_device_register(isp_dev->dev, &isp_dev->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register v4l2 device:%d\n", ret);
return ret;
}
media_device_init(&isp_dev->media_dev);
ret = media_device_register(&isp_dev->media_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register media device:%d\n", ret);
goto err_unreg_v4l2_dev;
}
pm_runtime_enable(dev);
/* create & register platefom subdev (from of_node) */
ret = rkisp_register_platform_subdevs(isp_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register platform subdevs:%d\n", ret);
goto err_unreg_media_dev;
}
rkisp_wait_line = 0;
of_property_read_u32(dev->of_node, "wait-line", &rkisp_wait_line);
rkisp_proc_init(isp_dev);
mutex_lock(&rkisp_dev_mutex);
list_add_tail(&isp_dev->list, &rkisp_device_list);
mutex_unlock(&rkisp_dev_mutex);
isp_dev->is_probe_end = true;
return 0;
err_unreg_media_dev:
media_device_unregister(&isp_dev->media_dev);
err_unreg_v4l2_dev:
v4l2_device_unregister(&isp_dev->v4l2_dev);
return ret;
}
static int rkisp_plat_remove(struct platform_device *pdev)
{
struct rkisp_device *isp_dev = platform_get_drvdata(pdev);
isp_dev->is_hw_link = false;
isp_dev->hw_dev->isp[isp_dev->dev_id] = NULL;
pm_runtime_disable(&pdev->dev);
rkisp_proc_cleanup(isp_dev);
media_device_unregister(&isp_dev->media_dev);
v4l2_async_nf_unregister(&isp_dev->notifier);
v4l2_async_nf_cleanup(&isp_dev->notifier);
v4l2_device_unregister(&isp_dev->v4l2_dev);
v4l2_ctrl_handler_free(&isp_dev->ctrl_handler);
rkisp_unregister_pdaf_vdev(isp_dev);
rkisp_unregister_luma_vdev(&isp_dev->luma_vdev);
rkisp_unregister_params_vdev(&isp_dev->params_vdev);
rkisp_unregister_stats_vdev(&isp_dev->stats_vdev);
rkisp_unregister_dmarx_vdev(isp_dev);
rkisp_unregister_stream_vdevs(isp_dev);
rkisp_unregister_bridge_subdev(isp_dev);
rkisp_unregister_csi_subdev(isp_dev);
rkisp_unregister_isp_subdev(isp_dev);
media_device_cleanup(&isp_dev->media_dev);
return 0;
}
static int __maybe_unused rkisp_runtime_suspend(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
int ret;
mutex_lock(&isp_dev->hw_dev->dev_lock);
ret = pm_runtime_put_sync(isp_dev->hw_dev->dev);
mutex_unlock(&isp_dev->hw_dev->dev_lock);
return (ret > 0) ? 0 : ret;
}
static int __maybe_unused rkisp_runtime_resume(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
int ret;
/* power on to config default format from sensor */
if (isp_dev->isp_inp & (INP_CSI | INP_DVP | INP_LVDS | INP_CIF) &&
rkisp_update_sensor_info(isp_dev) >= 0)
_set_pipeline_default_fmt(isp_dev, false);
isp_dev->cap_dev.wrap_line = rkisp_wrap_line;
mutex_lock(&isp_dev->hw_dev->dev_lock);
ret = pm_runtime_get_sync(isp_dev->hw_dev->dev);
mutex_unlock(&isp_dev->hw_dev->dev_lock);
return (ret > 0) ? 0 : ret;
}
#ifndef MODULE
static int __init rkisp_clr_unready_dev(void)
{
__rkisp_clr_unready_dev();
return 0;
}
late_initcall_sync(rkisp_clr_unready_dev);
#endif
static int rkisp_pm_prepare(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
struct rkisp_hw_dev *hw = isp_dev->hw_dev;
struct rkisp_pipeline *p = &isp_dev->pipe;
unsigned long lock_flags = 0;
int i, on = 0, time = 100;
if (isp_dev->isp_state & ISP_STOP) {
if (pm_runtime_active(dev) &&
rkisp_link_sensor(isp_dev->isp_inp)) {
struct v4l2_subdev *mipi_sensor = NULL;
rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR);
if (mipi_sensor)
v4l2_subdev_call(mipi_sensor, core, s_power, 0);
}
return 0;
}
isp_dev->suspend_sync = false;
isp_dev->is_suspend = true;
if (rkisp_link_sensor(isp_dev->isp_inp)) {
for (i = p->num_subdevs - 1; i >= 0; i--)
v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
} else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) {
v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on);
}
if (IS_HDR_RDBK(isp_dev->rd_mode)) {
spin_lock_irqsave(&hw->rdbk_lock, lock_flags);
if (!hw->is_idle && hw->cur_dev_id == isp_dev->dev_id)
isp_dev->suspend_sync = true;
spin_unlock_irqrestore(&hw->rdbk_lock, lock_flags);
}
if (isp_dev->suspend_sync) {
wait_for_completion_timeout(&isp_dev->pm_cmpl, msecs_to_jiffies(time));
isp_dev->suspend_sync = false;
}
if (rkisp_link_sensor(isp_dev->isp_inp)) {
for (i = p->num_subdevs - 1; i >= 0; i--)
v4l2_subdev_call(p->subdevs[i], core, s_power, 0);
}
return 0;
}
static int rkisp_resume(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
struct rkisp_hw_dev *hw = isp_dev->hw_dev;
struct rkisp_pipeline *p = &isp_dev->pipe;
struct rkisp_stream *stream;
struct rkisp_device *isp_tmp;
int i, on = 1, rd_mode = isp_dev->rd_mode;
u32 val;
if (isp_dev->isp_state & ISP_STOP) {
if (pm_runtime_active(dev) &&
rkisp_link_sensor(isp_dev->isp_inp)) {
struct v4l2_subdev *mipi_sensor = NULL;
rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR);
if (mipi_sensor)
v4l2_subdev_call(mipi_sensor, core, s_power, 1);
}
return 0;
}
if (isp_dev->is_rtt_suspend) {
rkisp_save_tb_info(isp_dev);
v4l2_info(&isp_dev->v4l2_dev,
"tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d mode:%d\n",
isp_dev->tb_head.enable, isp_dev->tb_head.complete,
isp_dev->tb_head.frm_total, isp_dev->tb_head.width,
isp_dev->tb_head.height, isp_dev->tb_head.camera_num,
isp_dev->tb_head.camera_index, isp_dev->tb_head.rtt_mode);
isp_dev->is_first_double = false;
switch (isp_dev->tb_head.rtt_mode) {
case RKISP_RTT_MODE_ONE_FRAME:
isp_dev->is_first_double = true;
/* switch to readback mode */
switch (rd_mode) {
case HDR_LINEX3_DDR:
isp_dev->rd_mode = HDR_RDBK_FRAME3;
break;
case HDR_LINEX2_DDR:
isp_dev->rd_mode = HDR_RDBK_FRAME2;
break;
default:
isp_dev->rd_mode = HDR_RDBK_FRAME1;
}
break;
case RKISP_RTT_MODE_MULTI_FRAME:
default:
if (isp_dev->tb_head.rtt_mode != RKISP_RTT_MODE_MULTI_FRAME)
v4l2_warn(&isp_dev->v4l2_dev,
"invalid rtt mode:%d, change to mode:%d\n",
isp_dev->tb_head.rtt_mode, RKISP_RTT_MODE_MULTI_FRAME);
if (!hw->is_single)
break;
/* switch to online mode for single sensor */
switch (rd_mode) {
case HDR_RDBK_FRAME3:
isp_dev->rd_mode = HDR_LINEX3_DDR;
break;
case HDR_RDBK_FRAME2:
isp_dev->rd_mode = HDR_LINEX2_DDR;
break;
default:
isp_dev->rd_mode = HDR_NORMAL;
}
}
isp_dev->hdr.op_mode = isp_dev->rd_mode;
if (rd_mode != isp_dev->rd_mode && hw->cur_dev_id == isp_dev->dev_id) {
rkisp_unite_write(isp_dev, CSI2RX_CTRL0,
SW_IBUF_OP_MODE(isp_dev->rd_mode), true);
if (IS_HDR_RDBK(isp_dev->rd_mode))
rkisp_unite_set_bits(isp_dev, CTRL_SWS_CFG, 0,
SW_MPIP_DROP_FRM_DIS, true);
else
rkisp_unite_clear_bits(isp_dev, CTRL_SWS_CFG,
SW_MPIP_DROP_FRM_DIS, true);
}
}
isp_dev->is_suspend = false;
isp_dev->isp_state = ISP_START | ISP_FRAME_END;
if (!hw->is_single && hw->is_multi_overflow)
hw->pre_dev_id++;
if (isp_dev->is_suspend_one_frame &&
!hw->is_multi_overflow && hw->isp_ver < ISP_V33)
isp_dev->is_first_double = true;
if (hw->isp_ver > ISP_V20 && hw->isp_ver < ISP_V33) {
val = ISP3X_YNR_FST_FRAME | ISP3X_CNR_FST_FRAME |
ISP3X_DHAZ_FST_FRAME | ISP3X_ADRC_FST_FRAME;
if (hw->isp_ver == ISP_V32)
val |= ISP32_SHP_FST_FRAME;
rkisp_unite_set_bits(isp_dev, ISP3X_ISP_CTRL1, 0, val, false);
}
for (i = 0; i < RKISP_MAX_STREAM; i++) {
stream = &isp_dev->cap_dev.stream[i];
if (i == RKISP_STREAM_VIR || !stream->streaming)
continue;
/* skip first frame due to hw no reference frame information */
if (isp_dev->is_first_double)
stream->skip_frame = 1;
}
if (hw->cur_dev_id == isp_dev->dev_id) {
if (atomic_read(&hw->refcnt) == 2) {
/* isp0 online, isp1 offline, isp0 to running first */
isp_tmp = hw->isp[!isp_dev->dev_id];
if (isp_dev->dev_id && !(IS_HDR_RDBK(isp_tmp->rd_mode)))
hw->is_idle = false;
}
rkisp_rdbk_trigger_event(isp_dev, T_CMD_QUEUE, NULL);
}
if (rkisp_link_sensor(isp_dev->isp_inp)) {
for (i = 0; i < p->num_subdevs; i++)
v4l2_subdev_call(p->subdevs[i], core, s_power, 1);
for (i = 0; i < p->num_subdevs; i++)
v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
} else if (isp_dev->isp_inp & INP_CIF && !IS_HDR_RDBK(isp_dev->rd_mode)) {
if (!hw->is_single) {
int on = 1;
if (atomic_read(&hw->refcnt) == 2) {
/* isp0 and isp1 online, isp1 to running first */
isp_tmp = hw->isp[!isp_dev->dev_id];
if (!IS_HDR_RDBK(isp_tmp->rd_mode) && !isp_dev->dev_id)
on = 0;
} else if (isp_dev->unite_div == ISP_UNITE_DIV2) {
isp_dev->unite_index = ISP_UNITE_LEFT;
isp_dev->params_vdev.rdbk_times = 2;
}
if (on) {
hw->cur_dev_id = isp_dev->dev_id;
hw->is_idle = false;
rkisp_online_update_reg(isp_dev, false, true);
rkisp_vicap_hw_link(isp_dev, on);
}
}
v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on);
}
return 0;
}
static int rkisp_pm_resume(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
if (isp_dev->isp_ver == ISP_V33)
return rkisp_resume(dev);
return 0;
}
static void rkisp_pm_complete(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
if (isp_dev->isp_ver == ISP_V33)
return;
rkisp_resume(dev);
}
static const struct dev_pm_ops rkisp_plat_pm_ops = {
.prepare = rkisp_pm_prepare,
.resume = rkisp_pm_resume,
.complete = rkisp_pm_complete,
SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, rkisp_runtime_resume, NULL)
};
static const struct of_device_id rkisp_plat_of_match[] = {
{
.compatible = "rockchip,rkisp-vir",
}, {
.compatible = "rockchip,rv1126-rkisp-vir",
},
{},
};
struct platform_driver rkisp_plat_drv = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(rkisp_plat_of_match),
.pm = &rkisp_plat_pm_ops,
},
.probe = rkisp_plat_probe,
.remove = rkisp_plat_remove,
};
MODULE_AUTHOR("Rockchip Camera/ISP team");
MODULE_DESCRIPTION("Rockchip ISP platform driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(DMA_BUF);
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);