mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
video: rockchip: vehicle: add fast reverse camera driver
Signed-off-by: Jianwei Fan <jianwei.fan@rock-chips.com> Change-Id: I3c53046462000eaac645b2e5f0ef30b666b3f543
This commit is contained in:
@@ -6,3 +6,4 @@ source "drivers/video/rockchip/rve/Kconfig"
|
||||
source "drivers/video/rockchip/iep/Kconfig"
|
||||
source "drivers/video/rockchip/mpp/Kconfig"
|
||||
source "drivers/video/rockchip/dvbm/Kconfig"
|
||||
source "drivers/video/rockchip/vehicle/Kconfig"
|
||||
|
||||
@@ -6,3 +6,4 @@ obj-$(CONFIG_ROCKCHIP_RVE) += rve/
|
||||
obj-$(CONFIG_IEP) += iep/
|
||||
obj-$(CONFIG_ROCKCHIP_MPP_SERVICE) += mpp/
|
||||
obj-$(CONFIG_ROCKCHIP_DVBM) += dvbm/
|
||||
obj-$(CONFIG_VIDEO_REVERSE_IMAGE) += vehicle/
|
||||
|
||||
41
drivers/video/rockchip/vehicle/Kconfig
Normal file
41
drivers/video/rockchip/vehicle/Kconfig
Normal file
@@ -0,0 +1,41 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
config VIDEO_REVERSE_IMAGE
|
||||
bool "Rockchip Fast Reverse Image driver"
|
||||
depends on ARCH_ROCKCHIP && ROCKCHIP_DRM_DIRECT_SHOW
|
||||
depends on VIDEO_ROCKCHIP_CIF && PHY_ROCKCHIP_CSI2_DPHY
|
||||
help
|
||||
fast reverse Image module.
|
||||
|
||||
if VIDEO_REVERSE_IMAGE
|
||||
|
||||
config VIDEO_REVERSE_NVP6324
|
||||
bool "nvp6324 for reverse sensor"
|
||||
help
|
||||
Say y if use nvp6324.
|
||||
|
||||
config VIDEO_REVERSE_NVP6188
|
||||
bool "nvp6188 for reverse sensor"
|
||||
help
|
||||
Say y if use nvp6188.
|
||||
|
||||
config VIDEO_REVERSE_MAX96714
|
||||
bool "max96714 for reverse sensor"
|
||||
help
|
||||
Say y if use max96714.
|
||||
|
||||
config VIDEO_REVERSE_GC2145
|
||||
bool "gc2145 for reverse sensor"
|
||||
help
|
||||
Say y if use gc2145.
|
||||
|
||||
config VIDEO_REVERSE_TP2825
|
||||
bool "tp2825 for reverse sensor"
|
||||
help
|
||||
Say y if use tp2825.
|
||||
|
||||
config VIDEO_REVERSE_AD7181
|
||||
bool "ad7181 for reverse sensor"
|
||||
help
|
||||
Say y if use ad7181.
|
||||
|
||||
endif
|
||||
26
drivers/video/rockchip/vehicle/Makefile
Normal file
26
drivers/video/rockchip/vehicle/Makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_VIDEO_REVERSE_IMAGE) += video_rkvehicle.o
|
||||
video_rkvehicle-objs += vehicle_flinger.o \
|
||||
vehicle_dev.o \
|
||||
vehicle_main.o \
|
||||
vehicle_cif.o \
|
||||
vehicle_generic_sensor.o \
|
||||
vehicle_gpio.o \
|
||||
|
||||
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_NVP6324) += \
|
||||
vehicle_ad_nvp6324.o
|
||||
|
||||
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_NVP6188) += \
|
||||
vehicle_ad_nvp6188.o
|
||||
|
||||
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_MAX96714) += \
|
||||
vehicle_ad_max96714.o
|
||||
|
||||
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_GC2145) += \
|
||||
vehicle_ad_gc2145.o
|
||||
|
||||
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_TP2825) += \
|
||||
vehicle_ad_tp2825.o
|
||||
|
||||
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_AD7181) += \
|
||||
vehicle_ad_7181.o
|
||||
362
drivers/video/rockchip/vehicle/vehicle-csi2-dphy-common.h
Normal file
362
drivers/video/rockchip/vehicle/vehicle-csi2-dphy-common.h
Normal file
@@ -0,0 +1,362 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _VEHICLE_CSI2_DPHY_COMMON_H_
|
||||
#define _VEHICLE_CSI2_DPHY_COMMON_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include "vehicle_samsung_dcphy_common.h"
|
||||
#include "../../../media/platform/rockchip/cif/mipi-csi2.h"
|
||||
|
||||
/* GRF REG OFFSET */
|
||||
#define GRF_VI_CON0 (0x0340)
|
||||
#define GRF_VI_CON1 (0x0344)
|
||||
|
||||
/*RK3588 DPHY GRF REG OFFSET */
|
||||
#define GRF_DPHY_CON0 (0x0)
|
||||
#define GRF_SOC_CON2 (0x0308)
|
||||
|
||||
/*GRF REG BIT DEFINE */
|
||||
#define GRF_CSI2PHY_LANE_SEL_SPLIT (0x1)
|
||||
#define GRF_CSI2PHY_SEL_SPLIT_0_1 (0x0)
|
||||
#define GRF_CSI2PHY_SEL_SPLIT_2_3 BIT(0)
|
||||
|
||||
/*RK3588 DCPHY GRF REG OFFSET */
|
||||
#define GRF_DCPHY_CON0 (0x0)
|
||||
|
||||
/* PHY REG OFFSET */
|
||||
#define CSI2_DPHY_CTRL_INVALID_OFFSET (0xffff)
|
||||
#define CSI2_DPHY_CTRL_PWRCTL \
|
||||
CSI2_DPHY_CTRL_INVALID_OFFSET
|
||||
#define CSI2_DPHY_CTRL_LANE_ENABLE (0x00)
|
||||
#define CSI2_DPHY_CLK1_LANE_EN (0x2C)
|
||||
#define CSI2_DPHY_DUAL_CAL_EN (0x80)
|
||||
#define CSI2_DPHY_CLK_WR_THS_SETTLE (0x160)
|
||||
#define CSI2_DPHY_CLK_CALIB_EN (0x168)
|
||||
#define CSI2_DPHY_LANE0_WR_THS_SETTLE (0x1e0)
|
||||
#define CSI2_DPHY_LANE0_CALIB_EN (0x1e8)
|
||||
#define CSI2_DPHY_LANE1_WR_THS_SETTLE (0x260)
|
||||
#define CSI2_DPHY_LANE1_CALIB_EN (0x268)
|
||||
#define CSI2_DPHY_LANE2_WR_THS_SETTLE (0x2e0)
|
||||
#define CSI2_DPHY_LANE2_CALIB_EN (0x2e8)
|
||||
#define CSI2_DPHY_LANE3_WR_THS_SETTLE (0x360)
|
||||
#define CSI2_DPHY_LANE3_CALIB_EN (0x368)
|
||||
#define CSI2_DPHY_CLK1_WR_THS_SETTLE (0x3e0)
|
||||
#define CSI2_DPHY_CLK1_CALIB_EN (0x3e8)
|
||||
|
||||
//DCPHY
|
||||
#define CSI2_DCPHY_CLK_WR_THS_SETTLE (0x030)
|
||||
#define CSI2_DCPHY_LANE0_WR_THS_SETTLE (0x130)
|
||||
#define CSI2_DCPHY_LANE0_WR_ERR_SOT_SYNC (0x134)
|
||||
#define CSI2_DCPHY_LANE1_WR_THS_SETTLE (0x230)
|
||||
#define CSI2_DCPHY_LANE1_WR_ERR_SOT_SYNC (0x234)
|
||||
#define CSI2_DCPHY_LANE2_WR_THS_SETTLE (0x330)
|
||||
#define CSI2_DCPHY_LANE2_WR_ERR_SOT_SYNC (0x334)
|
||||
#define CSI2_DCPHY_LANE3_WR_THS_SETTLE (0x430)
|
||||
#define CSI2_DCPHY_LANE3_WR_ERR_SOT_SYNC (0x434)
|
||||
#define CSI2_DCPHY_CLK_LANE_ENABLE (0x000)
|
||||
#define CSI2_DCPHY_DATA_LANE0_ENABLE (0x100)
|
||||
#define CSI2_DCPHY_DATA_LANE1_ENABLE (0x200)
|
||||
#define CSI2_DCPHY_DATA_LANE2_ENABLE (0x300)
|
||||
#define CSI2_DCPHY_DATA_LANE3_ENABLE (0x400)
|
||||
|
||||
#define CSI2_DCPHY_S0C_GNR_CON1 (0x004)
|
||||
#define CSI2_DCPHY_S0C_ANA_CON1 (0x00c)
|
||||
#define CSI2_DCPHY_S0C_ANA_CON2 (0x010)
|
||||
#define CSI2_DCPHY_S0C_ANA_CON3 (0x014)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_GNR_CON1 (0x104)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON1 (0x10c)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON2 (0x110)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON3 (0x114)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON6 (0x120)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON7 (0x124)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_DESKEW_CON0 (0x140)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_DESKEW_CON2 (0x148)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_DESKEW_CON4 (0x150)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_CRC_CON1 (0x164)
|
||||
#define CSI2_DCPHY_COMBO_S0D0_CRC_CON2 (0x168)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_GNR_CON1 (0x204)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON1 (0x20c)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON2 (0x210)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON3 (0x214)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON6 (0x220)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON7 (0x224)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_DESKEW_CON0 (0x240)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_DESKEW_CON2 (0x248)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_DESKEW_CON4 (0x250)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_CRC_CON1 (0x264)
|
||||
#define CSI2_DCPHY_COMBO_S0D1_CRC_CON2 (0x268)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_GNR_CON1 (0x304)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON1 (0x30c)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON2 (0x310)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON3 (0x314)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON6 (0x320)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON7 (0x324)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_DESKEW_CON0 (0x340)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_DESKEW_CON2 (0x348)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_DESKEW_CON4 (0x350)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_CRC_CON1 (0x364)
|
||||
#define CSI2_DCPHY_COMBO_S0D2_CRC_CON2 (0x368)
|
||||
#define CSI2_DCPHY_S0D3_GNR_CON1 (0x404)
|
||||
#define CSI2_DCPHY_S0D3_ANA_CON1 (0x40c)
|
||||
#define CSI2_DCPHY_S0D3_ANA_CON2 (0x410)
|
||||
#define CSI2_DCPHY_S0D3_ANA_CON3 (0x414)
|
||||
#define CSI2_DCPHY_S0D3_DESKEW_CON0 (0x440)
|
||||
#define CSI2_DCPHY_S0D3_DESKEW_CON2 (0x448)
|
||||
#define CSI2_DCPHY_S0D3_DESKEW_CON4 (0x450)
|
||||
|
||||
/* PHY REG BIT DEFINE */
|
||||
#define CSI2_DPHY_LANE_MODE_FULL (0x4)
|
||||
#define CSI2_DPHY_LANE_MODE_SPLIT (0x2)
|
||||
#define CSI2_DPHY_LANE_SPLIT_TOP (0x1)
|
||||
#define CSI2_DPHY_LANE_SPLIT_BOT (0x2)
|
||||
#define CSI2_DPHY_LANE_SPLIT_LANE0_1 (0x3 << 2)
|
||||
#define CSI2_DPHY_LANE_SPLIT_LANE2_3 (0x3 << 4)
|
||||
#define CSI2_DPHY_LANE_DUAL_MODE_EN BIT(6)
|
||||
#define CSI2_DPHY_LANE_PARA_ARR_NUM (0x2)
|
||||
|
||||
#define CSI2_DPHY_CTRL_DATALANE_ENABLE_OFFSET_BIT 2
|
||||
#define CSI2_DPHY_CTRL_DATALANE_SPLIT_LANE2_3_OFFSET_BIT 4
|
||||
#define CSI2_DPHY_CTRL_CLKLANE_ENABLE_OFFSET_BIT 6
|
||||
|
||||
enum csi2_dphy_index {
|
||||
DPHY0 = 0x0,
|
||||
DPHY1,
|
||||
DPHY2,
|
||||
};
|
||||
|
||||
enum csi2_dphy_lane {
|
||||
CSI2_DPHY_LANE_CLOCK = 0,
|
||||
CSI2_DPHY_LANE_CLOCK1,
|
||||
CSI2_DPHY_LANE_DATA0,
|
||||
CSI2_DPHY_LANE_DATA1,
|
||||
CSI2_DPHY_LANE_DATA2,
|
||||
CSI2_DPHY_LANE_DATA3
|
||||
};
|
||||
|
||||
enum grf_reg_id {
|
||||
GRF_DPHY_RX0_TURNDISABLE = 0,
|
||||
GRF_DPHY_RX0_FORCERXMODE,
|
||||
GRF_DPHY_RX0_FORCETXSTOPMODE,
|
||||
GRF_DPHY_RX0_ENABLE,
|
||||
GRF_DPHY_RX0_TESTCLR,
|
||||
GRF_DPHY_RX0_TESTCLK,
|
||||
GRF_DPHY_RX0_TESTEN,
|
||||
GRF_DPHY_RX0_TESTDIN,
|
||||
GRF_DPHY_RX0_TURNREQUEST,
|
||||
GRF_DPHY_RX0_TESTDOUT,
|
||||
GRF_DPHY_TX0_TURNDISABLE,
|
||||
GRF_DPHY_TX0_FORCERXMODE,
|
||||
GRF_DPHY_TX0_FORCETXSTOPMODE,
|
||||
GRF_DPHY_TX0_TURNREQUEST,
|
||||
GRF_DPHY_TX1RX1_TURNDISABLE,
|
||||
GRF_DPHY_TX1RX1_FORCERXMODE,
|
||||
GRF_DPHY_TX1RX1_FORCETXSTOPMODE,
|
||||
GRF_DPHY_TX1RX1_ENABLE,
|
||||
GRF_DPHY_TX1RX1_MASTERSLAVEZ,
|
||||
GRF_DPHY_TX1RX1_BASEDIR,
|
||||
GRF_DPHY_TX1RX1_ENABLECLK,
|
||||
GRF_DPHY_TX1RX1_TURNREQUEST,
|
||||
GRF_DPHY_RX1_SRC_SEL,
|
||||
/* rk3288 only */
|
||||
GRF_CON_DISABLE_ISP,
|
||||
GRF_CON_ISP_DPHY_SEL,
|
||||
GRF_DSI_CSI_TESTBUS_SEL,
|
||||
GRF_DVP_V18SEL,
|
||||
/* rk1808 & rk3326 & rv1126 */
|
||||
GRF_DPHY_CSI2PHY_FORCERXMODE,
|
||||
GRF_DPHY_CSI2PHY_CLKLANE_EN,
|
||||
GRF_DPHY_CSI2PHY_DATALANE_EN,
|
||||
/* rv1126 only */
|
||||
GRF_DPHY_CLK_INV_SEL,
|
||||
GRF_DPHY_SEL,
|
||||
/* rk3368 only */
|
||||
GRF_ISP_MIPI_CSI_HOST_SEL,
|
||||
/* below is for rk3399 only */
|
||||
GRF_DPHY_RX0_CLK_INV_SEL,
|
||||
GRF_DPHY_RX1_CLK_INV_SEL,
|
||||
GRF_DPHY_TX1RX1_SRC_SEL,
|
||||
/* below is for rk3568 only */
|
||||
GRF_DPHY_CSI2PHY_CLKLANE1_EN,
|
||||
GRF_DPHY_CLK1_INV_SEL,
|
||||
GRF_DPHY_ISP_CSI2PHY_SEL,
|
||||
GRF_DPHY_CIF_CSI2PHY_SEL,
|
||||
GRF_DPHY_CSI2PHY_LANE_SEL,
|
||||
GRF_DPHY_CSI2PHY1_LANE_SEL,
|
||||
GRF_DPHY_CSI2PHY_DATALANE_EN0,
|
||||
GRF_DPHY_CSI2PHY_DATALANE_EN1,
|
||||
GRF_CPHY_MODE,
|
||||
GRF_DPHY_CSIHOST2_SEL,
|
||||
GRF_DPHY_CSIHOST3_SEL,
|
||||
GRF_DPHY_CSIHOST4_SEL,
|
||||
GRF_DPHY_CSIHOST5_SEL,
|
||||
};
|
||||
|
||||
enum csi2dphy_reg_id {
|
||||
CSI2PHY_REG_CTRL_LANE_ENABLE = 0,
|
||||
CSI2PHY_CTRL_PWRCTL,
|
||||
CSI2PHY_CTRL_DIG_RST,
|
||||
CSI2PHY_CLK_THS_SETTLE,
|
||||
CSI2PHY_LANE0_THS_SETTLE,
|
||||
CSI2PHY_LANE1_THS_SETTLE,
|
||||
CSI2PHY_LANE2_THS_SETTLE,
|
||||
CSI2PHY_LANE3_THS_SETTLE,
|
||||
CSI2PHY_CLK_CALIB_ENABLE,
|
||||
CSI2PHY_LANE0_CALIB_ENABLE,
|
||||
CSI2PHY_LANE1_CALIB_ENABLE,
|
||||
CSI2PHY_LANE2_CALIB_ENABLE,
|
||||
CSI2PHY_LANE3_CALIB_ENABLE,
|
||||
//rv1126 only
|
||||
CSI2PHY_MIPI_LVDS_MODEL,
|
||||
CSI2PHY_LVDS_MODE,
|
||||
//rk3568 only
|
||||
CSI2PHY_DUAL_CLK_EN,
|
||||
CSI2PHY_CLK1_THS_SETTLE,
|
||||
CSI2PHY_CLK1_CALIB_ENABLE,
|
||||
//rk3588
|
||||
CSI2PHY_CLK_LANE_ENABLE,
|
||||
CSI2PHY_CLK1_LANE_ENABLE,
|
||||
CSI2PHY_DATA_LANE0_ENABLE,
|
||||
CSI2PHY_DATA_LANE1_ENABLE,
|
||||
CSI2PHY_DATA_LANE2_ENABLE,
|
||||
CSI2PHY_DATA_LANE3_ENABLE,
|
||||
CSI2PHY_LANE0_ERR_SOT_SYNC,
|
||||
CSI2PHY_LANE1_ERR_SOT_SYNC,
|
||||
CSI2PHY_LANE2_ERR_SOT_SYNC,
|
||||
CSI2PHY_LANE3_ERR_SOT_SYNC,
|
||||
CSI2PHY_S0C_GNR_CON1,
|
||||
CSI2PHY_S0C_ANA_CON1,
|
||||
CSI2PHY_S0C_ANA_CON2,
|
||||
CSI2PHY_S0C_ANA_CON3,
|
||||
CSI2PHY_COMBO_S0D0_GNR_CON1,
|
||||
CSI2PHY_COMBO_S0D0_ANA_CON1,
|
||||
CSI2PHY_COMBO_S0D0_ANA_CON2,
|
||||
CSI2PHY_COMBO_S0D0_ANA_CON3,
|
||||
CSI2PHY_COMBO_S0D0_ANA_CON6,
|
||||
CSI2PHY_COMBO_S0D0_ANA_CON7,
|
||||
CSI2PHY_COMBO_S0D0_DESKEW_CON0,
|
||||
CSI2PHY_COMBO_S0D0_DESKEW_CON2,
|
||||
CSI2PHY_COMBO_S0D0_DESKEW_CON4,
|
||||
CSI2PHY_COMBO_S0D0_CRC_CON1,
|
||||
CSI2PHY_COMBO_S0D0_CRC_CON2,
|
||||
CSI2PHY_COMBO_S0D1_GNR_CON1,
|
||||
CSI2PHY_COMBO_S0D1_ANA_CON1,
|
||||
CSI2PHY_COMBO_S0D1_ANA_CON2,
|
||||
CSI2PHY_COMBO_S0D1_ANA_CON3,
|
||||
CSI2PHY_COMBO_S0D1_ANA_CON6,
|
||||
CSI2PHY_COMBO_S0D1_ANA_CON7,
|
||||
CSI2PHY_COMBO_S0D1_DESKEW_CON0,
|
||||
CSI2PHY_COMBO_S0D1_DESKEW_CON2,
|
||||
CSI2PHY_COMBO_S0D1_DESKEW_CON4,
|
||||
CSI2PHY_COMBO_S0D1_CRC_CON1,
|
||||
CSI2PHY_COMBO_S0D1_CRC_CON2,
|
||||
CSI2PHY_COMBO_S0D2_GNR_CON1,
|
||||
CSI2PHY_COMBO_S0D2_ANA_CON1,
|
||||
CSI2PHY_COMBO_S0D2_ANA_CON2,
|
||||
CSI2PHY_COMBO_S0D2_ANA_CON3,
|
||||
CSI2PHY_COMBO_S0D2_ANA_CON6,
|
||||
CSI2PHY_COMBO_S0D2_ANA_CON7,
|
||||
CSI2PHY_COMBO_S0D2_DESKEW_CON0,
|
||||
CSI2PHY_COMBO_S0D2_DESKEW_CON2,
|
||||
CSI2PHY_COMBO_S0D2_DESKEW_CON4,
|
||||
CSI2PHY_COMBO_S0D2_CRC_CON1,
|
||||
CSI2PHY_COMBO_S0D2_CRC_CON2,
|
||||
CSI2PHY_S0D3_GNR_CON1,
|
||||
CSI2PHY_S0D3_ANA_CON1,
|
||||
CSI2PHY_S0D3_ANA_CON2,
|
||||
CSI2PHY_S0D3_ANA_CON3,
|
||||
CSI2PHY_S0D3_DESKEW_CON0,
|
||||
CSI2PHY_S0D3_DESKEW_CON2,
|
||||
CSI2PHY_S0D3_DESKEW_CON4,
|
||||
};
|
||||
|
||||
#define HIWORD_UPDATE(val, mask, shift) \
|
||||
((val) << (shift) | (mask) << ((shift) + 16))
|
||||
|
||||
#define GRF_REG(_offset, _width, _shift) \
|
||||
{ .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
|
||||
|
||||
#define CSI2PHY_REG(_offset) \
|
||||
{ .offset = _offset, }
|
||||
|
||||
/* add new chip id in tail by time order */
|
||||
enum csi2_dphy_chip_id {
|
||||
CHIP_ID_RK3568 = 0x0,
|
||||
CHIP_ID_RK3588 = 0x1,
|
||||
CHIP_ID_RK3588_DCPHY = 0x2,
|
||||
};
|
||||
|
||||
enum csi2_dphy_rx_pads {
|
||||
CSI2_DPHY_RX_PAD_SINK = 0,
|
||||
CSI2_DPHY_RX_PAD_SOURCE,
|
||||
CSI2_DPHY_RX_PADS_NUM,
|
||||
};
|
||||
|
||||
enum csi2_dphy_lane_mode {
|
||||
LANE_MODE_UNDEF = 0x0,
|
||||
LANE_MODE_FULL,
|
||||
LANE_MODE_SPLIT,
|
||||
};
|
||||
|
||||
struct grf_reg {
|
||||
u32 offset;
|
||||
u32 mask;
|
||||
u32 shift;
|
||||
};
|
||||
|
||||
struct csi2dphy_reg {
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
struct hsfreq_range {
|
||||
u32 range_h;
|
||||
u16 cfg_bit;
|
||||
};
|
||||
|
||||
#define MAX_DPHY_SENSORS (2)
|
||||
#define MAX_NUM_CSI2_DPHY (0x2)
|
||||
|
||||
#define RKCSI2_MAX_RESET 8
|
||||
#define RKDPHY_MAX_RESET 8
|
||||
/* csi2 head */
|
||||
|
||||
struct csi2_dphy_hw {
|
||||
struct clk_bulk_data *dphy_clks;
|
||||
int num_dphy_clks;
|
||||
struct clk_bulk_data *csi2_clks;
|
||||
int num_csi2_clks;
|
||||
const char * const *csi2_rsts;
|
||||
struct reset_control *csi2_rst[RKCSI2_MAX_RESET];
|
||||
int num_csi2_rsts;
|
||||
const char * const *dphy_rsts;
|
||||
struct reset_control *dphy_rst[RKDPHY_MAX_RESET];
|
||||
int num_dphy_rsts;
|
||||
// struct reset_control *rsts_bulk;
|
||||
/* spinlock_t lock; */
|
||||
bool on;
|
||||
const struct hsfreq_range *hsfreq_ranges;
|
||||
int num_hsfreq_ranges;
|
||||
const struct grf_reg *grf_regs;
|
||||
const struct txrx_reg *txrx_regs;
|
||||
const struct csi2dphy_reg *csi2dphy_regs;
|
||||
enum csi2_dphy_chip_id chip_id;
|
||||
struct device *dev;
|
||||
struct regmap *regmap_grf;
|
||||
struct regmap *regmap_sys_grf;
|
||||
void __iomem *csi2_dphy_base; /*csi2_dphy base addr*/
|
||||
void __iomem *csi2_base; /*csi2 base addr*/
|
||||
struct mutex mutex; /* lock for updating protection */
|
||||
atomic_t stream_cnt;
|
||||
struct csi2_err_stats err_list[RK_CSI2_ERR_MAX];
|
||||
u64 data_rate_mbps;
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
struct samsung_mipi_dcphy *samsung_phy;
|
||||
};
|
||||
|
||||
#endif
|
||||
82
drivers/video/rockchip/vehicle/vehicle_ad.h
Normal file
82
drivers/video/rockchip/vehicle/vehicle_ad.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_AD_COMMON_H
|
||||
#define __VEHICLE_AD_COMMON_H
|
||||
#include <linux/i2c.h>
|
||||
#include "vehicle_cfg.h"
|
||||
#include <linux/rk-camera-module.h>
|
||||
|
||||
enum vehicle_ad_fix_format {
|
||||
AD_FIX_FORMAT_AUTO_DETECT = 0,
|
||||
AD_FIX_FORMAT_PAL = 1,
|
||||
AD_FIX_FORMAT_NTSC = 2,
|
||||
AD_FIX_FORMAT_720P_50FPS = 3,
|
||||
AD_FIX_FORMAT_720P_30FPS = 4,
|
||||
AD_FIX_FORMAT_720P_25FPS = 5,
|
||||
AD_FIX_FORMAT_1080P_30FPS = 6,
|
||||
AD_FIX_FORMAT_1080P_25FPS = 7,
|
||||
};
|
||||
|
||||
struct vehicle_camera_device_defrect {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int crop_x;
|
||||
unsigned int crop_y;
|
||||
unsigned int crop_width;
|
||||
unsigned int crop_height;
|
||||
const char *interface;
|
||||
};
|
||||
|
||||
struct vehicle_state_check_work {
|
||||
struct workqueue_struct *state_check_wq;
|
||||
struct delayed_work work;
|
||||
};
|
||||
|
||||
struct vehicle_ad_dev {
|
||||
struct device *dev;
|
||||
struct i2c_adapter *adapter;
|
||||
const char *ad_name;
|
||||
int resolution;
|
||||
int mclk_rate;
|
||||
int ad_chl;
|
||||
int i2c_chl;
|
||||
int i2c_add;
|
||||
// int i2c_rate;
|
||||
int powerdown;
|
||||
int pwdn_active;
|
||||
int power;
|
||||
int pwr_active;
|
||||
int reset;
|
||||
int rst_active;
|
||||
int cvstd;
|
||||
int cvstd_irq_flag;
|
||||
int irq;
|
||||
int fix_format;
|
||||
struct vehicle_camera_device_defrect defrects[4];
|
||||
struct vehicle_state_check_work state_check_work;
|
||||
struct vehicle_cfg cfg;
|
||||
int cif_error_last_line;
|
||||
u32 channel_reso[PAD_MAX];
|
||||
u8 detect_status;
|
||||
u8 last_detect_status;
|
||||
};
|
||||
|
||||
int vehicle_generic_sensor_write(struct vehicle_ad_dev *ad, char reg, char *pval);
|
||||
int vehicle_sensor_write(struct vehicle_ad_dev *ad, u8 reg, u8 val);
|
||||
int vehicle_generic_sensor_read(struct vehicle_ad_dev *ad, char reg);
|
||||
int vehicle_sensor_read(struct vehicle_ad_dev *ad, u8 reg, u8 *val);
|
||||
int vehicle_parse_sensor(struct vehicle_ad_dev *ad);
|
||||
void vehicle_ad_channel_set(struct vehicle_ad_dev *ad, int channel);
|
||||
|
||||
int vehicle_ad_init(struct vehicle_ad_dev *ad);
|
||||
int vehicle_ad_deinit(void);
|
||||
int vehicle_ad_stream(struct vehicle_ad_dev *ad, int val);
|
||||
struct vehicle_cfg *vehicle_ad_get_vehicle_cfg(void);
|
||||
void vehicle_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
|
||||
int vehicle_to_v4l2_drv_init(void);
|
||||
|
||||
#endif
|
||||
608
drivers/video/rockchip/vehicle/vehicle_ad_7181.c
Normal file
608
drivers/video/rockchip/vehicle/vehicle_ad_7181.c
Normal file
@@ -0,0 +1,608 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* vehicle sensor adv7181
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
|
||||
* Authors:
|
||||
* Zhiqin Wei <wzq@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include "vehicle_cfg.h"
|
||||
#include "vehicle_main.h"
|
||||
#include "vehicle_ad.h"
|
||||
#include "vehicle_ad_7181.h"
|
||||
|
||||
enum {
|
||||
FORCE_PAL_WIDTH = 720,
|
||||
FORCE_PAL_HEIGHT = 576,
|
||||
FORCE_NTSC_WIDTH = 720,
|
||||
FORCE_NTSC_HEIGHT = 480,
|
||||
FORCE_CIF_OUTPUT_FORMAT = CIF_OUTPUT_FORMAT_420,
|
||||
};
|
||||
|
||||
static struct vehicle_ad_dev *ad7181_g_addev;
|
||||
static v4l2_std_id std_old = V4L2_STD_NTSC;
|
||||
|
||||
#define SENSOR_REGISTER_LEN 1 /* sensor register address bytes*/
|
||||
#define SENSOR_VALUE_LEN 1 /* sensor register value bytes*/
|
||||
|
||||
struct rk_sensor_reg {
|
||||
unsigned int reg;
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
#define ADV7181_STATUS1_REG 0x10
|
||||
#define ADV7181_STATUS1_IN_LOCK 0x01
|
||||
#define ADV7181_STATUS1_AUTOD_MASK 0x70
|
||||
#define ADV7181_STATUS1_AUTOD_NTSM_M_J 0x00
|
||||
#define ADV7181_STATUS1_AUTOD_NTSC_4_43 0x10
|
||||
#define ADV7181_STATUS1_AUTOD_PAL_M 0x20
|
||||
#define ADV7181_STATUS1_AUTOD_PAL_60 0x30
|
||||
#define ADV7181_STATUS1_AUTOD_PAL_B_G 0x40
|
||||
#define ADV7181_STATUS1_AUTOD_SECAM 0x50
|
||||
#define ADV7181_STATUS1_AUTOD_PAL_COMB 0x60
|
||||
#define ADV7181_STATUS1_AUTOD_SECAM_525 0x70
|
||||
|
||||
#define ADV7181_INPUT_CONTROL 0x00
|
||||
#define ADV7181_INPUT_DEFAULT 0x00
|
||||
#define ADV7181_INPUT_CVBS_AIN2 0x00
|
||||
#define ADV7181_INPUT_CVBS_AIN3 0x01
|
||||
#define ADV7181_INPUT_CVBS_AIN5 0x02
|
||||
#define ADV7181_INPUT_CVBS_AIN6 0x03
|
||||
#define ADV7181_INPUT_CVBS_AIN8 0x04
|
||||
#define ADV7181_INPUT_CVBS_AIN10 0x05
|
||||
#define ADV7181_INPUT_CVBS_AIN1 0x0B
|
||||
#define ADV7181_INPUT_CVBS_AIN4 0x0D
|
||||
#define ADV7181_INPUT_CVBS_AIN7 0x0F
|
||||
#define ADV7181_INPUT_YPRPB_AIN6_8_10 0x00
|
||||
|
||||
#define SEQCMD_END 0xFF000000
|
||||
#define SensorEnd {SEQCMD_END, 0x00}
|
||||
|
||||
#define SENSOR_DG VEHICLE_DG
|
||||
|
||||
/* Preview resolution setting*/
|
||||
static struct rk_sensor_reg sensor_preview_data[] = {
|
||||
/* autodetect cvbs in ntsc/pal/secam 8-bit 422 encode */
|
||||
{0x00, 0x0B}, /*cvbs in AIN1*/
|
||||
{0x04, 0x77},
|
||||
{0x17, 0x41},
|
||||
{0x1D, 0x47},
|
||||
{0x31, 0x02},
|
||||
{0x3A, 0x17},
|
||||
{0x3B, 0x81},
|
||||
{0x3D, 0xA2},
|
||||
{0x3E, 0x6A},
|
||||
{0x3F, 0xA0},
|
||||
{0x86, 0x0B},
|
||||
{0xF3, 0x01},
|
||||
{0xF9, 0x03},
|
||||
{0x0E, 0x80},
|
||||
{0x52, 0x46},
|
||||
{0x54, 0x80},
|
||||
{0x7F, 0xFF},
|
||||
{0x81, 0x30},
|
||||
{0x90, 0xC9},
|
||||
{0x91, 0x40},
|
||||
{0x92, 0x3C},
|
||||
{0x93, 0xCA},
|
||||
{0x94, 0xD5},
|
||||
{0xB1, 0xFF},
|
||||
{0xB6, 0x08},
|
||||
{0xC0, 0x9A},
|
||||
{0xCF, 0x50},
|
||||
{0xD0, 0x4E},
|
||||
{0xD1, 0xB9},
|
||||
{0xD6, 0xDD},
|
||||
{0xD7, 0xE2},
|
||||
{0xE5, 0x51},
|
||||
{0xF6, 0x3B},
|
||||
{0x0E, 0x00},
|
||||
{0x03, 0x4C}, //stream off
|
||||
{0xDF, 0X46},
|
||||
{0xC9, 0x04},
|
||||
{0xC5, 0x81},
|
||||
{0xC4, 0x34},
|
||||
{0xBf, 0x02},
|
||||
{0xB5, 0x83},
|
||||
{0xB6, 0x00},
|
||||
{0xaf, 0x03},
|
||||
{0xae, 0x00},
|
||||
{0xac, 0x00},
|
||||
{0xAB, 0x00},
|
||||
{0xa1, 0xFF},
|
||||
{0xA2, 0x00},
|
||||
{0xA3, 0x00},
|
||||
{0xA4, 0x00},
|
||||
{0xa5, 0x01},
|
||||
{0xA6, 0x00},
|
||||
{0xA6, 0x00},
|
||||
{0xA7, 0x00},
|
||||
{0xA8, 0x00},
|
||||
{0xa0, 0x03},
|
||||
{0x98, 0X00},
|
||||
{0x97, 0X00},
|
||||
{0X90, 0X00},
|
||||
{0X85, 0X02},
|
||||
{0x7B, 0x1E},
|
||||
{0x74, 0x04},
|
||||
{0x75, 0x01},
|
||||
{0x76, 0x00},
|
||||
{0x6B, 0xC0},
|
||||
{0x67, 0x03},
|
||||
{0x3C, 0x58},
|
||||
{0x30, 0x4C},
|
||||
{0x2E, 0X9F},
|
||||
{0x12, 0XC0},
|
||||
{0x10, 0X0D},
|
||||
{0x05, 0X00},
|
||||
{0x06, 0X02},
|
||||
{0x60, 0x01},
|
||||
SensorEnd
|
||||
};
|
||||
|
||||
static struct rk_sensor_reg sensor_preview_data_yprpb_p[] = {
|
||||
{0x05, 0x01},
|
||||
{0x06, 0x06},
|
||||
{0xc3, 0x56},
|
||||
{0xc4, 0xb4},
|
||||
{0x1d, 0x47},
|
||||
{0x3a, 0x11},
|
||||
{0x3b, 0x81},
|
||||
{0x3c, 0x3b},
|
||||
{0x6b, 0x83},
|
||||
{0xc9, 0x00},
|
||||
{0x73, 0x10},
|
||||
{0x74, 0xa3},
|
||||
{0x75, 0xe8},
|
||||
{0x76, 0xfa},
|
||||
{0x7b, 0x1c},
|
||||
{0x85, 0x19},
|
||||
{0x86, 0x0b},
|
||||
{0xbf, 0x06},
|
||||
{0xc0, 0x40},
|
||||
{0xc1, 0xf0},
|
||||
{0xc2, 0x80},
|
||||
{0xc5, 0x01},
|
||||
{0xc9, 0x08},
|
||||
{0x0e, 0x80},
|
||||
{0x52, 0x46},
|
||||
{0x54, 0x80},
|
||||
{0x57, 0x01},
|
||||
{0xf6, 0x3b},
|
||||
{0x0e, 0x00},
|
||||
{0x67, 0x2f},
|
||||
{0x03, 0x4C}, //disable out put
|
||||
SensorEnd
|
||||
};
|
||||
|
||||
static v4l2_std_id adv7181_std_to_v4l2(u8 status1)
|
||||
{
|
||||
/* in case V4L2_IN_ST_NO_SIGNAL */
|
||||
if (!(status1 & ADV7181_STATUS1_IN_LOCK))
|
||||
return V4L2_STD_UNKNOWN;
|
||||
|
||||
switch (status1 & ADV7181_STATUS1_AUTOD_MASK) {
|
||||
case ADV7181_STATUS1_AUTOD_PAL_M:
|
||||
case ADV7181_STATUS1_AUTOD_NTSM_M_J:
|
||||
return V4L2_STD_NTSC;
|
||||
case ADV7181_STATUS1_AUTOD_NTSC_4_43:
|
||||
return V4L2_STD_NTSC_443;
|
||||
case ADV7181_STATUS1_AUTOD_PAL_60:
|
||||
return V4L2_STD_PAL_60;
|
||||
case ADV7181_STATUS1_AUTOD_PAL_B_G:
|
||||
return V4L2_STD_PAL;
|
||||
case ADV7181_STATUS1_AUTOD_SECAM:
|
||||
return V4L2_STD_SECAM;
|
||||
case ADV7181_STATUS1_AUTOD_PAL_COMB:
|
||||
return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
|
||||
case ADV7181_STATUS1_AUTOD_SECAM_525:
|
||||
return V4L2_STD_SECAM;
|
||||
default:
|
||||
return V4L2_STD_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 adv7181_status_to_v4l2(u8 status1)
|
||||
{
|
||||
if (!(status1 & ADV7181_STATUS1_IN_LOCK))
|
||||
return V4L2_IN_ST_NO_SIGNAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7181_vehicle_status(struct vehicle_ad_dev *ad,
|
||||
u32 *status,
|
||||
v4l2_std_id *std)
|
||||
{
|
||||
unsigned char status1 = 0;
|
||||
|
||||
status1 = vehicle_generic_sensor_read(ad, ADV7181_STATUS1_REG);
|
||||
if (status1)
|
||||
return status1;
|
||||
|
||||
if (status)
|
||||
*status = adv7181_status_to_v4l2(status1);
|
||||
|
||||
if (std)
|
||||
*std = adv7181_std_to_v4l2(status1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adv7181_reinit_parameter(struct vehicle_ad_dev *ad, v4l2_std_id std)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ad7181_g_addev->ad_chl == 0) {
|
||||
ad->cfg.width = 1024;
|
||||
ad->cfg.height = 500;
|
||||
ad->cfg.start_x = 56;
|
||||
ad->cfg.start_y = 0;
|
||||
ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
|
||||
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
|
||||
ad->cfg.field_order = 0;
|
||||
ad->cfg.yuv_order = 1;
|
||||
ad->cfg.href = 0;
|
||||
ad->cfg.vsync = 0;
|
||||
ad->cfg.frame_rate = 60;
|
||||
ad->cfg.type = V4L2_MBUS_PARALLEL;
|
||||
ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
|
||||
V4L2_MBUS_VSYNC_ACTIVE_LOW |
|
||||
V4L2_MBUS_PCLK_SAMPLE_RISING;
|
||||
} else if (std == V4L2_STD_PAL) {
|
||||
ad->cfg.width = FORCE_PAL_WIDTH;
|
||||
ad->cfg.height = FORCE_PAL_HEIGHT;
|
||||
ad->cfg.start_x = 0;
|
||||
ad->cfg.start_y = 0;
|
||||
ad->cfg.input_format = CIF_INPUT_FORMAT_PAL;
|
||||
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
|
||||
ad->cfg.field_order = 0;
|
||||
ad->cfg.yuv_order = 0;
|
||||
ad->cfg.href = 0;
|
||||
ad->cfg.vsync = 0;
|
||||
ad->cfg.frame_rate = 25;
|
||||
ad->cfg.type = V4L2_MBUS_PARALLEL;
|
||||
ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
|
||||
V4L2_MBUS_VSYNC_ACTIVE_LOW |
|
||||
V4L2_MBUS_PCLK_SAMPLE_RISING;
|
||||
} else {
|
||||
ad->cfg.width = FORCE_NTSC_WIDTH;
|
||||
ad->cfg.height = FORCE_NTSC_HEIGHT;
|
||||
ad->cfg.start_x = 0;
|
||||
ad->cfg.start_y = 0;
|
||||
ad->cfg.input_format = CIF_INPUT_FORMAT_NTSC;
|
||||
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
|
||||
ad->cfg.field_order = 0;
|
||||
ad->cfg.yuv_order = 2;
|
||||
ad->cfg.href = 0;
|
||||
ad->cfg.vsync = 0;
|
||||
ad->cfg.frame_rate = 30;
|
||||
ad->cfg.type = V4L2_MBUS_PARALLEL;
|
||||
ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
|
||||
V4L2_MBUS_VSYNC_ACTIVE_LOW |
|
||||
V4L2_MBUS_PCLK_SAMPLE_RISING;
|
||||
}
|
||||
|
||||
/* fix crop info from dts config */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((ad->defrects[i].width == ad->cfg.width) &&
|
||||
(ad->defrects[i].height == ad->cfg.height)) {
|
||||
ad->cfg.start_x = ad->defrects[i].crop_x;
|
||||
ad->cfg.start_y = ad->defrects[i].crop_y;
|
||||
ad->cfg.width = ad->defrects[i].crop_width;
|
||||
ad->cfg.height = ad->defrects[i].crop_height;
|
||||
}
|
||||
}
|
||||
|
||||
SENSOR_DG("size %dx%d, crop(%d,%d)\n",
|
||||
ad->cfg.width, ad->cfg.height,
|
||||
ad->cfg.start_x, ad->cfg.start_y);
|
||||
}
|
||||
|
||||
static void adv7181_reg_init(struct vehicle_ad_dev *ad, unsigned char cvstd)
|
||||
{
|
||||
struct rk_sensor_reg *sensor;
|
||||
int i = 0;
|
||||
unsigned char val[2];
|
||||
|
||||
switch (ad->ad_chl) {
|
||||
case 0:
|
||||
ad->ad_chl = ADV7181_INPUT_CVBS_AIN1;
|
||||
break;
|
||||
case 1:
|
||||
ad->ad_chl = ADV7181_INPUT_CVBS_AIN6;
|
||||
break;
|
||||
case 2:
|
||||
ad->ad_chl = ADV7181_INPUT_CVBS_AIN8;
|
||||
break;
|
||||
case 3:
|
||||
ad->ad_chl = ADV7181_INPUT_CVBS_AIN10;
|
||||
break;
|
||||
case 4:
|
||||
ad->ad_chl = ADV7181_INPUT_YPRPB_AIN6_8_10;
|
||||
break;
|
||||
default:
|
||||
ad->ad_chl = ADV7181_INPUT_CVBS_AIN1;
|
||||
}
|
||||
val[0] = ad->ad_chl;
|
||||
vehicle_generic_sensor_write(ad, ADV7181_INPUT_CONTROL, val);
|
||||
|
||||
if (ad->ad_chl == ADV7181_INPUT_YPRPB_AIN6_8_10) {
|
||||
SENSOR_DG("%s %d set sensor_preview_data_yprpb_p/p", __func__, __LINE__);
|
||||
sensor = sensor_preview_data_yprpb_p;
|
||||
} else {
|
||||
SENSOR_DG("%s %d set n/p", __func__, __LINE__);
|
||||
sensor = sensor_preview_data;
|
||||
}
|
||||
while ((sensor[i].reg != SEQCMD_END) && (sensor[i].reg != 0xFC000000)) {
|
||||
if (sensor[i].reg == ADV7181_INPUT_CONTROL) {
|
||||
SENSOR_DG("%s %d lkg test ad channel = %d\n",
|
||||
__func__, __LINE__, ad->ad_chl);
|
||||
} else {
|
||||
val[0] = sensor[i].val;
|
||||
vehicle_generic_sensor_write(ad, sensor[i].reg, val);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
val[0] = ad->ad_chl;
|
||||
vehicle_generic_sensor_write(ad, ADV7181_INPUT_CONTROL, val);
|
||||
}
|
||||
|
||||
int adv7181_ad_get_cfg(struct vehicle_cfg **cfg)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
if (!ad7181_g_addev)
|
||||
return -1;
|
||||
|
||||
adv7181_vehicle_status(ad7181_g_addev, &status, NULL);
|
||||
|
||||
ad7181_g_addev->cfg.ad_ready = true;
|
||||
|
||||
*cfg = &ad7181_g_addev->cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adv7181_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
|
||||
{
|
||||
SENSOR_DG("%s, last_line %d\n", __func__, last_line);
|
||||
if (last_line < 1)
|
||||
return;
|
||||
|
||||
ad->cif_error_last_line = last_line;
|
||||
if (std_old == V4L2_STD_PAL) {
|
||||
if (last_line == FORCE_NTSC_HEIGHT) {
|
||||
if (ad->state_check_work.state_check_wq)
|
||||
queue_delayed_work(
|
||||
ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work,
|
||||
msecs_to_jiffies(0));
|
||||
}
|
||||
} else if (std_old == V4L2_STD_NTSC) {
|
||||
if (last_line == FORCE_PAL_HEIGHT) {
|
||||
if (ad->state_check_work.state_check_wq)
|
||||
queue_delayed_work(
|
||||
ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work,
|
||||
msecs_to_jiffies(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int adv7181_check_id(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
int ret = 0;
|
||||
int val;
|
||||
|
||||
val = vehicle_generic_sensor_read(ad, 0x11);
|
||||
SENSOR_DG("%s vehicle read 0x11 --> 0x%02x\n", ad->ad_name, val);
|
||||
if (val != 0x20) {
|
||||
SENSOR_DG("%s vehicle wrong camera ID, expected 0x20, detected 0x%02x\n",
|
||||
ad->ad_name, val);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7181_check_std(struct vehicle_ad_dev *ad, v4l2_std_id *std)
|
||||
{
|
||||
u32 status = 0;
|
||||
|
||||
adv7181_vehicle_status(ad, &status, std);
|
||||
|
||||
if (status != 0) { /* No signal */
|
||||
mdelay(30);
|
||||
adv7181_vehicle_status(ad, &status, std);
|
||||
SENSOR_DG("status 0x%x\n", status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
void adv7181_channel_set(struct vehicle_ad_dev *ad, int channel)
|
||||
{
|
||||
static int channel_change = 11;
|
||||
v4l2_std_id std = 0;
|
||||
|
||||
ad->ad_chl = channel;
|
||||
adv7181_reg_init(ad, std);
|
||||
adv7181_check_std(ad, &std);
|
||||
adv7181_reinit_parameter(ad, std);
|
||||
if (channel_change != ad->ad_chl) {
|
||||
SENSOR_DG("%s %d channel changed now channel = %d old_channel = %d\n",
|
||||
__func__, __LINE__, ad->ad_chl, channel);
|
||||
channel_change = ad->ad_chl;
|
||||
vehicle_ad_stat_change_notify();
|
||||
}
|
||||
}
|
||||
|
||||
int adv7181_stream(struct vehicle_ad_dev *ad, int value)
|
||||
{
|
||||
char val;
|
||||
|
||||
if (value)
|
||||
val = 0x0c; //on
|
||||
else
|
||||
val = 0x4c;
|
||||
|
||||
SENSOR_DG("stream write 0x%x to reg 0x03\n", val);
|
||||
vehicle_generic_sensor_write(ad, 0x03, &val);
|
||||
if (value)
|
||||
val = 0x47; //on
|
||||
else
|
||||
val = 0x87;
|
||||
|
||||
SENSOR_DG("stream write 0x%x to reg 0x01d\n", val);
|
||||
vehicle_generic_sensor_write(ad, 0x1d, &val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void power_on(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
/* gpio_direction_output(ad->power, ad->pwr_active); */
|
||||
|
||||
if (gpio_is_valid(ad->powerdown)) {
|
||||
gpio_request(ad->powerdown, "ad_powerdown");
|
||||
gpio_direction_output(ad->powerdown, !ad->pwdn_active);
|
||||
/* gpio_set_value(ad->powerdown, !ad->pwdn_active); */
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ad->power)) {
|
||||
gpio_request(ad->power, "ad_power");
|
||||
gpio_direction_output(ad->power, ad->pwr_active);
|
||||
/* gpio_set_value(ad->power, ad->pwr_active); */
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ad->reset)) {
|
||||
gpio_request(ad->reset, "ad_reset");
|
||||
gpio_direction_output(ad->reset, 0);
|
||||
usleep_range(10000, 12000);
|
||||
gpio_set_value(ad->reset, 1);
|
||||
usleep_range(10000, 12000);
|
||||
}
|
||||
}
|
||||
|
||||
static void power_off(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
if (gpio_is_valid(ad->powerdown))
|
||||
gpio_free(ad->powerdown);
|
||||
|
||||
if (gpio_is_valid(ad->power))
|
||||
gpio_free(ad->power);
|
||||
|
||||
if (gpio_is_valid(ad->reset))
|
||||
gpio_free(ad->reset);
|
||||
}
|
||||
|
||||
static void adv7181_check_state_work(struct work_struct *work)
|
||||
{
|
||||
struct vehicle_ad_dev *ad;
|
||||
v4l2_std_id std;
|
||||
|
||||
ad = ad7181_g_addev;
|
||||
|
||||
if (ad->cif_error_last_line > 0)
|
||||
ad->cif_error_last_line = 0;
|
||||
|
||||
adv7181_check_std(ad, &std);
|
||||
SENSOR_DG("%s:new std(%llx), std_old(%llx)\n", __func__, std, std_old);
|
||||
if (std != std_old) {
|
||||
std_old = std;
|
||||
adv7181_reinit_parameter(ad, std);
|
||||
SENSOR_DG("%s:ad signal change notify\n", __func__);
|
||||
vehicle_ad_stat_change_notify();
|
||||
}
|
||||
|
||||
queue_delayed_work(ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work, msecs_to_jiffies(3000));
|
||||
}
|
||||
|
||||
int adv7181_ad_deinit(void)
|
||||
{
|
||||
struct vehicle_ad_dev *ad;
|
||||
|
||||
ad = ad7181_g_addev;
|
||||
|
||||
if (!ad)
|
||||
return -ENODEV;
|
||||
|
||||
if (ad->state_check_work.state_check_wq) {
|
||||
cancel_delayed_work_sync(&ad->state_check_work.work);
|
||||
flush_delayed_work(&ad->state_check_work.work);
|
||||
flush_workqueue(ad->state_check_work.state_check_wq);
|
||||
destroy_workqueue(ad->state_check_work.state_check_wq);
|
||||
}
|
||||
if (ad->irq)
|
||||
free_irq(ad->irq, ad);
|
||||
power_off(ad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int adv7181_ad_init(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
v4l2_std_id std = V4L2_STD_NTSC;
|
||||
|
||||
if (!ad)
|
||||
return -1;
|
||||
|
||||
ad7181_g_addev = ad;
|
||||
|
||||
/* 1. i2c init */
|
||||
while (ad->adapter == NULL) {
|
||||
ad->adapter = i2c_get_adapter(ad->i2c_chl);
|
||||
usleep_range(10000, 12000);
|
||||
}
|
||||
|
||||
if (!i2c_check_functionality(ad->adapter, I2C_FUNC_I2C))
|
||||
return -EIO;
|
||||
|
||||
/* 2. ad power on sequence */
|
||||
power_on(ad);
|
||||
|
||||
/* fix mode */
|
||||
adv7181_check_std(ad, &std);
|
||||
std_old = std;
|
||||
SENSOR_DG("std: %s\n", (std == V4L2_STD_NTSC) ? "ntsc" : "pal");
|
||||
SENSOR_DG("std_old: %s\n", (std_old == V4L2_STD_NTSC) ? "ntsc" : "pal");
|
||||
|
||||
/* 3 .init default format params */
|
||||
adv7181_reg_init(ad, std);
|
||||
adv7181_reinit_parameter(ad, std);
|
||||
vehicle_ad_stat_change_notify();
|
||||
|
||||
/* 5. create workqueue to detect signal change */
|
||||
INIT_DELAYED_WORK(&ad->state_check_work.work, adv7181_check_state_work);
|
||||
ad->state_check_work.state_check_wq =
|
||||
create_singlethread_workqueue("vehicle-ad-adv7181");
|
||||
|
||||
queue_delayed_work(ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work, msecs_to_jiffies(100));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
19
drivers/video/rockchip/vehicle/vehicle_ad_7181.h
Normal file
19
drivers/video/rockchip/vehicle/vehicle_ad_7181.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_AD_7181_H__
|
||||
#define __VEHICLE_AD_7181_H__
|
||||
|
||||
int adv7181_ad_init(struct vehicle_ad_dev *ad);
|
||||
int adv7181_ad_deinit(void);
|
||||
int adv7181_ad_get_cfg(struct vehicle_cfg **cfg);
|
||||
int adv7181_stream(struct vehicle_ad_dev *ad, int value);
|
||||
void adv7181_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
|
||||
int adv7181_check_id(struct vehicle_ad_dev *ad);
|
||||
void adv7181_channel_set(struct vehicle_ad_dev *ad, int channel);
|
||||
|
||||
#endif
|
||||
|
||||
1149
drivers/video/rockchip/vehicle/vehicle_ad_gc2145.c
Normal file
1149
drivers/video/rockchip/vehicle/vehicle_ad_gc2145.c
Normal file
File diff suppressed because it is too large
Load Diff
18
drivers/video/rockchip/vehicle/vehicle_ad_gc2145.h
Normal file
18
drivers/video/rockchip/vehicle/vehicle_ad_gc2145.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_AD_GC2145_H__
|
||||
#define __VEHICLE_AD_GC2145_H__
|
||||
|
||||
int gc2145_ad_init(struct vehicle_ad_dev *ad);
|
||||
int gc2145_ad_deinit(void);
|
||||
int gc2145_ad_get_cfg(struct vehicle_cfg **cfg);
|
||||
void gc2145_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
|
||||
int gc2145_check_id(struct vehicle_ad_dev *ad);
|
||||
int gc2145_stream(struct vehicle_ad_dev *ad, int enable);
|
||||
void gc2145_channel_set(struct vehicle_ad_dev *ad, int channel);
|
||||
|
||||
#endif
|
||||
539
drivers/video/rockchip/vehicle/vehicle_ad_max96714.c
Normal file
539
drivers/video/rockchip/vehicle/vehicle_ad_max96714.c
Normal file
@@ -0,0 +1,539 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* vehicle sensor max96714
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Jianwei Fan <jianwei.fan@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include "vehicle_cfg.h"
|
||||
#include "vehicle_main.h"
|
||||
#include "vehicle_ad.h"
|
||||
#include "vehicle_ad_max96714.h"
|
||||
|
||||
enum {
|
||||
CVSTD_720P60 = 0,
|
||||
CVSTD_720P50,
|
||||
CVSTD_1080P30,
|
||||
CVSTD_1080P25,
|
||||
CVSTD_720P30,
|
||||
CVSTD_720P25,
|
||||
CVSTD_SVGAP30,
|
||||
CVSTD_SD,
|
||||
CVSTD_NTSC,
|
||||
CVSTD_PAL
|
||||
};
|
||||
|
||||
enum {
|
||||
FORCE_PAL_WIDTH = 960,
|
||||
FORCE_PAL_HEIGHT = 576,
|
||||
FORCE_NTSC_WIDTH = 960,
|
||||
FORCE_NTSC_HEIGHT = 480,
|
||||
FORCE_SVGA_WIDTH = 800,
|
||||
FORCE_SVGA_HEIGHT = 600,
|
||||
FORCE_720P_WIDTH = 1280,
|
||||
FORCE_720P_HEIGHT = 720,
|
||||
FORCE_1080P_WIDTH = 1920,
|
||||
FORCE_1080P_HEIGHT = 1080,
|
||||
FORCE_CIF_OUTPUT_FORMAT = CIF_OUTPUT_FORMAT_420,
|
||||
};
|
||||
|
||||
enum {
|
||||
VIDEO_UNPLUG,
|
||||
VIDEO_IN,
|
||||
VIDEO_LOCKED,
|
||||
VIDEO_UNLOCK
|
||||
};
|
||||
|
||||
#define FLAG_LOCKED (0x1 << 3)
|
||||
#define MAX96714_LINK_FREQ_150M 150000000UL
|
||||
|
||||
static struct vehicle_ad_dev *max96714_g_addev;
|
||||
static int cvstd_mode = CVSTD_1080P30;
|
||||
//static int cvstd_old = CVSTD_720P25;
|
||||
static int cvstd_old = CVSTD_NTSC;
|
||||
|
||||
//static int cvstd_sd = CVSTD_NTSC;
|
||||
static int cvstd_state = VIDEO_UNPLUG;
|
||||
static int cvstd_old_state = VIDEO_UNLOCK;
|
||||
|
||||
static bool g_max96714_streaming;
|
||||
|
||||
#define SENSOR_VALUE_LEN 1 /* sensor register value bytes*/
|
||||
#define MAX96714_CHIP_ID 0xC9
|
||||
#define MAX96714_CHIP_ID_REG 0x0D
|
||||
#define MAX96714_GMSL_STATE 0x0013
|
||||
#define MAX96714_STREAM_CTL 0x0313
|
||||
#define MAX96714_MODE_SW_STANDBY 0x0
|
||||
#define MAX96714_MODE_STREAMING BIT(1)
|
||||
|
||||
struct regval {
|
||||
u16 reg;
|
||||
u8 val;
|
||||
};
|
||||
#define REG_NULL 0xFFFF
|
||||
|
||||
/* 1080p Preview resolution setting*/
|
||||
static struct regval sensor_preview_data_1080p_30hz[] = {
|
||||
{0x0313, 0x00},
|
||||
{0x0001, 0x01},
|
||||
{0x0010, 0x21},
|
||||
{0x0320, 0x23},
|
||||
{0x0325, 0x80},
|
||||
{0x0313, 0x00},
|
||||
{REG_NULL, 0x00},
|
||||
};
|
||||
|
||||
static struct rkmodule_csi_dphy_param max96714_dcphy_param = {
|
||||
.vendor = PHY_VENDOR_SAMSUNG,
|
||||
.lp_vol_ref = 3,
|
||||
.lp_hys_sw = {3, 0, 0, 0},
|
||||
.lp_escclk_pol_sel = {1, 0, 0, 0},
|
||||
.skew_data_cal_clk = {0, 3, 3, 3},
|
||||
.clk_hs_term_sel = 2,
|
||||
.data_hs_term_sel = {2, 2, 2, 2},
|
||||
.reserved = {0},
|
||||
};
|
||||
|
||||
static int max96714_read_reg(struct vehicle_ad_dev *ad, u16 reg,
|
||||
unsigned int len, u32 *val)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
u8 *data_be_p;
|
||||
__be32 data_be = 0;
|
||||
__be16 reg_addr_be = cpu_to_be16(reg);
|
||||
int ret;
|
||||
|
||||
if (len > 4 || !len)
|
||||
return -EINVAL;
|
||||
|
||||
data_be_p = (u8 *)&data_be;
|
||||
/* Write register address */
|
||||
msgs[0].addr = ad->i2c_add;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = 2;
|
||||
msgs[0].buf = (u8 *)®_addr_be;
|
||||
|
||||
/* Read data from register */
|
||||
msgs[1].addr = ad->i2c_add;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = len;
|
||||
msgs[1].buf = &data_be_p[4 - len];
|
||||
|
||||
ret = i2c_transfer(ad->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret != ARRAY_SIZE(msgs))
|
||||
return -EIO;
|
||||
|
||||
*val = be32_to_cpu(data_be);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max96714_write_reg(struct vehicle_ad_dev *ad, u16 reg, u8 val)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
u8 buf[3];
|
||||
int ret;
|
||||
|
||||
buf[0] = reg >> 8;
|
||||
buf[1] = reg & 0xff;
|
||||
buf[2] = val;
|
||||
|
||||
msg.addr = ad->i2c_add;
|
||||
msg.flags = 0;
|
||||
msg.buf = buf;
|
||||
msg.len = sizeof(buf);
|
||||
|
||||
ret = i2c_transfer(ad->adapter, &msg, 1);
|
||||
if (ret >= 0)
|
||||
return 0;
|
||||
|
||||
VEHICLE_DGERR(
|
||||
"max96714 write reg(0x%x val:0x%x) failed !\n", reg, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max96714_write_array(struct vehicle_ad_dev *ad,
|
||||
const struct regval *regs)
|
||||
{
|
||||
u32 i = 0;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; ret == 0 && regs[i].reg != REG_NULL; i++)
|
||||
ret = max96714_write_reg(ad, regs[i].reg, regs[i].val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max96714_reinit_parameter(struct vehicle_ad_dev *ad, unsigned char cvstd)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
switch (cvstd) {
|
||||
case CVSTD_1080P30:
|
||||
ad->cfg.width = 1920;
|
||||
ad->cfg.height = 1080;
|
||||
ad->cfg.start_x = 0;
|
||||
ad->cfg.start_y = 0;
|
||||
ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
|
||||
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
|
||||
ad->cfg.field_order = 0;
|
||||
ad->cfg.yuv_order = 0;/*00 - UYVY*/
|
||||
ad->cfg.href = 0;
|
||||
ad->cfg.vsync = 0;
|
||||
ad->cfg.frame_rate = 30;
|
||||
ad->cfg.mipi_freq = MAX96714_LINK_FREQ_150M;
|
||||
break;
|
||||
|
||||
default:
|
||||
ad->cfg.width = 1920;
|
||||
ad->cfg.height = 1080;
|
||||
ad->cfg.start_x = 0;
|
||||
ad->cfg.start_y = 0;
|
||||
ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
|
||||
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
|
||||
ad->cfg.field_order = 0;
|
||||
ad->cfg.yuv_order = 0;/*00 - UYVY*/
|
||||
ad->cfg.href = 0;
|
||||
ad->cfg.vsync = 0;
|
||||
ad->cfg.frame_rate = 30;
|
||||
ad->cfg.mipi_freq = MAX96714_LINK_FREQ_150M;
|
||||
break;
|
||||
}
|
||||
ad->cfg.type = V4L2_MBUS_CSI2_DPHY;
|
||||
ad->cfg.mbus_flags = V4L2_MBUS_CSI2_4_LANE | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK |
|
||||
V4L2_MBUS_CSI2_CHANNEL_0;
|
||||
ad->cfg.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8;
|
||||
ad->cfg.dphy_param = &max96714_dcphy_param;
|
||||
|
||||
switch (ad->cfg.mbus_flags & V4L2_MBUS_CSI2_LANES) {
|
||||
case V4L2_MBUS_CSI2_1_LANE:
|
||||
ad->cfg.lanes = 1;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_2_LANE:
|
||||
ad->cfg.lanes = 2;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_3_LANE:
|
||||
ad->cfg.lanes = 3;
|
||||
break;
|
||||
case V4L2_MBUS_CSI2_4_LANE:
|
||||
ad->cfg.lanes = 4;
|
||||
break;
|
||||
default:
|
||||
ad->cfg.lanes = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* fix crop info from dts config */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((ad->defrects[i].width == ad->cfg.width) &&
|
||||
(ad->defrects[i].height == ad->cfg.height)) {
|
||||
ad->cfg.start_x = ad->defrects[i].crop_x;
|
||||
ad->cfg.start_y = ad->defrects[i].crop_y;
|
||||
ad->cfg.width = ad->defrects[i].crop_width;
|
||||
ad->cfg.height = ad->defrects[i].crop_height;
|
||||
}
|
||||
}
|
||||
|
||||
VEHICLE_DG("crop(%d,%d)", ad->cfg.start_x, ad->cfg.start_y);
|
||||
}
|
||||
|
||||
static void max96714_reg_init(struct vehicle_ad_dev *ad, unsigned char cvstd)
|
||||
{
|
||||
struct regval *sensor;
|
||||
int ret = 0;
|
||||
|
||||
switch (cvstd) {
|
||||
case CVSTD_1080P30:
|
||||
VEHICLE_INFO("%s, init CVSTD_1080P30 mode", __func__);
|
||||
sensor = sensor_preview_data_1080p_30hz;
|
||||
break;
|
||||
default:
|
||||
VEHICLE_INFO("%s, init CVSTD_1080P30 mode", __func__);
|
||||
sensor = sensor_preview_data_1080p_30hz;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = max96714_write_array(ad, sensor);
|
||||
if (ret)
|
||||
VEHICLE_DGERR("%s, init sensor fail", __func__);
|
||||
}
|
||||
|
||||
void max96714_channel_set(struct vehicle_ad_dev *ad, int channel)
|
||||
{
|
||||
}
|
||||
|
||||
int max96714_ad_get_cfg(struct vehicle_cfg **cfg)
|
||||
{
|
||||
if (!max96714_g_addev)
|
||||
return -1;
|
||||
|
||||
switch (cvstd_state) {
|
||||
case VIDEO_UNPLUG:
|
||||
max96714_g_addev->cfg.ad_ready = false;
|
||||
break;
|
||||
case VIDEO_LOCKED:
|
||||
max96714_g_addev->cfg.ad_ready = true;
|
||||
break;
|
||||
case VIDEO_IN:
|
||||
max96714_g_addev->cfg.ad_ready = false;
|
||||
break;
|
||||
}
|
||||
|
||||
max96714_g_addev->cfg.ad_ready = true;
|
||||
|
||||
*cfg = &max96714_g_addev->cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void max96714_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
|
||||
{
|
||||
VEHICLE_DG("last_line %d\n", last_line);
|
||||
|
||||
if (last_line < 1)
|
||||
return;
|
||||
|
||||
ad->cif_error_last_line = last_line;
|
||||
if (cvstd_mode == CVSTD_PAL) {
|
||||
if (last_line == FORCE_NTSC_HEIGHT) {
|
||||
if (ad->state_check_work.state_check_wq)
|
||||
queue_delayed_work(
|
||||
ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work,
|
||||
msecs_to_jiffies(0));
|
||||
}
|
||||
} else if (cvstd_mode == CVSTD_NTSC) {
|
||||
if (last_line == FORCE_PAL_HEIGHT) {
|
||||
if (ad->state_check_work.state_check_wq)
|
||||
queue_delayed_work(
|
||||
ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work,
|
||||
msecs_to_jiffies(0));
|
||||
}
|
||||
} else if (cvstd_mode == CVSTD_1080P30) {
|
||||
if (last_line == FORCE_1080P_HEIGHT) {
|
||||
if (ad->state_check_work.state_check_wq)
|
||||
queue_delayed_work(
|
||||
ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work,
|
||||
msecs_to_jiffies(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int max96714_check_id(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 pid = 0;
|
||||
|
||||
ret = max96714_read_reg(ad, MAX96714_CHIP_ID_REG, SENSOR_VALUE_LEN, &pid);
|
||||
if (pid != MAX96714_CHIP_ID) {
|
||||
VEHICLE_DGERR("%s: expected 0xC9, detected: 0x%02x !",
|
||||
ad->ad_name, pid);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
VEHICLE_INFO("Found MAX96714 sensor: id(0x%2x) !\n", pid);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max96714_check_cvstd(struct vehicle_ad_dev *ad, bool activate_check)
|
||||
{
|
||||
static int state = VIDEO_UNPLUG;
|
||||
int ret = 0;
|
||||
|
||||
ret = max96714_read_reg(ad, MAX96714_GMSL_STATE, SENSOR_VALUE_LEN, &state);
|
||||
if (ret)
|
||||
VEHICLE_DGERR("read GMSL2 link lock failed!\n");
|
||||
|
||||
if (state & FLAG_LOCKED) {
|
||||
state = VIDEO_LOCKED;
|
||||
VEHICLE_DG("GMSL2 link locked!\n");
|
||||
cvstd_mode = CVSTD_1080P30;
|
||||
} else {
|
||||
state = VIDEO_UNPLUG;
|
||||
VEHICLE_DG("GMSL2 link not locked!\n");
|
||||
cvstd_mode = cvstd_old;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max96714_stream(struct vehicle_ad_dev *ad, int enable)
|
||||
{
|
||||
VEHICLE_INFO("%s on(%d)\n", __func__, enable);
|
||||
|
||||
g_max96714_streaming = (enable != 0);
|
||||
if (g_max96714_streaming) {
|
||||
max96714_write_reg(ad, MAX96714_STREAM_CTL, MAX96714_MODE_STREAMING);
|
||||
if (ad->state_check_work.state_check_wq)
|
||||
queue_delayed_work(ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work, msecs_to_jiffies(200));
|
||||
} else {
|
||||
max96714_write_reg(ad, MAX96714_STREAM_CTL, MAX96714_MODE_SW_STANDBY);
|
||||
if (ad->state_check_work.state_check_wq)
|
||||
cancel_delayed_work_sync(&ad->state_check_work.work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max96714_power_on(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
/* gpio_direction_output(ad->power, ad->pwr_active); */
|
||||
if (gpio_is_valid(ad->power)) {
|
||||
gpio_request(ad->power, "max96714_power");
|
||||
gpio_direction_output(ad->power, ad->pwr_active);
|
||||
/* gpio_set_value(ad->power, ad->pwr_active); */
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ad->powerdown)) {
|
||||
gpio_request(ad->powerdown, "max96714_pwd");
|
||||
gpio_direction_output(ad->powerdown, 1);
|
||||
/* gpio_set_value(ad->powerdown, !ad->pwdn_active); */
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ad->reset)) {
|
||||
gpio_request(ad->reset, "max96714_rst");
|
||||
gpio_direction_output(ad->reset, 0);
|
||||
usleep_range(1500, 2000);
|
||||
gpio_direction_output(ad->reset, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void max96714_power_deinit(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
if (gpio_is_valid(ad->reset))
|
||||
gpio_free(ad->reset);
|
||||
if (gpio_is_valid(ad->power))
|
||||
gpio_free(ad->power);
|
||||
if (gpio_is_valid(ad->powerdown))
|
||||
gpio_free(ad->powerdown);
|
||||
}
|
||||
|
||||
static void max96714_check_state_work(struct work_struct *work)
|
||||
{
|
||||
struct vehicle_ad_dev *ad;
|
||||
|
||||
ad = max96714_g_addev;
|
||||
|
||||
if (ad->cif_error_last_line > 0) {
|
||||
max96714_check_cvstd(ad, true);
|
||||
ad->cif_error_last_line = 0;
|
||||
} else {
|
||||
max96714_check_cvstd(ad, false);
|
||||
}
|
||||
|
||||
VEHICLE_DG("%s:cvstd_old(%d), cvstd_mode(%d)\n", __func__, cvstd_old, cvstd_mode);
|
||||
if (cvstd_old != cvstd_mode || cvstd_old_state != cvstd_state) {
|
||||
VEHICLE_INFO("%s:ad sensor std mode change, cvstd_old(%d), cvstd_mode(%d)\n",
|
||||
__func__, cvstd_old, cvstd_mode);
|
||||
cvstd_old = cvstd_mode;
|
||||
cvstd_old_state = cvstd_state;
|
||||
max96714_reinit_parameter(ad, cvstd_mode);
|
||||
max96714_reg_init(ad, cvstd_mode);
|
||||
vehicle_ad_stat_change_notify();
|
||||
}
|
||||
if (g_max96714_streaming) {
|
||||
queue_delayed_work(ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work, msecs_to_jiffies(100));
|
||||
}
|
||||
}
|
||||
|
||||
int max96714_ad_deinit(void)
|
||||
{
|
||||
struct vehicle_ad_dev *ad;
|
||||
|
||||
ad = max96714_g_addev;
|
||||
|
||||
if (!ad)
|
||||
return -ENODEV;
|
||||
|
||||
if (ad->state_check_work.state_check_wq) {
|
||||
cancel_delayed_work_sync(&ad->state_check_work.work);
|
||||
flush_delayed_work(&ad->state_check_work.work);
|
||||
flush_workqueue(ad->state_check_work.state_check_wq);
|
||||
destroy_workqueue(ad->state_check_work.state_check_wq);
|
||||
}
|
||||
if (ad->irq)
|
||||
free_irq(ad->irq, ad);
|
||||
max96714_power_deinit(ad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int get_ad_mode_from_fix_format(int fix_format)
|
||||
{
|
||||
int mode = -1;
|
||||
|
||||
switch (fix_format) {
|
||||
case AD_FIX_FORMAT_PAL:
|
||||
case AD_FIX_FORMAT_NTSC:
|
||||
case AD_FIX_FORMAT_720P_50FPS:
|
||||
case AD_FIX_FORMAT_720P_30FPS:
|
||||
case AD_FIX_FORMAT_720P_25FPS:
|
||||
mode = CVSTD_720P25;
|
||||
break;
|
||||
case AD_FIX_FORMAT_1080P_30FPS:
|
||||
case AD_FIX_FORMAT_1080P_25FPS:
|
||||
|
||||
default:
|
||||
mode = CVSTD_1080P30;
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
int max96714_ad_init(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
max96714_g_addev = ad;
|
||||
|
||||
/* 1. i2c init */
|
||||
while (ad->adapter == NULL) {
|
||||
ad->adapter = i2c_get_adapter(ad->i2c_chl);
|
||||
usleep_range(10000, 12000);
|
||||
}
|
||||
if (ad->adapter == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (!i2c_check_functionality(ad->adapter, I2C_FUNC_I2C))
|
||||
return -EIO;
|
||||
|
||||
max96714_power_on(ad);
|
||||
|
||||
max96714_reg_init(ad, cvstd_mode);
|
||||
|
||||
max96714_reinit_parameter(ad, cvstd_mode);
|
||||
|
||||
INIT_DELAYED_WORK(&ad->state_check_work.work, max96714_check_state_work);
|
||||
ad->state_check_work.state_check_wq =
|
||||
create_singlethread_workqueue("vehicle-ad-max96714");
|
||||
|
||||
queue_delayed_work(ad->state_check_work.state_check_wq,
|
||||
&ad->state_check_work.work, msecs_to_jiffies(100));
|
||||
|
||||
return 0;
|
||||
}
|
||||
18
drivers/video/rockchip/vehicle/vehicle_ad_max96714.h
Normal file
18
drivers/video/rockchip/vehicle/vehicle_ad_max96714.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_AD_MAX96714_H__
|
||||
#define __VEHICLE_AD_MAX96714_H__
|
||||
|
||||
int max96714_ad_init(struct vehicle_ad_dev *ad);
|
||||
int max96714_ad_deinit(void);
|
||||
int max96714_ad_get_cfg(struct vehicle_cfg **cfg);
|
||||
void max96714_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
|
||||
int max96714_check_id(struct vehicle_ad_dev *ad);
|
||||
int max96714_stream(struct vehicle_ad_dev *ad, int enable);
|
||||
void max96714_channel_set(struct vehicle_ad_dev *ad, int channel);
|
||||
|
||||
#endif
|
||||
1206
drivers/video/rockchip/vehicle/vehicle_ad_nvp6188.c
Normal file
1206
drivers/video/rockchip/vehicle/vehicle_ad_nvp6188.c
Normal file
File diff suppressed because it is too large
Load Diff
18
drivers/video/rockchip/vehicle/vehicle_ad_nvp6188.h
Normal file
18
drivers/video/rockchip/vehicle/vehicle_ad_nvp6188.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_AD_NVP6188_H__
|
||||
#define __VEHICLE_AD_NVP6188_H__
|
||||
|
||||
int nvp6188_ad_init(struct vehicle_ad_dev *ad);
|
||||
int nvp6188_ad_deinit(void);
|
||||
int nvp6188_ad_get_cfg(struct vehicle_cfg **cfg);
|
||||
void nvp6188_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
|
||||
int nvp6188_check_id(struct vehicle_ad_dev *ad);
|
||||
int nvp6188_stream(struct vehicle_ad_dev *ad, int enable);
|
||||
void nvp6188_channel_set(struct vehicle_ad_dev *ad, int channel);
|
||||
|
||||
#endif
|
||||
1359
drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.c
Normal file
1359
drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.c
Normal file
File diff suppressed because it is too large
Load Diff
18
drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.h
Normal file
18
drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_AD_NVP6324_H__
|
||||
#define __VEHICLE_AD_NVP6324_H__
|
||||
|
||||
int nvp6324_ad_init(struct vehicle_ad_dev *ad);
|
||||
int nvp6324_ad_deinit(void);
|
||||
int nvp6324_ad_get_cfg(struct vehicle_cfg **cfg);
|
||||
void nvp6324_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
|
||||
int nvp6324_check_id(struct vehicle_ad_dev *ad);
|
||||
int nvp6324_stream(struct vehicle_ad_dev *ad, int enable);
|
||||
void nvp6324_channel_set(struct vehicle_ad_dev *ad, int channel);
|
||||
|
||||
#endif
|
||||
1039
drivers/video/rockchip/vehicle/vehicle_ad_tp2825.c
Normal file
1039
drivers/video/rockchip/vehicle/vehicle_ad_tp2825.c
Normal file
File diff suppressed because it is too large
Load Diff
18
drivers/video/rockchip/vehicle/vehicle_ad_tp2825.h
Normal file
18
drivers/video/rockchip/vehicle/vehicle_ad_tp2825.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_AD_TP2825_H__
|
||||
#define __VEHICLE_AD_TP2825_H__
|
||||
|
||||
int tp2825_ad_init(struct vehicle_ad_dev *ad);
|
||||
int tp2825_ad_deinit(void);
|
||||
int tp2825_ad_get_cfg(struct vehicle_cfg **cfg);
|
||||
void tp2825_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
|
||||
int tp2825_check_id(struct vehicle_ad_dev *ad);
|
||||
int tp2825_stream(struct vehicle_ad_dev *ad, int enable);
|
||||
void tp2825_channel_set(struct vehicle_ad_dev *ad, int channel);
|
||||
|
||||
#endif
|
||||
144
drivers/video/rockchip/vehicle/vehicle_cfg.h
Normal file
144
drivers/video/rockchip/vehicle/vehicle_cfg.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_CFG
|
||||
#define __VEHICLE_CFG
|
||||
#include <media/v4l2-mediabus.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
|
||||
/* Driver information */
|
||||
#define VEHICLE_DRIVER_NAME "Vehicle"
|
||||
|
||||
static int vehicle_debug;
|
||||
#define VEHICLE_DG(format, ...) do { \
|
||||
if (vehicle_debug) \
|
||||
pr_info("%s %s(%d): " format, __func__, __LINE__, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define VEHICLE_DGERR(format, ...) \
|
||||
pr_info("%s %s(%d):" format, VEHICLE_DRIVER_NAME, __func__, __LINE__, ## __VA_ARGS__)
|
||||
#define VEHICLE_INFO(format, ...) \
|
||||
pr_info("%s %s(%d):" format, VEHICLE_DRIVER_NAME, __func__, __LINE__, ## __VA_ARGS__)
|
||||
|
||||
#define MAX_BUF_NUM (6)
|
||||
|
||||
#define CVBS_DOUBLE_FPS_MODE /*PAL 50fps; NTSC 60fps*/
|
||||
|
||||
enum {
|
||||
CIF_INPUT_FORMAT_YUV = 0,
|
||||
CIF_INPUT_FORMAT_PAL = 2,
|
||||
CIF_INPUT_FORMAT_NTSC = 3,
|
||||
CIF_INPUT_FORMAT_RAW = 4,
|
||||
CIF_INPUT_FORMAT_JPEG = 5,
|
||||
CIF_INPUT_FORMAT_MIPI = 6,
|
||||
CIF_INPUT_FORMAT_PAL_SW_COMPOSITE = 0xff000000,
|
||||
CIF_INPUT_FORMAT_NTSC_SW_COMPOSITE = 0xfe000000,
|
||||
};
|
||||
|
||||
enum {
|
||||
CIF_OUTPUT_FORMAT_422 = 0,
|
||||
CIF_OUTPUT_FORMAT_420 = 1,
|
||||
};
|
||||
|
||||
struct vehicle_cfg {
|
||||
/* output */
|
||||
int width;
|
||||
int height;
|
||||
/* sensor output */
|
||||
int src_width;
|
||||
int src_height;
|
||||
/*
|
||||
* action: source video data input format.
|
||||
* 000 - YUV
|
||||
* 010 - PAL
|
||||
* 011 - NTSC
|
||||
* 100 - RAW
|
||||
* 101 - JPEG
|
||||
* 110 - MIPI
|
||||
*/
|
||||
int input_format;
|
||||
/*
|
||||
* 0 - output is 422
|
||||
* 1 - output is 420
|
||||
*/
|
||||
int output_format;
|
||||
/*
|
||||
* YUV input order
|
||||
* 00 - UYVY
|
||||
* 01 - YVYU
|
||||
* 10 - VYUY
|
||||
* 11 - YUYV
|
||||
*/
|
||||
int yuv_order;
|
||||
/*
|
||||
* ccir input order
|
||||
* 0 : odd field first
|
||||
* 1 : even field first
|
||||
*/
|
||||
int field_order;
|
||||
|
||||
/*
|
||||
* BT.656 not use
|
||||
* BT.601 hsync polarity
|
||||
* val:
|
||||
* 0-low active
|
||||
* 1-high active
|
||||
*/
|
||||
int href;
|
||||
/*
|
||||
* BT.656 not use
|
||||
* BT.601 hsync polarity
|
||||
* val :
|
||||
* 0-low active
|
||||
* 1-high active
|
||||
*/
|
||||
int vsync;
|
||||
|
||||
/*
|
||||
* enum v4l2_mbus_type - media bus type
|
||||
* @V4L2_MBUS_PARALLEL: parallel interface with hsync and vsync
|
||||
* @V4L2_MBUS_BT656: parallel interface with embedded synchronisation, can
|
||||
* also be used for BT.1120
|
||||
* @V4L2_MBUS_CSI1: MIPI CSI-1 serial interface
|
||||
* @V4L2_MBUS_CCP2: CCP2 (Compact Camera Port 2)
|
||||
* @V4L2_MBUS_CSI2: MIPI CSI-2 serial interface
|
||||
*/
|
||||
enum v4l2_mbus_type type;
|
||||
|
||||
/*
|
||||
* Signal polarity flags
|
||||
* Note: in BT.656 mode HSYNC, FIELD, and VSYNC are unused
|
||||
* V4L2_MBUS_[HV]SYNC* flags should be also used for specifying
|
||||
* configuration of hardware that uses [HV]REF signals
|
||||
*/
|
||||
unsigned int mbus_flags;
|
||||
|
||||
/*
|
||||
* Note: in BT.656/601 mode mipi_freq are unused
|
||||
* only used when v4l2_mbus_type is V4L2_MBUS_CSI2
|
||||
*/
|
||||
s64 mipi_freq;
|
||||
/*
|
||||
* Note: in BT.656/601 mode mipi_freq are unused
|
||||
* only used when v4l2_mbus_type is V4L2_MBUS_CSI2
|
||||
*/
|
||||
int lanes;
|
||||
|
||||
u32 mbus_code;
|
||||
|
||||
int start_x;
|
||||
int start_y;
|
||||
int frame_rate;
|
||||
|
||||
unsigned int buf_phy_addr[MAX_BUF_NUM];
|
||||
unsigned int buf_num;
|
||||
int ad_ready;
|
||||
/*0:no, 1:90; 2:180; 4:270; 0x10:mirror-y; 0x20:mirror-x*/
|
||||
int rotate_mirror;
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
};
|
||||
|
||||
#endif
|
||||
4930
drivers/video/rockchip/vehicle/vehicle_cif.c
Normal file
4930
drivers/video/rockchip/vehicle/vehicle_cif.c
Normal file
File diff suppressed because it is too large
Load Diff
179
drivers/video/rockchip/vehicle/vehicle_cif.h
Normal file
179
drivers/video/rockchip/vehicle/vehicle_cif.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_CIF_H
|
||||
#define __VEHICLE_CIF_H
|
||||
|
||||
#include "vehicle_cfg.h"
|
||||
#include "vehicle_cif_regs.h"
|
||||
#include "../../../media/platform/rockchip/cif/hw.h"
|
||||
#include "../../../media/platform/rockchip/cif/dev.h"
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
enum vehicle_rkcif_chip_id {
|
||||
CHIP_RK3568_VEHICLE_CIF = 0x0,
|
||||
CHIP_RK3588_VEHICLE_CIF,
|
||||
};
|
||||
|
||||
enum rkcif_csi_host_idx {
|
||||
RKCIF_MIPI0_CSI2 = 0x0,
|
||||
RKCIF_MIPI1_CSI2,
|
||||
RKCIF_MIPI2_CSI2,
|
||||
RKCIF_MIPI3_CSI2,
|
||||
RKCIF_MIPI4_CSI2,
|
||||
RKCIF_MIPI5_CSI2,
|
||||
};
|
||||
|
||||
struct vehicle_rkcif_dummy_buffer {
|
||||
void *vaddr;
|
||||
dma_addr_t dma_addr;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct rk_cif_clk {
|
||||
/************clk************/
|
||||
struct clk *clks[RKCIF_MAX_BUS_CLK];
|
||||
struct clk *xvclk;
|
||||
int clks_num;
|
||||
/************reset************/
|
||||
struct reset_control *cif_rst[RKCIF_MAX_RESET];
|
||||
int rsts_num;
|
||||
/* spinlock_t lock; */
|
||||
bool on;
|
||||
};
|
||||
|
||||
struct rk_cif_irqinfo {
|
||||
unsigned int irq;
|
||||
unsigned long cifirq_idx;
|
||||
unsigned long cifirq_normal_idx;
|
||||
unsigned long cifirq_abnormal_idx;
|
||||
unsigned long dmairq_idx;
|
||||
|
||||
/* @csi_overflow_cnt: count of csi overflow irq
|
||||
* @csi_bwidth_lack_cnt: count of csi bandwidth lack irq
|
||||
* @dvp_bus_err_cnt: count of dvp bus err irq
|
||||
* @dvp_overflow_cnt: count dvp overflow irq
|
||||
* @dvp_line_err_cnt: count dvp line err irq
|
||||
* @dvp_pix_err_cnt: count dvp pix err irq
|
||||
* @all_frm_end_cnt: raw frame end count
|
||||
* @all_err_cnt: all err count
|
||||
* @
|
||||
*/
|
||||
|
||||
u64 csi_overflow_cnt;
|
||||
u64 csi_bwidth_lack_cnt;
|
||||
u64 dvp_bus_err_cnt;
|
||||
u64 dvp_overflow_cnt;
|
||||
u64 dvp_line_err_cnt;
|
||||
u64 dvp_pix_err_cnt;
|
||||
u64 all_frm_end_cnt;
|
||||
u64 all_err_cnt;
|
||||
u64 dvp_size_err_cnt;
|
||||
u64 dvp_bwidth_lack_cnt;
|
||||
u64 csi_size_err_cnt;
|
||||
};
|
||||
|
||||
#define RKCIF_MAX_CSI_CHANNEL 4
|
||||
struct vehicle_csi_channel_info {
|
||||
unsigned char id;
|
||||
unsigned char enable; /* capture enable */
|
||||
unsigned char vc;
|
||||
unsigned char data_type;
|
||||
unsigned char crop_en;
|
||||
unsigned char cmd_mode_en;
|
||||
unsigned char fmt_val;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int virtual_width;
|
||||
unsigned int crop_st_x;
|
||||
unsigned int crop_st_y;
|
||||
};
|
||||
|
||||
struct vehicle_cif {
|
||||
struct device *dev;
|
||||
struct device_node *phy_node;
|
||||
struct rk_cif_clk clk;
|
||||
struct vehicle_cfg cif_cfg;
|
||||
char *base; /*cif base addr*/
|
||||
//unsigned long cru_base;
|
||||
//unsigned long grf_base;
|
||||
void __iomem *cru_base; /*cru base addr*/
|
||||
void __iomem *grf_base; /*grf base addr*/
|
||||
void __iomem *csi2_dphy_base; /*csi2_dphy base addr*/
|
||||
void __iomem *csi2_base; /*csi2 base addr*/
|
||||
struct delayed_work work;
|
||||
|
||||
bool is_enabled;
|
||||
u32 frame_buf[MAX_BUF_NUM];
|
||||
u32 current_buf_index;
|
||||
u32 last_buf_index;
|
||||
u32 active[2];
|
||||
int irq;
|
||||
int csi2_irq1;
|
||||
int csi2_irq2;
|
||||
int drop_frames;
|
||||
struct rk_cif_irqinfo irqinfo;
|
||||
const struct vehicle_cif_reg *cif_regs;
|
||||
struct regmap *regmap_grf;
|
||||
struct regmap *regmap_dphy_grf;
|
||||
unsigned int frame_idx;
|
||||
struct vehicle_rkcif_dummy_buffer dummy_buf;
|
||||
struct csi2_dphy_hw *dphy_hw;
|
||||
int num_channels;
|
||||
int chip_id;
|
||||
int inf_id;
|
||||
unsigned int csi_host_idx;
|
||||
struct vehicle_csi_channel_info channels[RKCIF_MAX_CSI_CHANNEL];
|
||||
spinlock_t vbq_lock; /* vfd lock */
|
||||
bool interlaced_enable;
|
||||
unsigned int interlaced_offset;
|
||||
unsigned int interlaced_counts;
|
||||
unsigned long *interlaced_buffer;
|
||||
atomic_t reset_status;
|
||||
wait_queue_head_t wq_stopped;
|
||||
bool stopping;
|
||||
struct mutex stream_lock;
|
||||
enum rkcif_state state;
|
||||
};
|
||||
|
||||
int vehicle_cif_init_mclk(struct vehicle_cif *cif);
|
||||
int vehicle_cif_init(struct vehicle_cif *cif);
|
||||
int vehicle_cif_deinit(struct vehicle_cif *cif);
|
||||
|
||||
int vehicle_cif_reverse_open(struct vehicle_cfg *v_cfg);
|
||||
|
||||
int vehicle_cif_reverse_close(void);
|
||||
int vehicle_wait_cif_reset_done(void);
|
||||
|
||||
/* CIF IRQ STAT*/
|
||||
#define DMA_FRAME_END (0x01 << 0)
|
||||
#define LINE_END (0x01 << 1)
|
||||
#define IFIFO_OF (0x01 << 4)
|
||||
#define DFIFO_OF (0x01 << 5)
|
||||
#define PRE_INF_FRAME_END (0x01 << 8)
|
||||
#define PST_INF_FRAME_END (0x01 << 9)
|
||||
|
||||
enum rk_camera_signal_polarity {
|
||||
RK_CAMERA_DEVICE_SIGNAL_HIGH_LEVEL = 1,
|
||||
RK_CAMERA_DEVICE_SIGNAL_LOW_LEVEL = 0,
|
||||
};
|
||||
|
||||
enum rk_camera_device_type {
|
||||
RK_CAMERA_DEVICE_BT601_8 = 0x10000011,
|
||||
RK_CAMERA_DEVICE_BT601_10 = 0x10000012,
|
||||
RK_CAMERA_DEVICE_BT601_12 = 0x10000014,
|
||||
RK_CAMERA_DEVICE_BT601_16 = 0x10000018,
|
||||
|
||||
RK_CAMERA_DEVICE_BT656_8 = 0x10000021,
|
||||
RK_CAMERA_DEVICE_BT656_10 = 0x10000022,
|
||||
RK_CAMERA_DEVICE_BT656_12 = 0x10000024,
|
||||
RK_CAMERA_DEVICE_BT656_16 = 0x10000028,
|
||||
|
||||
RK_CAMERA_DEVICE_CVBS_NTSC = 0x20000001,
|
||||
RK_CAMERA_DEVICE_CVBS_PAL = 0x20000002
|
||||
};
|
||||
|
||||
#endif
|
||||
19
drivers/video/rockchip/vehicle/vehicle_cif_regs.h
Normal file
19
drivers/video/rockchip/vehicle/vehicle_cif_regs.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle Driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _VEHICLE_RKCIF_REGS_H
|
||||
#define _VEHICLE_RKCIF_REGS_H
|
||||
#include "../../../media/platform/rockchip/cif/regs.h"
|
||||
|
||||
struct vehicle_cif_reg {
|
||||
u32 offset;
|
||||
char *name;
|
||||
};
|
||||
|
||||
#define CIF_REG_NAME(_offset, _name) { .offset = (_offset), .name = (_name), }
|
||||
|
||||
#endif
|
||||
117
drivers/video/rockchip/vehicle/vehicle_dev.c
Normal file
117
drivers/video/rockchip/vehicle/vehicle_dev.c
Normal file
@@ -0,0 +1,117 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/video/rockchip/video/vehicle_dev.c
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
|
||||
* Authors:
|
||||
* Zhiqin Wei <wzq@rock-chips.com>
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include "vehicle_main.h"
|
||||
#include "vehicle_cfg.h"
|
||||
|
||||
static int vechile_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vechile_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t vechile_write(struct file *file, const char __user *buf,
|
||||
size_t size, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
char data[22] = "";
|
||||
|
||||
ret = copy_from_user(data, buf, 18);
|
||||
|
||||
if (ret)
|
||||
return -1;
|
||||
if (memcmp(data, "88", 2) == 0) {
|
||||
vehicle_android_is_ready_notify();
|
||||
VEHICLE_INFO("android already up, set vehicle in bottom\n");
|
||||
} else {
|
||||
vehicle_apk_state_change(data);
|
||||
VEHICLE_INFO("apk_state_change, open dvr\n");
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
vechile_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct file_operations vechile_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
/*.compat_ioctl = vechile_ioctl,*/
|
||||
.open = vechile_open,
|
||||
.release = vechile_close,
|
||||
.write = vechile_write,
|
||||
.read = vechile_read,
|
||||
};
|
||||
|
||||
static struct miscdevice vechile_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "vehicle",
|
||||
.fops = &vechile_fops,
|
||||
};
|
||||
|
||||
static int __init vechile_module_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* register misc device*/
|
||||
ret = misc_register(&vechile_dev);
|
||||
if (ret) {
|
||||
VEHICLE_DGERR("ERROR: could not register vechile dev\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit vechile_module_exit(void)
|
||||
{
|
||||
misc_deregister(&vechile_dev);
|
||||
}
|
||||
|
||||
module_init(vechile_module_init);
|
||||
module_exit(vechile_module_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
1513
drivers/video/rockchip/vehicle/vehicle_flinger.c
Normal file
1513
drivers/video/rockchip/vehicle/vehicle_flinger.c
Normal file
File diff suppressed because it is too large
Load Diff
115
drivers/video/rockchip/vehicle/vehicle_flinger.h
Normal file
115
drivers/video/rockchip/vehicle/vehicle_flinger.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* drivers/video/rockchip/flinger/flinger.c
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
|
||||
*
|
||||
*/
|
||||
#ifndef __VEHICLE_FLINGER_H
|
||||
#define __VEHICLE_FLINGER_H
|
||||
|
||||
#include "vehicle_cfg.h"
|
||||
#include "../rga3/include/rga.h"
|
||||
#include <linux/types.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
int vehicle_flinger_init(struct device *dev, struct vehicle_cfg *v_cfg);
|
||||
int vehicle_flinger_deinit(void);
|
||||
int vehicle_flinger_reverse_open(struct vehicle_cfg *cfg,
|
||||
bool android_already);
|
||||
int vehicle_flinger_reverse_close(bool android_already);
|
||||
unsigned long vehicle_flinger_request_cif_buffer(void);
|
||||
void vehicle_flinger_commit_cif_buffer(u32 buf_phy_addr);
|
||||
|
||||
enum {
|
||||
RGA_TRANSFORM_ROT_MASK = 0x0000000F,
|
||||
RGA_TRANSFORM_ROT_0 = 0x00000000,
|
||||
RGA_TRANSFORM_ROT_90 = 0x00000001,
|
||||
RGA_TRANSFORM_ROT_180 = 0x00000002,
|
||||
RGA_TRANSFORM_ROT_270 = 0x00000004,
|
||||
|
||||
RGA_TRANSFORM_FLIP_MASK = 0x000000F0,
|
||||
RGA_TRANSFORM_FLIP_H = 0x00000020,
|
||||
RGA_TRANSFORM_FLIP_V = 0x00000010,
|
||||
};
|
||||
/*
|
||||
* pixel format definitions,this is copy from android/system/core/include/system/graphics.h
|
||||
*/
|
||||
enum {
|
||||
HAL_PIXEL_FORMAT_RGBA_8888 = 1,
|
||||
HAL_PIXEL_FORMAT_RGBX_8888 = 2,
|
||||
HAL_PIXEL_FORMAT_RGB_888 = 3,
|
||||
HAL_PIXEL_FORMAT_RGB_565 = 4,
|
||||
HAL_PIXEL_FORMAT_BGRA_8888 = 5,
|
||||
HAL_PIXEL_FORMAT_RGBA_5551 = 6,
|
||||
HAL_PIXEL_FORMAT_RGBA_4444 = 7,
|
||||
|
||||
/* 0x8 - 0xFF range unavailable */
|
||||
|
||||
/*
|
||||
* 0x100 - 0x1FF
|
||||
*
|
||||
* This range is reserved for pixel formats that are specific to the HAL
|
||||
* implementation. Implementations can use any value in this range to
|
||||
* communicate video pixel formats between their HAL modules. These formats
|
||||
* must not have an alpha channel. Additionally, an EGLimage created from a
|
||||
* gralloc buffer of one of these formats must be supported for use with the
|
||||
* GL_OES_EGL_image_external OpenGL ES extension.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Android YUV format:
|
||||
*
|
||||
* This format is exposed outside of the HAL to software decoders and
|
||||
* applications. EGLImageKHR must support it in conjunction with the
|
||||
* OES_EGL_image_external extension.
|
||||
*
|
||||
* YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
|
||||
* by (W/2) x (H/2) Cr and Cb planes.
|
||||
*
|
||||
* This format assumes
|
||||
* - an even width
|
||||
* - an even height
|
||||
* - a horizontal stride multiple of 16 pixels
|
||||
* - a vertical stride equal to the height
|
||||
*
|
||||
* y_size = stride * height
|
||||
* c_size = ALIGN(stride/2, 16) * height/2
|
||||
* size = y_size + c_size * 2
|
||||
* cr_offset = y_size
|
||||
* cb_offset = y_size + c_size
|
||||
*
|
||||
*/
|
||||
HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar
|
||||
|
||||
/* Legacy formats (deprecated), used by ImageFormat.java */
|
||||
|
||||
/*
|
||||
*YCbCr format default is BT601.
|
||||
*/
|
||||
HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16
|
||||
HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21
|
||||
HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, // YUY2
|
||||
HAL_PIXEL_FORMAT_YCrCb_NV12 = 0x20, // YUY2
|
||||
HAL_PIXEL_FORMAT_YCrCb_NV12_VIDEO = 0x21, // YUY2
|
||||
|
||||
HAL_PIXEL_FORMAT_YCrCb_NV12_10 = 0x22, // YUV420_1obit
|
||||
HAL_PIXEL_FORMAT_YCbCr_422_SP_10 = 0x23, // YUV422_1obit
|
||||
HAL_PIXEL_FORMAT_YCrCb_444_SP_10 = 0x24, //YUV444_1obit
|
||||
|
||||
HAL_PIXEL_FORMAT_YCrCb_444 = 0x25, //yuv444
|
||||
HAL_PIXEL_FORMAT_FBDC_RGB565 = 0x26,
|
||||
HAL_PIXEL_FORMAT_FBDC_U8U8U8U8 = 0x27, /*ARGB888*/
|
||||
HAL_PIXEL_FORMAT_FBDC_U8U8U8 = 0x28, /*RGBP888*/
|
||||
HAL_PIXEL_FORMAT_FBDC_RGBA888 = 0x29, /*ABGR888*/
|
||||
HAL_PIXEL_FORMAT_BGRX_8888 = 0x30,
|
||||
HAL_PIXEL_FORMAT_BGR_888 = 0x31,
|
||||
HAL_PIXEL_FORMAT_BGR_565 = 0x32,
|
||||
|
||||
HAL_PIXEL_FORMAT_YUYV422 = 0x33,
|
||||
HAL_PIXEL_FORMAT_YUYV420 = 0x34,
|
||||
HAL_PIXEL_FORMAT_UYVY422 = 0x35,
|
||||
HAL_PIXEL_FORMAT_UYVY420 = 0x36,
|
||||
};
|
||||
|
||||
#endif
|
||||
435
drivers/video/rockchip/vehicle/vehicle_generic_sensor.c
Normal file
435
drivers/video/rockchip/vehicle/vehicle_generic_sensor.c
Normal file
@@ -0,0 +1,435 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/video/rockchip/video/vehicle_generic_sensor.c
|
||||
*
|
||||
* Copyright (C) 2020 Rockchip Electronics Co.Ltd
|
||||
* Authors:
|
||||
* Zhiqin Wei <wzq@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include "vehicle_ad.h"
|
||||
#include "vehicle_ad_7181.h"
|
||||
#include "vehicle_ad_tp2825.h"
|
||||
#include "vehicle_ad_gc2145.h"
|
||||
#include "vehicle_ad_nvp6324.h"
|
||||
#include "vehicle_ad_nvp6188.h"
|
||||
#include "vehicle_ad_max96714.h"
|
||||
#include <linux/moduleparam.h>
|
||||
#include "../../../../drivers/media/i2c/jaguar1_drv/jaguar1_v4l2.h"
|
||||
#include "../../../../drivers/media/i2c/nvp6188.h"
|
||||
#include "../../../../drivers/media/i2c/max96714.h"
|
||||
|
||||
struct vehicle_sensor_ops {
|
||||
const char *name;
|
||||
int (*sensor_init)(struct vehicle_ad_dev *ad);
|
||||
int (*sensor_deinit)(void);
|
||||
int (*sensor_stream)(struct vehicle_ad_dev *ad, int value);
|
||||
int (*sensor_get_cfg)(struct vehicle_cfg **cfg);
|
||||
void (*sensor_check_cif_error)(struct vehicle_ad_dev *ad, int last_line);
|
||||
int (*sensor_check_id_cb)(struct vehicle_ad_dev *ad);
|
||||
void (*sensor_set_channel)(struct vehicle_ad_dev *ad, int channel);
|
||||
int (*sensor_mod_init)(void);
|
||||
};
|
||||
static struct vehicle_sensor_ops *sensor_cb;
|
||||
|
||||
static struct vehicle_sensor_ops sensor_cb_series[] = {
|
||||
{
|
||||
.name = "adv7181",
|
||||
#ifdef CONFIG_VIDEO_REVERSE_AD7181
|
||||
.sensor_init = adv7181_ad_init,
|
||||
.sensor_deinit = adv7181_ad_deinit,
|
||||
.sensor_stream = adv7181_stream,
|
||||
.sensor_get_cfg = adv7181_ad_get_cfg,
|
||||
.sensor_check_cif_error = adv7181_ad_check_cif_error,
|
||||
.sensor_check_id_cb = adv7181_check_id,
|
||||
.sensor_set_channel = adv7181_channel_set
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "tp2825",
|
||||
#ifdef CONFIG_VIDEO_REVERSE_TP2825
|
||||
.sensor_init = tp2825_ad_init,
|
||||
.sensor_deinit = tp2825_ad_deinit,
|
||||
.sensor_stream = tp2825_stream,
|
||||
.sensor_get_cfg = tp2825_ad_get_cfg,
|
||||
.sensor_check_cif_error = tp2825_ad_check_cif_error,
|
||||
.sensor_check_id_cb = tp2825_check_id,
|
||||
.sensor_set_channel = tp2825_channel_set
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "gc2145",
|
||||
#ifdef CONFIG_VIDEO_REVERSE_GC2145
|
||||
.sensor_init = gc2145_ad_init,
|
||||
.sensor_deinit = gc2145_ad_deinit,
|
||||
.sensor_stream = gc2145_stream,
|
||||
.sensor_get_cfg = gc2145_ad_get_cfg,
|
||||
.sensor_check_cif_error = gc2145_ad_check_cif_error,
|
||||
.sensor_check_id_cb = gc2145_check_id,
|
||||
.sensor_set_channel = gc2145_channel_set,
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "nvp6324",
|
||||
#ifdef CONFIG_VIDEO_REVERSE_NVP6324
|
||||
.sensor_init = nvp6324_ad_init,
|
||||
.sensor_deinit = nvp6324_ad_deinit,
|
||||
.sensor_stream = nvp6324_stream,
|
||||
.sensor_get_cfg = nvp6324_ad_get_cfg,
|
||||
.sensor_check_cif_error = nvp6324_ad_check_cif_error,
|
||||
.sensor_check_id_cb = nvp6324_check_id,
|
||||
.sensor_set_channel = nvp6324_channel_set,
|
||||
#ifdef CONFIG_VIDEO_NVP6324
|
||||
.sensor_mod_init = nvp6324_sensor_mod_init
|
||||
#endif
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "max96714",
|
||||
#ifdef CONFIG_VIDEO_REVERSE_MAX96714
|
||||
.sensor_init = max96714_ad_init,
|
||||
.sensor_deinit = max96714_ad_deinit,
|
||||
.sensor_stream = max96714_stream,
|
||||
.sensor_get_cfg = max96714_ad_get_cfg,
|
||||
.sensor_check_cif_error = max96714_ad_check_cif_error,
|
||||
.sensor_check_id_cb = max96714_check_id,
|
||||
.sensor_set_channel = max96714_channel_set,
|
||||
#ifdef CONFIG_VIDEO_MAX96714
|
||||
.sensor_mod_init = max96714_sensor_mod_init
|
||||
#endif
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "nvp6188",
|
||||
#ifdef CONFIG_VIDEO_REVERSE_NVP6188
|
||||
.sensor_init = nvp6188_ad_init,
|
||||
.sensor_deinit = nvp6188_ad_deinit,
|
||||
.sensor_stream = nvp6188_stream,
|
||||
.sensor_get_cfg = nvp6188_ad_get_cfg,
|
||||
.sensor_check_cif_error = nvp6188_ad_check_cif_error,
|
||||
.sensor_check_id_cb = nvp6188_check_id,
|
||||
.sensor_set_channel = nvp6188_channel_set,
|
||||
#ifdef CONFIG_VIDEO_NVP6188
|
||||
.sensor_mod_init = nvp6188_sensor_mod_init
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
int vehicle_generic_sensor_write(struct vehicle_ad_dev *ad, char reg, char *pval)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
|
||||
char *tx_buf = kmalloc(2, GFP_KERNEL);
|
||||
|
||||
if (!tx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(tx_buf, ®, 1);
|
||||
memcpy(tx_buf+1, (char *)pval, 1);
|
||||
|
||||
msg.addr = ad->i2c_add;
|
||||
msg.flags = 0;
|
||||
msg.len = 2;
|
||||
msg.buf = (char *)tx_buf;
|
||||
// msg.scl_rate = ad->i2c_rate;
|
||||
|
||||
ret = i2c_transfer(ad->adapter, &msg, 1);
|
||||
kfree(tx_buf);
|
||||
|
||||
return (ret == 1) ? 4 : ret;
|
||||
}
|
||||
|
||||
int vehicle_sensor_write(struct vehicle_ad_dev *ad, u8 reg, u8 val)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
u8 buf[2];
|
||||
int ret;
|
||||
|
||||
//SENSOR_DG("write reg(0x%x val:0x%x)!\n", reg, val);
|
||||
buf[0] = reg & 0xFF;
|
||||
buf[1] = val;
|
||||
|
||||
msg.addr = ad->i2c_add;
|
||||
msg.flags = 0;
|
||||
msg.buf = buf;
|
||||
msg.len = sizeof(buf);
|
||||
|
||||
ret = i2c_transfer(ad->adapter, &msg, 1);
|
||||
if (ret >= 0)
|
||||
return 0;
|
||||
|
||||
VEHICLE_DGERR("write reg(0x%x val:0x%x) failed !\n", reg, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vehicle_generic_sensor_read(struct vehicle_ad_dev *ad, char reg)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
int ret;
|
||||
char reg_buf[2];
|
||||
char pval;
|
||||
|
||||
memcpy(reg_buf, ®, 1);
|
||||
|
||||
msgs[0].addr = ad->i2c_add;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = reg_buf;
|
||||
// msgs[0].scl_rate = ad->i2c_rate;
|
||||
|
||||
msgs[1].addr = ad->i2c_add;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = 1;
|
||||
msgs[1].buf = &pval;
|
||||
// msgs[1].scl_rate = ad->i2c_rate;
|
||||
|
||||
ret = i2c_transfer(ad->adapter, msgs, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return pval;
|
||||
}
|
||||
|
||||
/* sensor register read */
|
||||
int vehicle_sensor_read(struct vehicle_ad_dev *ad, u8 reg, u8 *val)
|
||||
{
|
||||
struct i2c_msg msg[2];
|
||||
u8 buf[1];
|
||||
int ret;
|
||||
|
||||
buf[0] = reg & 0xFF;
|
||||
|
||||
msg[0].addr = ad->i2c_add;
|
||||
msg[0].flags = 0;
|
||||
msg[0].buf = buf;
|
||||
msg[0].len = sizeof(buf);
|
||||
|
||||
msg[1].addr = ad->i2c_add;
|
||||
msg[1].flags = I2C_M_RD;
|
||||
msg[1].buf = buf;
|
||||
msg[1].len = 1;
|
||||
|
||||
ret = i2c_transfer(ad->adapter, msg, 2);
|
||||
if (ret >= 0) {
|
||||
*val = buf[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(ad->dev,
|
||||
"read reg:0x%x failed !\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vehicle_ad_stream(struct vehicle_ad_dev *ad, int val)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (sensor_cb && sensor_cb->sensor_stream) {
|
||||
ret = sensor_cb->sensor_stream(ad, val);
|
||||
if (ret < 0)
|
||||
VEHICLE_DGERR("%s sensor_init failed!\n", ad->ad_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vehicle_parse_sensor(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
struct device *dev = ad->dev;
|
||||
struct device_node *node = NULL;
|
||||
struct device_node *cp = NULL;
|
||||
enum of_gpio_flags flags;
|
||||
const char *status = NULL;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "ad,fix-format",
|
||||
&ad->fix_format))
|
||||
VEHICLE_DGERR("get fix-format failed!\n");
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "vehicle,rotate-mirror",
|
||||
&ad->cfg.rotate_mirror))
|
||||
VEHICLE_DGERR("get rotate-mirror failed!\n");
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "rockchip,cif-sensor", 0);
|
||||
if (!node) {
|
||||
VEHICLE_DGERR("get cif-sensor dts failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for_each_child_of_node(node, cp) {
|
||||
of_property_read_string(cp, "status", &status);
|
||||
if (status && !strcmp(status, "disabled"))
|
||||
continue;
|
||||
VEHICLE_DG("status: %s\n", status);
|
||||
|
||||
// if (of_property_read_u32(cp, "i2c_rata", &ad->i2c_rate))
|
||||
// SENSOR_DG("Get %s i2c_rata failed!\n", cp->name);
|
||||
if (of_property_read_u32(cp, "i2c_chl", &ad->i2c_chl))
|
||||
VEHICLE_DGERR("Get %s i2c_chl failed!", cp->name);
|
||||
if (of_property_read_u32(cp, "ad_chl", &ad->ad_chl))
|
||||
VEHICLE_DGERR("Get %s ad_chl failed!", cp->name);
|
||||
|
||||
if (ad->ad_chl > 4 || ad->ad_chl < 0) {
|
||||
VEHICLE_DGERR("error, ad_chl %d !\n", ad->ad_chl);
|
||||
ad->ad_chl = 0;
|
||||
}
|
||||
if (of_property_read_u32(cp, "mclk_rate", &ad->mclk_rate))
|
||||
VEHICLE_DGERR("Get %s mclk_rate failed!\n", cp->name);
|
||||
|
||||
if (of_property_read_u32(cp, "rst_active", &ad->rst_active))
|
||||
VEHICLE_DGERR("Get %s rst_active failed!", cp->name);
|
||||
|
||||
ad->reset = of_get_named_gpio_flags(cp, "reset-gpios",
|
||||
0, &flags);
|
||||
|
||||
if (of_property_read_u32(cp, "pwr_active", &ad->pwr_active))
|
||||
VEHICLE_DGERR("Get %s pwr_active failed!\n", cp->name);
|
||||
|
||||
if (of_property_read_u32(cp, "pwdn_active", &ad->pwdn_active))
|
||||
VEHICLE_DGERR("Get %s pwdn_active failed!\n", cp->name);
|
||||
|
||||
ad->power = of_get_named_gpio_flags(cp, "power-gpios",
|
||||
0, &flags);
|
||||
ad->powerdown = of_get_named_gpio_flags(cp,
|
||||
"powerdown-gpios",
|
||||
0, &flags);
|
||||
ad->reset = of_get_named_gpio_flags(cp, "reset-gpios",
|
||||
0, &flags);
|
||||
|
||||
if (of_property_read_u32(cp, "i2c_add", &ad->i2c_add))
|
||||
VEHICLE_DGERR("Get %s i2c_add failed!\n", cp->name);
|
||||
|
||||
ad->i2c_add = (ad->i2c_add >> 1);
|
||||
|
||||
if (of_property_read_u32(cp, "resolution", &ad->resolution))
|
||||
VEHICLE_DGERR("Get %s resolution failed!\n", cp->name);
|
||||
|
||||
of_property_read_u32_array(cp,
|
||||
"rockchip,camera-module-defrect0",
|
||||
(unsigned int *)&ad->defrects[0], 6);
|
||||
of_property_read_u32_array(cp,
|
||||
"rockchip,camera-module-defrect1",
|
||||
(unsigned int *)&ad->defrects[1], 6);
|
||||
of_property_read_u32_array(cp,
|
||||
"rockchip,camera-module-defrect2",
|
||||
(unsigned int *)&ad->defrects[2], 6);
|
||||
of_property_read_u32_array(cp,
|
||||
"rockchip,camera-module-defrect3",
|
||||
(unsigned int *)&ad->defrects[3], 6);
|
||||
|
||||
of_property_read_string(cp,
|
||||
"rockchip,camera-module-interface0",
|
||||
&ad->defrects[0].interface);
|
||||
of_property_read_string(cp,
|
||||
"rockchip,camera-module-interface1",
|
||||
&ad->defrects[1].interface);
|
||||
of_property_read_string(cp,
|
||||
"rockchip,camera-module-interface2",
|
||||
&ad->defrects[2].interface);
|
||||
of_property_read_string(cp,
|
||||
"rockchip,camera-module-interface3",
|
||||
&ad->defrects[3].interface);
|
||||
|
||||
ad->ad_name = cp->name;
|
||||
for (i = 0; i < ARRAY_SIZE(sensor_cb_series); i++) {
|
||||
if (!strcmp(ad->ad_name, sensor_cb_series[i].name))
|
||||
sensor_cb = sensor_cb_series + i;
|
||||
}
|
||||
|
||||
VEHICLE_DG("%s: ad_chl=%d,,ad_addr=%x,fix_for=%d\n", ad->ad_name,
|
||||
ad->ad_chl, ad->i2c_add, ad->fix_format);
|
||||
VEHICLE_DG("gpio power:%d, active:%d\n", ad->power, ad->pwr_active);
|
||||
VEHICLE_DG("gpio powerdown:%d, active:%d\n",
|
||||
ad->powerdown, ad->pwdn_active);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ad->ad_name)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vehicle_ad_channel_set(struct vehicle_ad_dev *ad, int channel)
|
||||
{
|
||||
if (sensor_cb->sensor_set_channel)
|
||||
sensor_cb->sensor_set_channel(ad, channel);
|
||||
}
|
||||
|
||||
int vehicle_ad_init(struct vehicle_ad_dev *ad)
|
||||
{
|
||||
int ret = 0;
|
||||
//WARN_ON(1);
|
||||
VEHICLE_DGERR("%s(%d) ad_name:%s!", __func__, __LINE__, ad->ad_name);
|
||||
|
||||
if (sensor_cb->sensor_init) {
|
||||
ret = sensor_cb->sensor_init(ad);
|
||||
if (ret < 0) {
|
||||
VEHICLE_DGERR("%s sensor_init failed!\n", ad->ad_name);
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
VEHICLE_DGERR("%s sensor_init is NULL!\n", ad->ad_name);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sensor_cb->sensor_check_id_cb) {
|
||||
ret = sensor_cb->sensor_check_id_cb(ad);
|
||||
if (ret < 0)
|
||||
VEHICLE_DGERR("%s check id failed!\n", ad->ad_name);
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vehicle_ad_deinit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (sensor_cb->sensor_deinit)
|
||||
ret = sensor_cb->sensor_deinit();
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vehicle_to_v4l2_drv_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
VEHICLE_DG("%s(%d) enter!", __func__, __LINE__);
|
||||
if (sensor_cb && sensor_cb->sensor_mod_init)
|
||||
ret = sensor_cb->sensor_mod_init();
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct vehicle_cfg *vehicle_ad_get_vehicle_cfg(void)
|
||||
{
|
||||
struct vehicle_cfg *cfg = NULL;
|
||||
|
||||
if (sensor_cb->sensor_get_cfg)
|
||||
sensor_cb->sensor_get_cfg(&cfg);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
void vehicle_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
|
||||
{
|
||||
if (sensor_cb->sensor_get_cfg)
|
||||
sensor_cb->sensor_check_cif_error(ad, last_line);
|
||||
}
|
||||
182
drivers/video/rockchip/vehicle/vehicle_gpio.c
Normal file
182
drivers/video/rockchip/vehicle/vehicle_gpio.c
Normal file
@@ -0,0 +1,182 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/video/rockchip/video/vehicle_gpio.c
|
||||
*
|
||||
* Copyright (C) 2020 Rockchip Electronics Co.Ltd
|
||||
* Authors:
|
||||
* Jianwei Fan <jianwei.fan@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "vehicle_gpio.h"
|
||||
#include "vehicle_main.h"
|
||||
|
||||
static void gpio_det_work_func(struct work_struct *work)
|
||||
{
|
||||
struct gpio_detect *gpiod = container_of(work, struct gpio_detect,
|
||||
work.work);
|
||||
int val = gpio_get_value(gpiod->gpio);
|
||||
|
||||
VEHICLE_DG("%s: gpiod->old val(%d), new val(%d)\n",
|
||||
__func__, gpiod->val, val);
|
||||
|
||||
if (gpiod->val != val) {
|
||||
gpiod->val = val;
|
||||
vehicle_gpio_stat_change_notify();
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_det_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct gpio_detect *gpiod = dev_id;
|
||||
int val = gpio_get_value(gpiod->gpio);
|
||||
unsigned int irqflags = IRQF_ONESHOT;
|
||||
|
||||
if (val)
|
||||
irqflags |= IRQ_TYPE_EDGE_FALLING;
|
||||
else
|
||||
irqflags |= IRQ_TYPE_EDGE_RISING;
|
||||
irq_set_irq_type(gpiod->irq, irqflags);
|
||||
|
||||
mod_delayed_work(system_wq, &gpiod->work,
|
||||
msecs_to_jiffies(gpiod->debounce_ms));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int vehicle_gpio_init_check(struct gpio_detect *gpiod)
|
||||
{
|
||||
gpiod->val = gpio_get_value(gpiod->gpio);
|
||||
|
||||
dev_info(gpiod->dev, "%s: gpiod->atv_val(%d), gpiod->val(%d)\n",
|
||||
__func__, gpiod->atv_val, gpiod->val);
|
||||
|
||||
if (gpiod->atv_val == gpiod->val) {
|
||||
vehicle_gpio_stat_change_notify();
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool vehicle_gpio_reverse_check(struct gpio_detect *gpiod)
|
||||
{
|
||||
int val = gpiod->val ^ gpiod->atv_val;
|
||||
|
||||
if (gpiod->num == 0)
|
||||
return true;
|
||||
else
|
||||
return (val == 0) ? true : false;
|
||||
}
|
||||
|
||||
static int gpio_parse_dt(struct gpio_detect *gpiod, const char *ad_name)
|
||||
{
|
||||
struct device *dev = gpiod->dev;
|
||||
struct device_node *gpiod_node;
|
||||
struct device_node *node;
|
||||
const char *name;
|
||||
// int num;
|
||||
int ret = 0;
|
||||
|
||||
gpiod_node = of_parse_phandle(dev->of_node, "rockchip,gpio-det", 0);
|
||||
if (!gpiod_node) {
|
||||
VEHICLE_DGERR("phase gpio-det from dts failed, maybe no use!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
gpiod->num = of_get_child_count(gpiod_node);
|
||||
if (gpiod->num == 0) {
|
||||
VEHICLE_DGERR("gpio-det child count is 0, maybe no use!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
of_property_read_u32(gpiod_node, "rockchip,camcap-mirror",
|
||||
&gpiod->mirror);
|
||||
for_each_child_of_node(gpiod_node, node) {
|
||||
enum of_gpio_flags flags;
|
||||
|
||||
name = of_get_property(node, "label", NULL);
|
||||
if (!strcmp(name, "car-reverse")) {
|
||||
gpiod->gpio = of_get_named_gpio_flags(node, "car-reverse-gpios", 0, &flags);
|
||||
if (!gpio_is_valid(gpiod->gpio)) {
|
||||
dev_err(dev, "failed to get car reverse gpio\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
gpiod->atv_val = !(flags & OF_GPIO_ACTIVE_LOW);
|
||||
of_property_read_u32(node, "linux,debounce-ms",
|
||||
&gpiod->debounce_ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VEHICLE_DG("%s:gpio %d, act_val %d, mirror %d, debounce_ms %d\n",
|
||||
__func__, gpiod->gpio, gpiod->atv_val, gpiod->mirror, gpiod->debounce_ms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vehicle_gpio_init(struct gpio_detect *gpiod, const char *ad_name)
|
||||
{
|
||||
int gpio;
|
||||
int ret;
|
||||
unsigned long irqflags = IRQF_ONESHOT;
|
||||
|
||||
if (gpio_parse_dt(gpiod, ad_name) < 0) {
|
||||
VEHICLE_DGERR("%s,parse dt failed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio = gpiod->gpio;
|
||||
|
||||
ret = gpio_request(gpio, "vehicle");
|
||||
if (ret < 0)
|
||||
VEHICLE_DGERR("%s:failed to request gpio %d, maybe no use\n", __func__, ret);
|
||||
|
||||
dev_info(gpiod->dev, "%s: request irq gpio(%d)\n", __func__, gpio);
|
||||
gpio_direction_input(gpio);
|
||||
|
||||
gpiod->irq = gpio_to_irq(gpio);
|
||||
if (gpiod->irq < 0)
|
||||
VEHICLE_DGERR("failed to get irq, GPIO %d, maybe no use\n", gpio);
|
||||
|
||||
gpiod->val = gpio_get_value(gpio);
|
||||
if (gpiod->val)
|
||||
irqflags |= IRQ_TYPE_EDGE_FALLING;
|
||||
else
|
||||
irqflags |= IRQ_TYPE_EDGE_RISING;
|
||||
ret = devm_request_threaded_irq(gpiod->dev, gpiod->irq,
|
||||
NULL, gpio_det_interrupt,
|
||||
irqflags, "vehicle gpio", gpiod);
|
||||
if (ret < 0)
|
||||
VEHICLE_DGERR("request irq(%s) failed:%d\n",
|
||||
"vehicle", ret);
|
||||
|
||||
//if not add in create_workqueue only execute once;
|
||||
INIT_DELAYED_WORK(&gpiod->work, gpio_det_work_func);
|
||||
|
||||
vehicle_gpio_init_check(gpiod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vehicle_gpio_deinit(struct gpio_detect *gpiod)
|
||||
{
|
||||
free_irq(gpiod->irq, gpiod);
|
||||
gpio_free(gpiod->gpio);
|
||||
return 0;
|
||||
}
|
||||
33
drivers/video/rockchip/vehicle/vehicle_gpio.h
Normal file
33
drivers/video/rockchip/vehicle/vehicle_gpio.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_GPIO_H
|
||||
#define __VEHICLE_GPIO_H
|
||||
|
||||
#include "vehicle_cfg.h"
|
||||
|
||||
struct gpio_detect {
|
||||
int gpio;
|
||||
int atv_val;
|
||||
int val;
|
||||
int irq;
|
||||
int mirror;
|
||||
int num;
|
||||
unsigned int debounce_ms;
|
||||
struct delayed_work work;
|
||||
struct device *dev;
|
||||
};
|
||||
/*
|
||||
* true : reverse on
|
||||
* false : reverse over
|
||||
*/
|
||||
bool vehicle_gpio_reverse_check(struct gpio_detect *gpiod);
|
||||
|
||||
int vehicle_gpio_init(struct gpio_detect *gpiod, const char *ad_name);
|
||||
|
||||
int vehicle_gpio_deinit(struct gpio_detect *gpiod);
|
||||
|
||||
#endif
|
||||
504
drivers/video/rockchip/vehicle/vehicle_main.c
Normal file
504
drivers/video/rockchip/vehicle/vehicle_main.c
Normal file
@@ -0,0 +1,504 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/video/rockchip/video/vehicle_main.c
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
|
||||
* Authors:
|
||||
* Zhiqin Wei <wzq@rock-chips.com>
|
||||
* <randy.wang@rock-chips.com>
|
||||
* Jianwei Fan <jianwei.fan@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#define CAMMODULE_NAME "vehicle_main"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include "vehicle_flinger.h"
|
||||
#include "vehicle_cfg.h"
|
||||
#include "vehicle_ad.h"
|
||||
#include "vehicle_main.h"
|
||||
#include "vehicle_cif.h"
|
||||
#include "vehicle_gpio.h"
|
||||
#include <linux/version.h>
|
||||
#include "../../../media/platform/rockchip/cif/hw.h"
|
||||
#include "../../../media/platform/rockchip/cif/dev.h"
|
||||
// #include "../../../media/platform/rockchip/cif/mipi-csi2.h"
|
||||
#include "../../../phy/rockchip/phy-rockchip-csi2-dphy-common.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x03, 0x00)
|
||||
|
||||
static bool flinger_inited;
|
||||
static bool TEST_GPIO = true;
|
||||
static bool dvr_apk_need_start;
|
||||
|
||||
enum {
|
||||
STATE_CLOSE = 0,
|
||||
STATE_OPEN,
|
||||
};
|
||||
|
||||
struct vehicle {
|
||||
struct device *dev;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
struct wake_lock wake_lock;
|
||||
struct gpio_detect gpio_data;
|
||||
struct vehicle_cif cif;
|
||||
struct vehicle_ad_dev ad;
|
||||
int mirror;
|
||||
wait_queue_head_t vehicle_wait;
|
||||
atomic_t vehicle_atomic;
|
||||
int state;
|
||||
bool android_is_ready;
|
||||
bool gpio_over;
|
||||
};
|
||||
|
||||
static struct vehicle *g_vehicle;
|
||||
|
||||
static int vehicle_parse_dt(struct vehicle *vehicle_info)
|
||||
{
|
||||
struct device *dev = vehicle_info->dev;
|
||||
|
||||
/* 1. pinctrl */
|
||||
vehicle_info->pinctrl = devm_pinctrl_get(dev);
|
||||
|
||||
if (IS_ERR(vehicle_info->pinctrl)) {
|
||||
dev_err(dev, "pinctrl get failed\n");
|
||||
return PTR_ERR(vehicle_info->pinctrl);
|
||||
}
|
||||
|
||||
vehicle_info->pins_default = pinctrl_lookup_state(vehicle_info->pinctrl,
|
||||
"default");
|
||||
|
||||
if (IS_ERR(vehicle_info->pins_default))
|
||||
dev_err(dev, "get default pinstate failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vehicle_ad_stat_change_notify(void)
|
||||
{
|
||||
if (g_vehicle) {
|
||||
VEHICLE_INFO("ad state change! set atpmic to 1!\n");
|
||||
atomic_set(&g_vehicle->vehicle_atomic, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void vehicle_cif_stat_change_notify(void)
|
||||
{
|
||||
if (g_vehicle) {
|
||||
VEHICLE_INFO("cif state change! set atpmic to 1!\n");
|
||||
atomic_set(&g_vehicle->vehicle_atomic, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void vehicle_gpio_stat_change_notify(void)
|
||||
{
|
||||
if (g_vehicle && !g_vehicle->gpio_over) {
|
||||
VEHICLE_INFO("reverse gpio state change! set atpmic to 1!\n");
|
||||
atomic_set(&g_vehicle->vehicle_atomic, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void vehicle_cif_error_notify(int last_line)
|
||||
{
|
||||
if (g_vehicle) {
|
||||
VEHICLE_INFO("cif error notify\n");
|
||||
vehicle_ad_check_cif_error(&g_vehicle->ad, last_line);
|
||||
}
|
||||
}
|
||||
|
||||
static void vehicle_open(struct vehicle_cfg *v_cfg)
|
||||
{
|
||||
VEHICLE_INFO("%s enter: android_is_ready ?= %d",
|
||||
__func__, g_vehicle->android_is_ready);
|
||||
vehicle_flinger_reverse_open(v_cfg, g_vehicle->android_is_ready);
|
||||
vehicle_cif_reverse_open(v_cfg);
|
||||
}
|
||||
|
||||
static void vehicle_close(void)
|
||||
{
|
||||
vehicle_cif_reverse_close();
|
||||
vehicle_flinger_reverse_close(g_vehicle->android_is_ready);
|
||||
}
|
||||
|
||||
static void vehicle_open_close(void)
|
||||
{
|
||||
vehicle_cif_reverse_close();
|
||||
}
|
||||
|
||||
static int vehicle_state_change(struct vehicle *v)
|
||||
{
|
||||
struct vehicle_cfg *v_cfg;
|
||||
struct gpio_detect *gpiod = &v->gpio_data;
|
||||
bool gpio_reverse_on;
|
||||
int ret = 0;
|
||||
|
||||
/* 1. get ad sensor cfg */
|
||||
v_cfg = vehicle_ad_get_vehicle_cfg();
|
||||
|
||||
if (!v_cfg) {
|
||||
VEHICLE_DGERR("v_cfg is NULL, if for test continue.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!flinger_inited) {
|
||||
do {
|
||||
/* 2. flinger */
|
||||
VEHICLE_DG("%s: flinger init start\r\n", __func__);
|
||||
ret = vehicle_flinger_init(v->dev, v_cfg);
|
||||
if (ret < 0) {
|
||||
VEHICLE_DG("rk_vehicle_system_main: flinger init failed\r\n");
|
||||
msleep(20);
|
||||
}
|
||||
} while (ret);
|
||||
}
|
||||
VEHICLE_DG("%s: flinger init success\r\n", __func__);
|
||||
flinger_inited = true;
|
||||
|
||||
gpio_reverse_on = vehicle_gpio_reverse_check(gpiod);
|
||||
gpio_reverse_on = TEST_GPIO & gpio_reverse_on;
|
||||
VEHICLE_DG(
|
||||
"%s, gpio = reverse %s, width = %d, sensor_ready = %d, state=%d dvr_apk_need_start = %d\n",
|
||||
__func__, gpio_reverse_on ? "on" : "over",
|
||||
v_cfg->width, v_cfg->ad_ready, v->state, dvr_apk_need_start);
|
||||
if (v_cfg->mbus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) {
|
||||
switch (v->state) {
|
||||
case STATE_CLOSE:
|
||||
if (dvr_apk_need_start) {
|
||||
vehicle_open(v_cfg);
|
||||
msleep(20);
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
v->state = STATE_OPEN;
|
||||
}
|
||||
if (gpio_reverse_on) {
|
||||
vehicle_open(v_cfg);
|
||||
msleep(20);
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
v->state = STATE_OPEN;
|
||||
}
|
||||
break;
|
||||
case STATE_OPEN:
|
||||
/* reverse exit || video loss */
|
||||
if (!dvr_apk_need_start && (!gpio_reverse_on || !v_cfg->ad_ready)) {
|
||||
vehicle_close();
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
v->state = STATE_CLOSE;
|
||||
} else if (gpio_reverse_on) { // reverse on & video format change
|
||||
vehicle_open_close();
|
||||
vehicle_open(v_cfg);
|
||||
msleep(100);
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
} else if (!gpio_reverse_on && dvr_apk_need_start) {
|
||||
vehicle_close();
|
||||
vehicle_open(v_cfg);
|
||||
msleep(20);
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (v_cfg->mbus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) {
|
||||
switch (v->state) {
|
||||
case STATE_CLOSE:
|
||||
if (dvr_apk_need_start) {
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(20);
|
||||
vehicle_open(v_cfg);
|
||||
v->state = STATE_OPEN;
|
||||
}
|
||||
if (gpio_reverse_on) {
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(20);
|
||||
vehicle_open(v_cfg);
|
||||
v->state = STATE_OPEN;
|
||||
}
|
||||
break;
|
||||
case STATE_OPEN:
|
||||
/* reverse exit || video loss */
|
||||
if (!dvr_apk_need_start && (!gpio_reverse_on || !v_cfg->ad_ready)) {
|
||||
vehicle_close();
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
v->state = STATE_CLOSE;
|
||||
} else if (gpio_reverse_on) { // reverse on & video format change
|
||||
vehicle_open_close();
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(100);
|
||||
vehicle_open(v_cfg);
|
||||
} else if (!gpio_reverse_on && dvr_apk_need_start) {
|
||||
vehicle_close();
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(20);
|
||||
vehicle_open(v_cfg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (v->state) {
|
||||
case STATE_CLOSE:
|
||||
if (dvr_apk_need_start) {
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(20);
|
||||
vehicle_open(v_cfg);
|
||||
v->state = STATE_OPEN;
|
||||
}
|
||||
if (gpio_reverse_on) {
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(20);
|
||||
vehicle_open(v_cfg);
|
||||
v->state = STATE_OPEN;
|
||||
}
|
||||
break;
|
||||
case STATE_OPEN:
|
||||
/* reverse exit || video loss */
|
||||
if (!dvr_apk_need_start && (!gpio_reverse_on || !v_cfg->ad_ready)) {
|
||||
vehicle_close();
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
v->state = STATE_CLOSE;
|
||||
} else if (gpio_reverse_on) { // reverse on & video format change
|
||||
vehicle_open_close();
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(100);
|
||||
vehicle_open(v_cfg);
|
||||
} else if (!gpio_reverse_on && dvr_apk_need_start) {
|
||||
vehicle_close();
|
||||
vehicle_ad_stream(&v->ad, 0);
|
||||
vehicle_ad_channel_set(&g_vehicle->ad, 0);
|
||||
vehicle_ad_stream(&v->ad, 1);
|
||||
msleep(20);
|
||||
vehicle_open(v_cfg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vehicle_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vehicle *vehicle_info;
|
||||
|
||||
dev_info(&pdev->dev, "driver version: %02x.%02x.%02x",
|
||||
DRIVER_VERSION >> 16,
|
||||
(DRIVER_VERSION & 0xff00) >> 8,
|
||||
DRIVER_VERSION & 0x00ff);
|
||||
|
||||
vehicle_info = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct vehicle), GFP_KERNEL);
|
||||
if (!vehicle_info)
|
||||
return -ENOMEM;
|
||||
|
||||
vehicle_info->dev = &pdev->dev;
|
||||
vehicle_info->gpio_data.dev = &pdev->dev;
|
||||
vehicle_info->cif.dev = &pdev->dev;
|
||||
vehicle_info->ad.dev = &pdev->dev;
|
||||
|
||||
dev_set_name(vehicle_info->dev, "vehicle_main");
|
||||
if (!pdev->dev.of_node)
|
||||
return -EINVAL;
|
||||
|
||||
vehicle_parse_dt(vehicle_info);
|
||||
|
||||
if (vehicle_parse_sensor(&vehicle_info->ad) < 0) {
|
||||
VEHICLE_DGERR("parse sensor failed!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wake_lock_init(&vehicle_info->wake_lock, WAKE_LOCK_SUSPEND, "vehicle");
|
||||
|
||||
dev_info(vehicle_info->dev, "vehicle driver probe success\n");
|
||||
|
||||
init_waitqueue_head(&vehicle_info->vehicle_wait);
|
||||
atomic_set(&vehicle_info->vehicle_atomic, 0);
|
||||
vehicle_info->state = STATE_CLOSE;
|
||||
vehicle_info->android_is_ready = false;
|
||||
vehicle_info->gpio_over = false;
|
||||
|
||||
g_vehicle = vehicle_info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id vehicle_of_match[] = {
|
||||
{ .compatible = "rockchip,vehicle", },
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver vehicle_driver = {
|
||||
.driver = {
|
||||
.name = "vehicle",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(vehicle_of_match),
|
||||
},
|
||||
.probe = vehicle_probe,
|
||||
};
|
||||
|
||||
void vehicle_android_is_ready_notify(void)
|
||||
{
|
||||
if (g_vehicle)
|
||||
g_vehicle->android_is_ready = true;
|
||||
TEST_GPIO = !TEST_GPIO;
|
||||
atomic_set(&g_vehicle->vehicle_atomic, 1);
|
||||
}
|
||||
|
||||
void vehicle_apk_state_change(char data[22])
|
||||
{
|
||||
if (memcmp(data, "11", 2) == 0)
|
||||
dvr_apk_need_start = true;
|
||||
else if (memcmp(data, "10", 2) == 0)
|
||||
dvr_apk_need_start = false;
|
||||
|
||||
if (g_vehicle)
|
||||
atomic_set(&g_vehicle->vehicle_atomic, 1);
|
||||
}
|
||||
|
||||
static void vehicle_exit_complete_notify(struct vehicle *v)
|
||||
{
|
||||
char *status = NULL;
|
||||
char *envp[2];
|
||||
|
||||
if (!v)
|
||||
return;
|
||||
status = kasprintf(GFP_KERNEL, "vehicle_exit=done");
|
||||
envp[0] = status;
|
||||
envp[1] = NULL;
|
||||
wake_lock_timeout(&v->wake_lock, 5 * HZ);
|
||||
kobject_uevent_env(&v->dev->kobj, KOBJ_CHANGE, envp);
|
||||
|
||||
kfree(status);
|
||||
}
|
||||
|
||||
static int rk_vehicle_system_main(void *arg)
|
||||
{
|
||||
int ret = -1;
|
||||
struct vehicle *v = g_vehicle;
|
||||
int loop_times = 0;
|
||||
|
||||
if (!g_vehicle) {
|
||||
VEHICLE_DGERR("vehicle probe failed, g_vehicle is NULL.\n");
|
||||
goto VEHICLE_EXIT;
|
||||
}
|
||||
|
||||
/* 0. gpio init and check state */
|
||||
ret = vehicle_gpio_init(&v->gpio_data, v->ad.ad_name);
|
||||
if (ret < 0) {
|
||||
VEHICLE_DGERR("%s: gpio init failed\r\n", __func__);
|
||||
goto VEHICLE_GPIO_DEINIT;
|
||||
}
|
||||
VEHICLE_DG("vehicle_gpio_init ok!\n");
|
||||
|
||||
/* 1.ad */
|
||||
VEHICLE_DG("%s: vehicle_ad_init start\r\n", __func__);
|
||||
/* config mclk first */
|
||||
ret = vehicle_cif_init_mclk(&v->cif);
|
||||
ret |= vehicle_ad_init(&v->ad);
|
||||
if (ret < 0) {
|
||||
VEHICLE_DGERR("%s: ad init failed\r\n", __func__);
|
||||
goto VEHICLE_AD_DEINIT;
|
||||
}
|
||||
VEHICLE_DG("vehicle_ad_init ok!\r\n");
|
||||
|
||||
/* 3. cif init */
|
||||
ret = vehicle_cif_init(&v->cif);
|
||||
if (ret < 0) {
|
||||
VEHICLE_DGERR("%s: cif init failed\r\n", __func__);
|
||||
goto VEHICLE_CIF_DEINIT;
|
||||
}
|
||||
VEHICLE_DG("%s: vehicle_cif_init ok!\r\n", __func__);
|
||||
pm_runtime_enable(v->dev);
|
||||
pm_runtime_get_sync(v->dev);
|
||||
|
||||
//while (STATE_OPEN == v->state || !v->vehicle_need_exit) {
|
||||
while (v->state == STATE_OPEN || !v->android_is_ready) {
|
||||
if (v->android_is_ready && !v->state)
|
||||
v->gpio_over = true;
|
||||
wait_event_timeout(v->vehicle_wait,
|
||||
atomic_read(&v->vehicle_atomic),
|
||||
msecs_to_jiffies(100));
|
||||
if (atomic_read(&v->vehicle_atomic)) {
|
||||
atomic_set(&v->vehicle_atomic, 0);
|
||||
vehicle_state_change(v);
|
||||
}
|
||||
VEHICLE_DG("loop time(%d) \r\n", loop_times);
|
||||
loop_times++;
|
||||
}
|
||||
|
||||
VEHICLE_CIF_DEINIT:
|
||||
vehicle_cif_deinit(&v->cif);
|
||||
|
||||
VEHICLE_AD_DEINIT:
|
||||
vehicle_ad_deinit();
|
||||
|
||||
VEHICLE_GPIO_DEINIT:
|
||||
vehicle_gpio_deinit(&v->gpio_data);
|
||||
|
||||
/*Init normal drivers*/
|
||||
VEHICLE_EXIT:
|
||||
if (flinger_inited)
|
||||
vehicle_flinger_deinit();
|
||||
// if (v && v->pinctrl)
|
||||
// pinctrl_put(v->pinctrl);
|
||||
vehicle_to_v4l2_drv_init();
|
||||
msleep(500);
|
||||
rockchip_csi2_dphy_hw_init();
|
||||
rockchip_csi2_dphy_init();
|
||||
rk_cif_plat_drv_init();
|
||||
// rkcif_csi2_plat_drv_init();
|
||||
rkcif_clr_unready_dev();
|
||||
#ifdef CONFIG_GPIO_DET
|
||||
//gpio_det_init();
|
||||
#endif
|
||||
// msleep(1000);
|
||||
vehicle_exit_complete_notify(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init vehicle_system_start(void)
|
||||
{
|
||||
platform_driver_register(&vehicle_driver);
|
||||
kthread_run(rk_vehicle_system_main, NULL, "vehicle main");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall_sync(vehicle_system_start);
|
||||
18
drivers/video/rockchip/vehicle/vehicle_main.h
Normal file
18
drivers/video/rockchip/vehicle/vehicle_main.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#ifndef __VEHICLE_MAIN_H
|
||||
#define __VEHICLE_MAIN_H
|
||||
|
||||
/* impl by vehicle_main, call by ad detect */
|
||||
void vehicle_ad_stat_change_notify(void);
|
||||
void vehicle_cif_stat_change_notify(void);
|
||||
void vehicle_gpio_stat_change_notify(void);
|
||||
void vehicle_cif_error_notify(int last_line);
|
||||
void vehicle_android_is_ready_notify(void);
|
||||
void vehicle_apk_state_change(char crtc[22]);
|
||||
|
||||
#endif
|
||||
246
drivers/video/rockchip/vehicle/vehicle_samsung_dcphy_common.h
Normal file
246
drivers/video/rockchip/vehicle/vehicle_samsung_dcphy_common.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VEHICLE_SAMSUNG_DCPHY_COMMON_H_
|
||||
#define _VEHICLE_SAMSUNG_DCPHY_COMMON_H_
|
||||
|
||||
#define MAX_NUM_CSI2_DPHY (0x2)
|
||||
|
||||
/*redefine samsung_mipi_dcphy info*/
|
||||
struct samsung_mipi_dcphy {
|
||||
struct device *dev;
|
||||
struct clk *ref_clk;
|
||||
struct clk *pclk;
|
||||
struct regmap *regmap;
|
||||
struct regmap *grf_regmap;
|
||||
struct reset_control *m_phy_rst;
|
||||
struct reset_control *s_phy_rst;
|
||||
struct reset_control *apb_rst;
|
||||
struct reset_control *grf_apb_rst;
|
||||
struct mutex mutex;
|
||||
struct csi2_dphy *dphy_dev[MAX_NUM_CSI2_DPHY];
|
||||
atomic_t stream_cnt;
|
||||
int dphy_dev_num;
|
||||
bool c_option;
|
||||
|
||||
unsigned int lanes;
|
||||
|
||||
struct {
|
||||
unsigned long long rate;
|
||||
u8 prediv;
|
||||
u16 fbdiv;
|
||||
long dsm;
|
||||
u8 scaler;
|
||||
|
||||
bool ssc_en;
|
||||
u8 mfr;
|
||||
u8 mrr;
|
||||
} pll;
|
||||
|
||||
int (*stream_on)(struct csi2_dphy *dphy, struct v4l2_subdev *sd);
|
||||
int (*stream_off)(struct csi2_dphy *dphy, struct v4l2_subdev *sd);
|
||||
|
||||
/*for vehicle*/
|
||||
struct csi2_dphy_hw *dphy_vehicle[MAX_NUM_CSI2_DPHY];
|
||||
int dphy_vehicle_num;
|
||||
};
|
||||
|
||||
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
|
||||
|
||||
/*samsung mipi dcphy register*/
|
||||
#define BIAS_CON0 0x0000
|
||||
#define BIAS_CON1 0x0004
|
||||
#define BIAS_CON2 0x0008
|
||||
#define BIAS_CON4 0x0010
|
||||
#define I_MUX_SEL_MASK GENMASK(6, 5)
|
||||
#define I_MUX_SEL(x) UPDATE(x, 6, 5)
|
||||
|
||||
#define PLL_CON0 0x0100
|
||||
#define PLL_EN BIT(12)
|
||||
#define S_MASK GENMASK(10, 8)
|
||||
#define S(x) UPDATE(x, 10, 8)
|
||||
#define P_MASK GENMASK(5, 0)
|
||||
#define P(x) UPDATE(x, 5, 0)
|
||||
#define PLL_CON1 0x0104
|
||||
#define PLL_CON2 0x0108
|
||||
#define M_MASK GENMASK(9, 0)
|
||||
#define M(x) UPDATE(x, 9, 0)
|
||||
#define PLL_CON3 0x010c
|
||||
#define MRR_MASK GENMASK(13, 8)
|
||||
#define MRR(x) UPDATE(x, 13, 8)
|
||||
#define MFR_MASK GENMASK(7, 0)
|
||||
#define MFR(x) UPDATE(x, 7, 0)
|
||||
#define PLL_CON4 0x0110
|
||||
#define SSCG_EN BIT(11)
|
||||
#define PLL_CON5 0x0114
|
||||
#define RESET_N_SEL BIT(10)
|
||||
#define PLL_ENABLE_SEL BIT(8)
|
||||
#define PLL_CON6 0x0118
|
||||
#define PLL_CON7 0x011c
|
||||
#define PLL_LOCK_CNT(x) UPDATE(x, 15, 0)
|
||||
#define PLL_CON8 0x0120
|
||||
#define PLL_STB_CNT(x) UPDATE(x, 15, 0)
|
||||
#define PLL_STAT0 0x0140
|
||||
#define PLL_LOCK BIT(0)
|
||||
|
||||
#define DPHY_MC_GNR_CON0 0x0300
|
||||
#define PHY_READY BIT(1)
|
||||
#define PHY_ENABLE BIT(0)
|
||||
#define DPHY_MC_GNR_CON1 0x0304
|
||||
#define T_PHY_READY(x) UPDATE(x, 15, 0)
|
||||
#define DPHY_MC_ANA_CON0 0x0308
|
||||
#define DPHY_MC_ANA_CON1 0x030c
|
||||
#define DPHY_MC_ANA_CON2 0x0310
|
||||
#define HS_VREG_AMP_ICON(x) UPDATE(x, 1, 0)
|
||||
#define DPHY_MC_TIME_CON0 0x0330
|
||||
#define HSTX_CLK_SEL BIT(12)
|
||||
#define T_LPX(x) UPDATE(x, 11, 4)
|
||||
#define DPHY_MC_TIME_CON1 0x0334
|
||||
#define T_CLK_ZERO(x) UPDATE(x, 15, 8)
|
||||
#define T_CLK_PREPARE(x) UPDATE(x, 7, 0)
|
||||
#define DPHY_MC_TIME_CON2 0x0338
|
||||
#define T_HS_EXIT(x) UPDATE(x, 15, 8)
|
||||
#define T_CLK_TRAIL(x) UPDATE(x, 7, 0)
|
||||
#define DPHY_MC_TIME_CON3 0x033c
|
||||
#define T_CLK_POST(x) UPDATE(x, 7, 0)
|
||||
#define DPHY_MC_TIME_CON4 0x0340
|
||||
#define T_ULPS_EXIT(x) UPDATE(x, 9, 0)
|
||||
#define DPHY_MC_DESKEW_CON0 0x0350
|
||||
#define SKEW_CAL_RUN_TIME(x) UPDATE(x, 15, 12)
|
||||
|
||||
#define SKEW_CAL_INIT_RUN_TIME(x) UPDATE(x, 11, 8)
|
||||
#define SKEW_CAL_INIT_WAIT_TIME(x) UPDATE(x, 7, 4)
|
||||
#define SKEW_CAL_EN BIT(0)
|
||||
|
||||
#define COMBO_MD0_GNR_CON0 0x0400
|
||||
#define COMBO_MD0_GNR_CON1 0x0404
|
||||
#define COMBO_MD0_ANA_CON0 0x0408
|
||||
#define COMBO_MD0_ANA_CON1 0x040C
|
||||
#define COMBO_MD0_ANA_CON2 0x0410
|
||||
|
||||
#define COMBO_MD0_TIME_CON0 0x0430
|
||||
#define COMBO_MD0_TIME_CON1 0x0434
|
||||
#define COMBO_MD0_TIME_CON2 0x0438
|
||||
#define COMBO_MD0_TIME_CON3 0x043C
|
||||
#define COMBO_MD0_TIME_CON4 0x0440
|
||||
#define COMBO_MD0_DATA_CON0 0x0444
|
||||
|
||||
#define COMBO_MD1_GNR_CON0 0x0500
|
||||
#define COMBO_MD1_GNR_CON1 0x0504
|
||||
#define COMBO_MD1_ANA_CON0 0x0508
|
||||
#define COMBO_MD1_ANA_CON1 0x050c
|
||||
#define COMBO_MD1_ANA_CON2 0x0510
|
||||
#define COMBO_MD1_TIME_CON0 0x0530
|
||||
#define COMBO_MD1_TIME_CON1 0x0534
|
||||
#define COMBO_MD1_TIME_CON2 0x0538
|
||||
#define COMBO_MD1_TIME_CON3 0x053C
|
||||
#define COMBO_MD1_TIME_CON4 0x0540
|
||||
#define COMBO_MD1_DATA_CON0 0x0544
|
||||
|
||||
#define COMBO_MD2_GNR_CON0 0x0600
|
||||
#define COMBO_MD2_GNR_CON1 0x0604
|
||||
#define COMBO_MD2_ANA_CON0 0X0608
|
||||
#define COMBO_MD2_ANA_CON1 0X060C
|
||||
#define COMBO_MD2_ANA_CON2 0X0610
|
||||
#define COMBO_MD2_TIME_CON0 0x0630
|
||||
#define COMBO_MD2_TIME_CON1 0x0634
|
||||
#define COMBO_MD2_TIME_CON2 0x0638
|
||||
#define COMBO_MD2_TIME_CON3 0x063C
|
||||
#define COMBO_MD2_TIME_CON4 0x0640
|
||||
#define COMBO_MD2_DATA_CON0 0x0644
|
||||
|
||||
#define DPHY_MD3_GNR_CON0 0x0700
|
||||
#define DPHY_MD3_GNR_CON1 0x0704
|
||||
#define DPHY_MD3_ANA_CON0 0X0708
|
||||
#define DPHY_MD3_ANA_CON1 0X070C
|
||||
#define DPHY_MD3_ANA_CON2 0X0710
|
||||
#define DPHY_MD3_TIME_CON0 0x0730
|
||||
#define DPHY_MD3_TIME_CON1 0x0734
|
||||
#define DPHY_MD3_TIME_CON2 0x0738
|
||||
#define DPHY_MD3_TIME_CON3 0x073C
|
||||
#define DPHY_MD3_TIME_CON4 0x0740
|
||||
#define DPHY_MD3_DATA_CON0 0x0744
|
||||
|
||||
#define T_LP_EXIT_SKEW(x) UPDATE(x, 3, 2)
|
||||
#define T_LP_ENTRY_SKEW(x) UPDATE(x, 1, 0)
|
||||
#define T_HS_ZERO(x) UPDATE(x, 15, 8)
|
||||
#define T_HS_PREPARE(x) UPDATE(x, 7, 0)
|
||||
#define T_HS_EXIT(x) UPDATE(x, 15, 8)
|
||||
#define T_HS_TRAIL(x) UPDATE(x, 7, 0)
|
||||
#define T_TA_GET(x) UPDATE(x, 7, 4)
|
||||
#define T_TA_GO(x) UPDATE(x, 3, 0)
|
||||
|
||||
/* MIPI_CDPHY_GRF registers */
|
||||
#define MIPI_DCPHY_GRF_CON0 0x0000
|
||||
#define S_CPHY_MODE HIWORD_UPDATE(1, 3, 3)
|
||||
#define M_CPHY_MODE HIWORD_UPDATE(1, 0, 0)
|
||||
|
||||
#define MAX_DPHY_BW 4500000L
|
||||
#define MAX_CPHY_BW 2000000L
|
||||
|
||||
#define RX_CLK_THS_SETTLE (0xb30)
|
||||
#define RX_LANE0_THS_SETTLE (0xC30)
|
||||
#define RX_LANE0_ERR_SOT_SYNC (0xC34)
|
||||
#define RX_LANE1_THS_SETTLE (0xD30)
|
||||
#define RX_LANE1_ERR_SOT_SYNC (0xD34)
|
||||
#define RX_LANE2_THS_SETTLE (0xE30)
|
||||
#define RX_LANE2_ERR_SOT_SYNC (0xE34)
|
||||
#define RX_LANE3_THS_SETTLE (0xF30)
|
||||
#define RX_LANE3_ERR_SOT_SYNC (0xF34)
|
||||
#define RX_CLK_LANE_ENABLE (0xB00)
|
||||
#define RX_DATA_LANE0_ENABLE (0xC00)
|
||||
#define RX_DATA_LANE1_ENABLE (0xD00)
|
||||
#define RX_DATA_LANE2_ENABLE (0xE00)
|
||||
#define RX_DATA_LANE3_ENABLE (0xF00)
|
||||
|
||||
#define RX_S0C_GNR_CON1 (0xB04)
|
||||
#define RX_S0C_ANA_CON1 (0xB0c)
|
||||
#define RX_S0C_ANA_CON2 (0xB10)
|
||||
#define RX_S0C_ANA_CON3 (0xB14)
|
||||
#define RX_COMBO_S0D0_GNR_CON1 (0xC04)
|
||||
#define RX_COMBO_S0D0_ANA_CON1 (0xC0c)
|
||||
#define RX_COMBO_S0D0_ANA_CON2 (0xC10)
|
||||
#define RX_COMBO_S0D0_ANA_CON3 (0xC14)
|
||||
#define RX_COMBO_S0D0_ANA_CON6 (0xC20)
|
||||
#define RX_COMBO_S0D0_ANA_CON7 (0xC24)
|
||||
#define RX_COMBO_S0D0_DESKEW_CON0 (0xC40)
|
||||
#define RX_COMBO_S0D0_DESKEW_CON2 (0xC48)
|
||||
#define RX_COMBO_S0D0_DESKEW_CON4 (0xC50)
|
||||
#define RX_COMBO_S0D0_CRC_CON1 (0xC64)
|
||||
#define RX_COMBO_S0D0_CRC_CON2 (0xC68)
|
||||
#define RX_COMBO_S0D1_GNR_CON1 (0xD04)
|
||||
#define RX_COMBO_S0D1_ANA_CON1 (0xD0c)
|
||||
#define RX_COMBO_S0D1_ANA_CON2 (0xD10)
|
||||
#define RX_COMBO_S0D1_ANA_CON3 (0xD14)
|
||||
#define RX_COMBO_S0D1_ANA_CON6 (0xD20)
|
||||
#define RX_COMBO_S0D1_ANA_CON7 (0xD24)
|
||||
#define RX_COMBO_S0D1_DESKEW_CON0 (0xD40)
|
||||
#define RX_COMBO_S0D1_DESKEW_CON2 (0xD48)
|
||||
#define RX_COMBO_S0D1_DESKEW_CON4 (0xD50)
|
||||
#define RX_COMBO_S0D1_CRC_CON1 (0xD64)
|
||||
#define RX_COMBO_S0D1_CRC_CON2 (0xD68)
|
||||
#define RX_COMBO_S0D2_GNR_CON1 (0xE04)
|
||||
#define RX_COMBO_S0D2_ANA_CON1 (0xE0c)
|
||||
#define RX_COMBO_S0D2_ANA_CON2 (0xE10)
|
||||
#define RX_COMBO_S0D2_ANA_CON3 (0xE14)
|
||||
#define RX_COMBO_S0D2_ANA_CON6 (0xE20)
|
||||
#define RX_COMBO_S0D2_ANA_CON7 (0xE24)
|
||||
#define RX_COMBO_S0D2_DESKEW_CON0 (0xE40)
|
||||
#define RX_COMBO_S0D2_DESKEW_CON2 (0xE48)
|
||||
#define RX_COMBO_S0D2_DESKEW_CON4 (0xE50)
|
||||
#define RX_COMBO_S0D2_CRC_CON1 (0xE64)
|
||||
#define RX_COMBO_S0D2_CRC_CON2 (0xE68)
|
||||
#define RX_S0D3_GNR_CON1 (0xF04)
|
||||
#define RX_S0D3_ANA_CON1 (0xF0c)
|
||||
#define RX_S0D3_ANA_CON2 (0xF10)
|
||||
#define RX_S0D3_ANA_CON3 (0xF14)
|
||||
#define RX_S0D3_DESKEW_CON0 (0xF40)
|
||||
#define RX_S0D3_DESKEW_CON2 (0xF48)
|
||||
#define RX_S0D3_DESKEW_CON4 (0xF50)
|
||||
|
||||
#endif
|
||||
73
drivers/video/rockchip/vehicle/vehicle_version.h
Normal file
73
drivers/video/rockchip/vehicle/vehicle_version.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rockchip Vehicle driver
|
||||
*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _RKVEHICLE_VERSION_H
|
||||
#define _RKVEHICLE_VERSION_H
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
/*
|
||||
*RKVEHICLE DRIVER VERSION NOTE
|
||||
*
|
||||
* V0.0X01.0X00 first version.
|
||||
* 1. add support rk356x dvp/mipi fast vehicle reverse
|
||||
* 2. add sample dvp interface sensor gc2145 for test
|
||||
* 3. add sample mipi interface sensor nvp6314 one channel for test
|
||||
* 4. fixup rga old/new format transform issue
|
||||
* V0.0X01.0X01 fixup rga yuvtorgb transform issue
|
||||
* V0.0X01.0X02 modify debug log issue
|
||||
* V0.0X01.0X03 fix vehicle reverse close crash issue
|
||||
* V0.0X01.0X04 fix vehicle reverse reopen not ok issue
|
||||
* V0.0X01.0X05 fix after add hwc reserved plane patch, but not use reverse display issue.
|
||||
* V0.0X01.0X06 fix reverse open/close probably stay in reverse preview issue.
|
||||
* V0.0X01.0X07 rename function & remove deprecated code.
|
||||
* V0.0X01.0X08 use Esmart0-win0 plane for vehicle, for Esmart1 depend on Esmart0 open first
|
||||
* V0.0X01.0X09
|
||||
* 1. fix vehicle plane zpos not update issue
|
||||
* 2. use vop_drm_zpos 0x7 & not use drm_direct_disable_kernel_logo to fix kernel logo issue
|
||||
* V0.0X01.0Xa
|
||||
* 1. add cif output nv16 format to display support
|
||||
* 2. use parameter vehicle_dump_data to control dump data
|
||||
* V0.0X01.0Xb add cvbs in PAL/NTSC I format to mipi csi support
|
||||
* V0.0X01.0Xc fix format switch split issue:
|
||||
* such as: PAL/NTSC I format switch to 720P, cause split problem;
|
||||
* V0.0X01.0Xd fix rk356x vehicle 1080P alloc_buffer_failed issue
|
||||
* nvp6324 default use 1080p for test.
|
||||
* V0.0X01.0Xe use dummy buffer when request buffer failed case
|
||||
* fix flicker issue
|
||||
* V0.0X01.0Xf set ddr scene to fix reverse sys stuck issue
|
||||
* V0.0X02.0X0
|
||||
* 1. add mipi csi2 hw soft reset
|
||||
* 2. add ahd hot plug support, sample driver: vehicle_ad_nvp6324.c
|
||||
* V0.0X02.0X1
|
||||
* 1. support quit vehicle, switch to normal v4l2 driver
|
||||
* 2. sample: vehicle_ad_nvp6324.c, vehicle_ad_gc2145.c
|
||||
* 3. switch cmd: echo 88 > /dev/vehicle
|
||||
* V0.0x02.0x2 support rk3588 csi2_dphy in kernel-5.10
|
||||
* V0.0x02.0x3 support rk3588 csi2_dcphy
|
||||
* V0.0x02.0x4 fix some rga3 ioctl and drm interface in kernel-5.10 for rk3588
|
||||
* V0.0X02.0X5 support rk3588 dvp interface sensor
|
||||
* V0.0X02.0X6 add dts phy_node to adapt different csi2_dphy or dvp sensor
|
||||
* V0.0X02.0X7 adapt flinger driver to drm direct show interface
|
||||
* V0.0X02.0X8 remove rockchip_ion falloc buf
|
||||
* V0.0X02.0X9 fix RGA rotation error
|
||||
* V0.0X02.0Xa add support MIPI CONTINUOUS CLOCK
|
||||
* V0.0X02.0Xb add support config crtc and plane from dts
|
||||
* 1.default crtc video_port3
|
||||
* 2.default plane Esmart0-win0
|
||||
* V0.0X02.0Xc remove some gpio unnecessary code
|
||||
* V0.0X02.0Xd support samsung mipi_dcphy combo one driver
|
||||
* V0.0X02.0Xe add GMSL to MIPI max96714 driver support
|
||||
* V0.0X02.0Xf add nvp6188 driver support
|
||||
* V0.0X03.0X00 update driver
|
||||
* 1.fix some code errors
|
||||
* 2.default palne Esmart3-win0
|
||||
* 3.fix rotation parameters config from dts
|
||||
* 4.add vehicle_version.h
|
||||
*/
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user