camera: add mipi csi driver for sm1 [1/1]

PD#SWPL-5388

Problem:
sm1 board camera need add mipi csi module

Solution:
add mipi csi module

Verify:
verified on SM1 AC200

Change-Id: I819f2f74aa8da7d725cb59e5636e790185964f79
Signed-off-by: Guosong Zhou <guosong.zhou@amlogic.com>
This commit is contained in:
Guosong Zhou
2019-04-15 02:56:09 -04:00
committed by Luke Go
parent b8c9ab7fc2
commit 8fe1ad84ea
18 changed files with 8668 additions and 19 deletions

View File

@@ -15048,3 +15048,23 @@ F: drivers/amlogic/drm/meson_vpu_pipeline.c
F: drivers/amlogic/drm/meson_vpu_pipeline_traverse.c
F: include/dt-bindings/display/meson-drm-ids.h
AMLOGIC SM1 MIPI CSI DRIVER
M: Guosong Zhou <guosong.zhou@amlogic.com>
F: arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts
F: arch/arm/boot/dts/amlogic/mesonsm1.dtsi
F: arch/arm/configs/meson64_a32_defconfig
F: arch/arm64/boot/dts/amlogic/sm1_s905d3_ac200.dts
F: arch/arm64/boot/dts/amlogic/mesonsm1.dtsi
F: arch/arm64/configs/meson64_defconfig
F: drivers/amlogic/clk/g12a/g12a.h
F: include/dt-bindings/clock/amlogic,g12a-clkc.h
F: drivers/amlogic/clk/sm1/sm1.c
F: drivers/amlogic/media/camera/Makefile
F: drivers/amlogic/media/camera/common/cam_prober.c
F: drivers/amlogic/media/vin/tvin/Kconfig
F: drivers/amlogic/media/vin/tvin/Makefile
F: include/linux/amlogic/media/camera/aml_cam_info.h
F: drivers/amlogic/media/camera/ov5640.c
F: drivers/amlogic/media/camera/ov5640_firmware.h
F: drivers/amlogic/media/vin/tvin/csi/*
F: include/linux/amlogic/media/mipi/*

View File

@@ -2307,6 +2307,15 @@
};
};
i2c2_master_pins3:i2c2_pins3 {
mux {
groups = "i2c2_sda_z10",
"i2c2_sck_z11";
function = "i2c2";
drive-strength = <2>;
};
};
i2c3_master_pins1:i2c3_pins1 {
mux {
groups = "i2c3_sda_h",

View File

@@ -310,7 +310,7 @@
compatible = "amlogic, vm";
memory-region = <&vm0_cma_reserved>;
dev_name = "vm0";
status = "disabled";
status = "okay";
vm_id = <0>;
};
@@ -333,28 +333,45 @@
aml_cams {
compatible = "amlogic, cams_prober";
status = "disabled";
status = "okay";
pinctrl-names="default";
pinctrl-0=<&cam_dvp_pins &gen_clk_ee_z>;
pinctrl-0=<&gen_clk_ee_z>;
clocks = <&clkc CLKID_GEN_CLK>;
clock-names = "g12a_24m";
cam_0{
cam_name = "gc2145";
cam_name = "ov5640";
front_back = <0>;
/*u200 i2c2 gpio conflict with ethmac*/
camera-i2c-bus = <&i2c2>;
gpio_pwdn-gpios = <&gpio GPIOZ_2 GPIO_ACTIVE_HIGH>;
camvdd-gpios = <&gpio GPIOZ_5 GPIO_ACTIVE_HIGH>;
gpio_pwdn-gpios = <&gpio GPIOZ_6 GPIO_ACTIVE_HIGH>;
gpio_rst-gpios = <&gpio GPIOZ_12 GPIO_ACTIVE_HIGH>;
mirror_flip = <1>;
vertical_flip = <1>;
spread_spectrum = <0>;
bt_path = "gpio";
bt_path = "csi";
interface = "mipi";
clk_channel = "a";
bt_path_count = <1>;
vdin_path = <0>;
status = "okay";
};
};
amvdec_csi {
compatible = "amlogic, amvdec_csi";
status = "okay";
csi_id = <0>;
reg = <0xff650000 0x00000100>,
<0xffe0c000 0x00000100>,
<0xffe0d000 0x00000100>;
reg-names = "csi_phy", "csi_host", "csi_adapt";
clocks = <&clkc CLKID_CSI_ADAPT_CLK_COMP>,
<&clkc CLKID_MIPI_CSI_PHY_CLK_COMP>;
clock-names = "cts_csi_adapt_clk_composite",
"cts_csi_phy_clk_composite";
interrupts = <0 1 0>;
interrupt-names = "csi_phy";
};
gpio_keypad{
compatible = "amlogic, gpio_keypad";
status = "okay";
@@ -1049,9 +1066,9 @@
};
&i2c2 {
status = "disabled";
status = "okay";
pinctrl-names="default";
pinctrl-0=<&i2c2_master_pins2>;
pinctrl-0=<&i2c2_master_pins3>;
clock-frequency = <100000>;
};

View File

@@ -316,6 +316,7 @@ CONFIG_AMLOGIC_MEDIA_TVIN_HDMI=y
CONFIG_AMLOGIC_MEDIA_TVIN_AFE=y
CONFIG_AMLOGIC_MEDIA_TVIN_VBI=y
CONFIG_AMLOGIC_MEDIA_TVIN_AVDETECT=y
CONFIG_AMLOGIC_MEDIA_TVIN_CSI=y
CONFIG_AMLOGIC_MEDIA_VIDEO_PROCESSOR=y
CONFIG_AMLOGIC_V4L_VIDEO=y
CONFIG_AMLOGIC_V4L_VIDEO2=y
@@ -333,6 +334,7 @@ CONFIG_AMLOGIC_MEDIA_GDC=y
CONFIG_AMLOGIC_VIDEO_CAPTURE=y
CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER=y
CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145=y
CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5640=y
CONFIG_AMLOGIC_DTV_DEMOD=y
CONFIG_AMLOGIC_MMC=y
CONFIG_AMLOGIC_NAND=y

View File

@@ -2267,6 +2267,15 @@
};
};
i2c2_master_pins3:i2c2_pins3 {
mux {
groups = "i2c2_sda_z10",
"i2c2_sck_z11";
function = "i2c2";
drive-strength = <2>;
};
};
i2c3_master_pins1:i2c3_pins1 {
mux {
groups = "i2c3_sda_h",

View File

@@ -333,26 +333,43 @@
compatible = "amlogic, cams_prober";
status = "disabled";
pinctrl-names="default";
pinctrl-0=<&cam_dvp_pins &gen_clk_ee_z>;
pinctrl-0=<&gen_clk_ee_z>;
clocks = <&clkc CLKID_GEN_CLK>;
clock-names = "g12a_24m";
cam_0{
cam_name = "gc2145";
cam_name = "ov5640";
front_back = <0>;
/*u200 i2c2 gpio conflict with ethmac*/
camera-i2c-bus = <&i2c2>;
gpio_pwdn-gpios = <&gpio GPIOZ_2 GPIO_ACTIVE_HIGH>;
camvdd-gpios = <&gpio GPIOZ_5 GPIO_ACTIVE_HIGH>;
gpio_pwdn-gpios = <&gpio GPIOZ_6 GPIO_ACTIVE_HIGH>;
gpio_rst-gpios = <&gpio GPIOZ_12 GPIO_ACTIVE_HIGH>;
mirror_flip = <1>;
vertical_flip = <1>;
spread_spectrum = <0>;
bt_path = "gpio";
bt_path = "csi";
interface = "mipi";
clk_channel = "a";
bt_path_count = <1>;
vdin_path = <0>;
status = "okay";
};
};
amvdec_csi {
compatible = "amlogic, amvdec_csi";
status = "disabled";
csi_id = <0>;
reg = <0x0 0xff650000 0x0 0x00000100>,
<0x0 0xffe0c000 0x0 0x00000100>,
<0x0 0xffe0d000 0x0 0x00000100>;
reg-names = "csi_phy", "csi_host", "csi_adapt";
clocks = <&clkc CLKID_CSI_ADAPT_CLK_COMP>,
<&clkc CLKID_MIPI_CSI_PHY_CLK_COMP>;
clock-names = "cts_csi_adapt_clk_composite",
"cts_csi_phy_clk_composite";
interrupts = <0 1 0>;
interrupt-names = "csi_phy";
};
gpio_keypad{
compatible = "amlogic, gpio_keypad";
status = "okay";
@@ -1053,7 +1070,7 @@
&i2c2 {
status = "disabled";
pinctrl-names="default";
pinctrl-0=<&i2c2_master_pins2>;
pinctrl-0=<&i2c2_master_pins3>;
clock-frequency = <100000>;
};

View File

@@ -310,6 +310,7 @@ CONFIG_AMLOGIC_MEDIA_TVIN_HDMI=y
CONFIG_AMLOGIC_MEDIA_TVIN_AFE=y
CONFIG_AMLOGIC_MEDIA_TVIN_VBI=y
CONFIG_AMLOGIC_MEDIA_TVIN_AVDETECT=y
CONFIG_AMLOGIC_MEDIA_TVIN_CSI=y
CONFIG_AMLOGIC_MEDIA_VIDEO_PROCESSOR=y
CONFIG_AMLOGIC_V4L_VIDEO=y
CONFIG_AMLOGIC_V4L_VIDEO2=y
@@ -327,6 +328,7 @@ CONFIG_AMLOGIC_MEDIA_GDC=y
CONFIG_AMLOGIC_VIDEO_CAPTURE=y
CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER=y
CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145=y
CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5640=y
CONFIG_AMLOGIC_DTV_DEMOD=y
CONFIG_AMLOGIC_MMC=y
CONFIG_AMLOGIC_NAND=y

View File

@@ -7,9 +7,11 @@ amlcamera-objs := common/plat_ctrl.o
amlvm-objs := common/vm.o
cam_prober-objs := common/cam_prober.o common/config_parser.o
gc2145dri-objs := gc2145.o
ov5640dri-objs := ov5640.o
obj-y += amlflash.o
obj-y += amlvm.o
obj-y += amlcamera.o
obj-y += cam_prober.o
obj-$(CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145) += gc2145dri.o
obj-$(CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5640) += ov5640dri.o

View File

@@ -33,6 +33,7 @@
#include <linux/amlogic/cpu_version.h>
#include <linux/amlogic/media/old_cpu_version.h>
#include <linux/clk.h>
#include <linux/errno.h>
#define CONFIG_ARCH_MESON8
@@ -1049,7 +1050,8 @@ void aml_cam_init(struct aml_cam_info_s *cam_dev)
if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB)
GXBB_cam_enable_clk();
else if ((get_cpu_type() == MESON_CPU_MAJOR_ID_G12A) ||
(get_cpu_type() == MESON_CPU_MAJOR_ID_G12B))
(get_cpu_type() == MESON_CPU_MAJOR_ID_G12B) ||
(is_meson_sm1_cpu()))
GX12_cam_enable_clk();
else
cam_enable_clk(cam_dev->mclk, cam_dev->spread_spectrum);
@@ -1109,7 +1111,8 @@ void aml_cam_uninit(struct aml_cam_info_s *cam_dev)
if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB)
GXBB_cam_disable_clk(cam_dev->spread_spectrum);
else if ((get_cpu_type() == MESON_CPU_MAJOR_ID_G12A) ||
(get_cpu_type() == MESON_CPU_MAJOR_ID_G12B))
(get_cpu_type() == MESON_CPU_MAJOR_ID_G12B) ||
(is_meson_sm1_cpu()))
GX12_cam_disable_clk(cam_dev->spread_spectrum);
else
cam_disable_clk(cam_dev->spread_spectrum);
@@ -1196,6 +1199,15 @@ static int fill_cam_dev(struct device_node *p_node,
goto err_out;
}
cam_dev->cam_vdd = of_get_named_gpio(p_node, "camvdd-gpios", 0);
pr_info("cam_dev->cam_vdd = %d\n", cam_dev->cam_vdd);
if (cam_dev->cam_vdd == 0)
pr_info("%s: failed to map gpio_cam_vdd !\n", cam_dev->name);
ret = gpio_request(cam_dev->cam_vdd, "camera");
if (ret < 0)
pr_info("aml_cam_init cam_vdd request failed\n");
gpio_direction_output(cam_dev->cam_vdd, 0);
cam_dev->pwdn_pin = of_get_named_gpio(p_node, "gpio_pwdn-gpios", 0);
if (cam_dev->pwdn_pin == 0) {
pr_info("%s: failed to map gpio_pwdn !\n", cam_dev->name);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -21,4 +21,5 @@ source "drivers/amlogic/media/vin/tvin/bt656/Kconfig"
source "drivers/amlogic/media/vin/tvin/hdmirx_ext/Kconfig"
source "drivers/amlogic/media/vin/tvin/hdmirx/Kconfig"
source "drivers/amlogic/media/vin/tvin/tvafe/Kconfig"
source "drivers/amlogic/media/vin/tvin/csi/Kconfig"
endif

View File

@@ -13,4 +13,5 @@ obj-$(CONFIG_AMLOGIC_MEDIA_TVIN_BT656) += bt656/
obj-$(CONFIG_AMLOGIC_MEDIA_TVIN_HDMI_EXT) += hdmirx_ext/
obj-$(CONFIG_AMLOGIC_MEDIA_TVIN_HDMI) += hdmirx/
obj-$(CONFIG_AMLOGIC_MEDIA_TVIN_AFE) += tvafe/
obj-$(CONFIG_AMLOGIC_MEDIA_TVIN_CSI) += csi/

View File

@@ -0,0 +1,11 @@
#
# CSI Device Driver Configuration
#
config AMLOGIC_MEDIA_TVIN_CSI
tristate "Amlogic CSI device driver"
default n
help
CSI device driver.

View File

@@ -0,0 +1,2 @@
obj-$(CONFIG_AMLOGIC_MEDIA_TVIN_CSI) += tvin_csi.o
tvin_csi-objs := csi.o mipi_hw.o

View File

@@ -0,0 +1,558 @@
/*
* drivers/amlogic/media/vin/tvin/csi/csi.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/major.h>
#include <linux/amlogic/media/mipi/am_mipi_csi2.h>
#include "../tvin_global.h"
#include "../vdin/vdin_regs.h"
#include "../vdin/vdin_drv.h"
#include "../vdin/vdin_ctl.h"
#include "../tvin_format_table.h"
#include "../tvin_frontend.h"
#include "csi.h"
#define DEV_NAME "amvdec_csi"
#define DRV_NAME "amvdec_csi"
#define CLS_NAME "amvdec_csi"
#define MOD_NAME "amvdec_csi"
#define CSI_MAX_DEVS 1
#define WDG_STEP_JIFFIES 10
static dev_t amcsi_devno;
static struct class *amcsi_clsp;
static void init_csi_dec_parameter(struct amcsi_dev_s *devp)
{
enum tvin_sig_fmt_e fmt;
const struct tvin_format_s *fmt_info_p;
pr_info("init_csi_dec_parameter.\n");
fmt = devp->para.fmt;
fmt_info_p =
(struct tvin_format_s *)tvin_get_fmt_info(fmt);
devp->para.v_active = 1080;
devp->para.h_active = 1920;
devp->para.hsync_phase = 0;
devp->para.vsync_phase = 0;
devp->para.hs_bp = 0;
devp->para.vs_bp = 0;
devp->para.csi_hw_info.lanes = 2;
}
static void reset_btcsi_module(void)
{
DPRINT("%s, %d\n", __func__, __LINE__);
}
static void reinit_csi_dec(struct amcsi_dev_s *devp)
{
DPRINT("%s, %d\n", __func__, __LINE__);
}
static void start_amvdec_csi(struct amcsi_dev_s *devp)
{
enum tvin_port_e port = devp->para.port;
pr_info("start_amvdec_csi.\n");
if (devp->dec_status & TVIN_AMCSI_RUNNING) {
pr_info("%s csi have started alreadly.\n",
__func__);
return;
}
devp->dec_status = TVIN_AMCSI_RUNNING;
pr_info("start_amvdec_csi port = %x\n", port);
if (port == TVIN_PORT_MIPI) {
init_csi_dec_parameter(devp);
reinit_csi_dec(devp);
} else {
devp->para.fmt = TVIN_SIG_FMT_NULL;
devp->para.port = TVIN_PORT_NULL;
DPRINT("%s: input is not selected, please try again\n",
__func__);
return;
}
devp->dec_status = TVIN_AMCSI_RUNNING;
}
static void stop_amvdec_csi(struct amcsi_dev_s *devp)
{
if (devp->dec_status & TVIN_AMCSI_RUNNING) {
reset_btcsi_module();
devp->dec_status = TVIN_AMCSI_STOP;
} else
DPRINT("%s device is not started yet\n", __func__);
}
static bool amcsi_check_skip_frame(struct tvin_frontend_s *fe)
{
struct amcsi_dev_s *devp =
container_of(fe, struct amcsi_dev_s, frontend);
if (devp->csi_parm.skip_frames > 0) {
devp->csi_parm.skip_frames--;
return true;
} else
return false;
}
int amcsi_support(struct tvin_frontend_s *fe, enum tvin_port_e port)
{
if (port != TVIN_PORT_MIPI) {
DPRINT("this is not MIPI port\n");
return -1;
} else {
return 0;
}
}
static int amcsi_open(struct inode *node, struct file *file)
{
struct amcsi_dev_s *csi_devp;
csi_devp = container_of(node->i_cdev, struct amcsi_dev_s, cdev);
file->private_data = csi_devp;
return 0;
}
static int amcsi_release(struct inode *node, struct file *file)
{
file->private_data = NULL;
return 0;
}
static const struct file_operations amcsi_fops = {
.owner = THIS_MODULE,
.open = amcsi_open,
.release = amcsi_release,
};
void amcsi_start(struct tvin_frontend_s *fe, enum tvin_sig_fmt_e fmt)
{
struct amcsi_dev_s *csi_devp;
csi_devp = container_of(fe, struct amcsi_dev_s, frontend);
start_amvdec_csi(csi_devp);
}
static void amcsi_stop(struct tvin_frontend_s *fe, enum tvin_port_e port)
{
struct amcsi_dev_s *devp =
container_of(fe, struct amcsi_dev_s, frontend);
if (port != TVIN_PORT_MIPI) {
DPRINT("%s:invaild port %d.\n", __func__, port);
return;
}
stop_amvdec_csi(devp);
}
void amcsi_get_sig_property(struct tvin_frontend_s *fe,
struct tvin_sig_property_s *prop)
{
struct amcsi_dev_s *devp =
container_of(fe, struct amcsi_dev_s, frontend);
prop->color_format = devp->para.cfmt;
prop->dest_cfmt = devp->para.dfmt;
pr_info("devp->para.cfmt=%d, devp->para.dfmt=%d\n",
devp->para.cfmt, devp->para.dfmt);
prop->decimation_ratio = 0;
}
int amcsi_isr(struct tvin_frontend_s *fe, unsigned int hcnt)
{
struct amcsi_dev_s *devp =
container_of(fe, struct amcsi_dev_s, frontend);
unsigned int data1 = 0;
struct am_csi2_frame_s frame;
frame.w = READ_CSI_ADPT_REG_BIT(CSI2_PIC_SIZE_STAT, 0, 16);
frame.h = READ_CSI_ADPT_REG_BIT(CSI2_PIC_SIZE_STAT, 16, 16);
frame.err = READ_CSI_ADPT_REG(CSI2_ERR_STAT0);
data1 = READ_CSI_ADPT_REG(CSI2_GEN_STAT0);
if (frame.err) {
DPRINT("%s,error---pixel cnt:%d, line cnt:%d\n",
__func__, frame.w, frame.h);
DPRINT("error state:0x%x.,status:0x%x\n",
frame.err, data1);
devp->overflow_cnt++;
WRITE_CSI_ADPT_REG(CSI2_ERR_STAT0, 0);
}
if (devp->overflow_cnt > 4) {
DPRINT("should reset mipi\n");
devp->overflow_cnt = 0;
return 0;
}
devp->reset = 0;
return 0;
}
static ssize_t csi_attr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t len = 0;
struct amcsi_dev_s *csi_devp;
int i;
csi_devp = dev_get_drvdata(dev);
if (csi_devp->dec_status != TVIN_AMCSI_RUNNING) {
len += sprintf(buf+len, "csi does not start\n");
return len;
}
len += sprintf(buf+len, "csi parameters below\n");
len +=
sprintf(buf+len, "\tlanes=%d, channel=%d\n"
"\tclk_channel=%d\n"
"\tmode=%d, clock_lane_mode=%d, active_pixel=%d\n"
"\tactive_line=%d, frame_size=%d, ui_val=%dns\n"
"\ths_freq=%dhz, urgent=%d\n",
csi_devp->csi_parm.lanes,
csi_devp->csi_parm.channel,
csi_devp->csi_parm.clk_channel,
csi_devp->csi_parm.mode,
csi_devp->csi_parm.clock_lane_mode,
csi_devp->csi_parm.active_pixel,
csi_devp->csi_parm.active_line,
csi_devp->csi_parm.frame_size,
csi_devp->csi_parm.ui_val,
csi_devp->csi_parm.hs_freq,
csi_devp->csi_parm.urgent);
len += sprintf(buf+len, "csi adapter register below\n");
for (i = CSI_ADPT_START_REG; i <= CSI_ADPT_END_REG; i++) {
len += sprintf(buf+len, "\t[0x%04x]=0x%08x\n",
i - CSI_ADPT_START_REG, READ_CSI_ADPT_REG(i));
}
len += sprintf(buf+len, "csi phy register below\n");
for (i = CSI_PHY_START_REG; i <= CSI_PHY_END_REG; i++) {
len += sprintf(buf+len, "\t[0x%04x]=0x%08x\n",
i, READ_CSI_PHY_REG(i));
}
len += sprintf(buf+len, "csi host register below\n");
for (i = CSI_HST_START_REG; i <= CSI_HST_END_REG; i++) {
len += sprintf(buf+len, "\t[0x%04x]=0x%08x\n",
i << 2, READ_CSI_HST_REG(i));
}
return len;
}
static ssize_t csi_attr_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct amcsi_dev_s *csi_devp;
unsigned int n = 0;
char *buf_orig, *ps, *token;
char *parm[6] = {NULL};
if (!buf)
return len;
buf_orig = kstrdup(buf, GFP_KERNEL);
csi_devp = dev_get_drvdata(dev);
ps = buf_orig;
while (1) {
if (n >= ARRAY_SIZE(parm)) {
pr_info("parm array overflow, n=%d\n", n);
kfree(buf_orig);
return len;
}
token = strsep(&ps, "\n");
if (token == NULL)
break;
if (*token == '\0')
continue;
parm[n++] = token;
}
if (strcmp(parm[0], "reset") == 0) {
pr_info("reset\n");
am_mipi_csi2_init(&csi_devp->csi_parm);
} else if (strcmp(parm[0], "init") == 0) {
pr_info("init mipi measure clock\n");
init_am_mipi_csi2_clock();
} else if (strcmp(parm[0], "min") == 0) {
csi_devp->min_frmrate =
kstrtol(parm[1], 16, NULL);
if ((csi_devp->min_frmrate * WDG_STEP_JIFFIES) < HZ)
csi_devp->min_frmrate = HZ/WDG_STEP_JIFFIES;
pr_info("min_frmrate=%d\n", csi_devp->min_frmrate);
}
kfree(buf_orig);
return len;
}
static DEVICE_ATTR(hw_info, 0664, csi_attr_show, csi_attr_store);
static int amcsi_feopen(struct tvin_frontend_s *fe, enum tvin_port_e port)
{
struct amcsi_dev_s *csi_devp =
container_of(fe, struct amcsi_dev_s, frontend);
struct vdin_parm_s *parm = fe->private_data;
if (port != TVIN_PORT_MIPI) {
DPRINT("[mipi..]%s:invaild port %d.\n", __func__, port);
return -1;
}
if (!memcpy(&csi_devp->para, parm,
sizeof(struct vdin_parm_s))) {
DPRINT("[mipi..]%s memcpy error.\n", __func__);
return -1;
}
init_am_mipi_csi2_clock();
csi_devp->para.port = port;
memcpy(&csi_devp->csi_parm,
&parm->csi_hw_info, sizeof(struct csi_parm_s));
csi_devp->csi_parm.skip_frames = parm->skip_count;
csi_devp->reset = 0;
csi_devp->reset_count = 0;
cal_csi_para(&csi_devp->csi_parm);
am_mipi_csi2_init(&csi_devp->csi_parm);
return 0;
}
static void amcsi_feclose(struct tvin_frontend_s *fe)
{
struct amcsi_dev_s *devp =
container_of(fe, struct amcsi_dev_s, frontend);
enum tvin_port_e port = devp->para.port;
if (port != TVIN_PORT_MIPI) {
DPRINT("[mipi..]%s:invaild port %d.\n", __func__, port);
return;
}
devp->reset = 0;
devp->reset_count = 0;
am_mipi_csi2_uninit();
memset(&devp->para, 0, sizeof(struct vdin_parm_s));
}
static struct tvin_state_machine_ops_s amcsi_machine_ops = {
.nosig = NULL,
.fmt_changed = NULL,
.get_fmt = NULL,
.fmt_config = NULL,
.adc_cal = NULL,
.pll_lock = NULL,
.get_sig_property = amcsi_get_sig_property,
.vga_set_param = NULL,
.vga_get_param = NULL,
.check_frame_skip = amcsi_check_skip_frame,
};
static struct tvin_decoder_ops_s amcsi_decoder_ops_s = {
.support = amcsi_support,
.open = amcsi_feopen,
.start = amcsi_start,
.stop = amcsi_stop,
.close = amcsi_feclose,
.decode_isr = amcsi_isr,
};
static int csi_add_cdev(struct cdev *cdevp,
const struct file_operations *fops, int minor)
{
int ret;
dev_t devno = MKDEV(MAJOR(amcsi_devno), minor);
cdev_init(cdevp, fops);
cdevp->owner = THIS_MODULE;
ret = cdev_add(cdevp, devno, 1);
return ret;
}
static void csi_delete_device(int minor)
{
dev_t devno = MKDEV(MAJOR(amcsi_devno), minor);
device_destroy(amcsi_clsp, devno);
}
static int amvdec_csi_probe(struct platform_device *pdev)
{
int ret = 0;
int id = 0;
struct amcsi_dev_s *devp = NULL;
devp = kmalloc(sizeof(struct amcsi_dev_s), GFP_KERNEL);
if (!devp) {
ret = -1;
goto fail_kmalloc_dev;
}
memset(devp, 0, sizeof(struct amcsi_dev_s));
ret = csi_add_cdev(&devp->cdev, &amcsi_fops, 0);
if (ret != 0) {
pr_err("%s: failed to add cdev\n", __func__);
goto fail_add_cdev;
}
ret = of_property_read_u32(pdev->dev.of_node, "csi_id", &id);
if (ret != 0) {
pr_err("%s: don't find csi_id.\n", __func__);
goto fail_add_cdev;
}
pdev->id = id;
sprintf(devp->frontend.name, "%s", DEV_NAME);
tvin_frontend_init(&devp->frontend, &amcsi_decoder_ops_s,
&amcsi_machine_ops, pdev->id);
tvin_reg_frontend(&devp->frontend);
devp->pdev = pdev;
platform_set_drvdata(pdev, devp);
am_mipi_csi2_para_init(pdev);
pr_info("amvdec_csi probe ok.\n");
return ret;
fail_add_cdev:
kfree(devp);
fail_kmalloc_dev:
return ret;
}
static int amvdec_csi_remove(struct platform_device *pdev)
{
struct amcsi_dev_s *devp;
devp = (struct amcsi_dev_s *)platform_get_drvdata(pdev);
tvin_unreg_frontend(&devp->frontend);
device_remove_file(devp->dev, &dev_attr_hw_info);
deinit_am_mipi_csi2_clock();
csi_delete_device(pdev->id);
cdev_del(&devp->cdev);
dev_set_drvdata(devp->dev, NULL);
platform_set_drvdata(pdev, NULL);
kfree(devp);
return 0;
}
static const struct of_device_id csi_dt_match[] = {
{
.compatible = "amlogic, amvdec_csi",
},
{},
};
static struct platform_driver amvdec_csi_driver = {
.probe = amvdec_csi_probe,
.remove = amvdec_csi_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = csi_dt_match,
}
};
static int __init amvdec_csi_init_module(void)
{
int ret = 0;
pr_info("amvdec_csi module: init.\n");
ret = alloc_chrdev_region(&amcsi_devno, 0,
CSI_MAX_DEVS, DEV_NAME);
if (ret != 0) {
pr_err("%s:failed to alloc major number\n",
__func__);
goto fail_alloc_cdev_region;
}
pr_info("%s:major %d\n", __func__, MAJOR(amcsi_devno));
amcsi_clsp = class_create(THIS_MODULE, CLS_NAME);
if (IS_ERR(amcsi_clsp)) {
ret = PTR_ERR(amcsi_clsp);
pr_err("%s:failed to create class\n", __func__);
goto fail_class_create;
}
ret = platform_driver_register(&amvdec_csi_driver);
if (ret) {
pr_err("failed to register amvdec_csi driver\n");
goto fail_pdrv_register;
}
pr_info("amvdec_csi module: init. ok\n");
return 0;
fail_pdrv_register:
class_destroy(amcsi_clsp);
fail_class_create:
unregister_chrdev_region(amcsi_devno, CSI_MAX_DEVS);
fail_alloc_cdev_region:
pr_err("amvdec_csi module: init failed, ret=%d\n", ret);
return ret;
}
static void __exit amvdec_csi_exit_module(void)
{
pr_info("amvdec_csi module remove.\n");
DPRINT("%s, %d\n", __func__, __LINE__);
class_destroy(amcsi_clsp);
unregister_chrdev_region(amcsi_devno, CSI_MAX_DEVS);
platform_driver_unregister(&amvdec_csi_driver);
}
module_init(amvdec_csi_init_module);
module_exit(amvdec_csi_exit_module);
MODULE_DESCRIPTION("AMLOGIC CSI input driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");

View File

@@ -0,0 +1,134 @@
/*
* drivers/amlogic/media/vin/tvin/csi/csi.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __CSI_INPUT_H
#define __CSI_INPUT_H
#include <linux/cdev.h>
#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
#include <linux/amlogic/media/mipi/am_mipi_csi2.h>
#include "../tvin_frontend.h"
#include "../tvin_global.h"
#ifdef PRINT_DEBUG_INFO
#define DPRINT(...) printk(__VA_ARGS__)
#else
#define DPRINT(...)
#endif
#define CSI2_CFG_USE_NULL_PACKET 0
#define CSI2_CFG_BUFFER_PIC_SIZE 1
#define CSI2_CFG_422TO444_MODE 1
#define CSI2_CFG_INV_FIELD 0
#define CSI2_CFG_INTERLACE_EN 0
#define CSI2_CFG_COLOR_EXPAND 0
#define CSI2_CFG_ALL_TO_MEM 0
/*mipi-csi2 phy registers*/
#define MIPI_PHY_CTRL 0x00
#define MIPI_PHY_CLK_LANE_CTRL 0x04
#define MIPI_PHY_DATA_LANE_CTRL 0x08
#define MIPI_PHY_DATA_LANE_CTRL1 0x0C
#define MIPI_PHY_TCLK_MISS 0x10
#define MIPI_PHY_TCLK_SETTLE 0x14
#define MIPI_PHY_THS_EXIT 0x18
#define MIPI_PHY_THS_SKIP 0x1C
#define MIPI_PHY_THS_SETTLE 0x20
#define MIPI_PHY_TINIT 0x24
#define MIPI_PHY_TULPS_C 0x28
#define MIPI_PHY_TULPS_S 0x2C
#define MIPI_PHY_TMBIAS 0x30
#define MIPI_PHY_TLP_EN_W 0x34
#define MIPI_PHY_TLPOK 0x38
#define MIPI_PHY_TWD_INIT 0x3C
#define MIPI_PHY_TWD_HS 0x40
#define MIPI_PHY_AN_CTRL0 0x44
#define MIPI_PHY_AN_CTRL1 0x48
#define MIPI_PHY_AN_CTRL2 0x4C
#define MIPI_PHY_CLK_LANE_STS 0x50
#define MIPI_PHY_DATA_LANE0_STS 0x54
#define MIPI_PHY_DATA_LANE1_STS 0x58
#define MIPI_PHY_DATA_LANE2_STS 0x5C
#define MIPI_PHY_DATA_LANE3_STS 0x60
#define MIPI_PHY_INT_STS 0x6C
#define MIPI_PHY_MUX_CTRL0 (0x61 << 2)
#define MIPI_PHY_MUX_CTRL1 (0x62 << 2)
/*mipi-csi2 host registers*/
#define CSI2_HOST_CSI2_RESETN 0x010
#define CSI2_HOST_N_LANES 0x004
#define CSI2_HOST_MASK1 0x028
#define CSI2_HOST_MASK2 0x02c
/*adapt frontend registers*/
#define CSI2_CLK_RESET (0x00 << 2)
#define CSI2_GEN_CTRL0 (0x01 << 2)
#define CSI2_GEN_CTRL1 (0x02 << 2)
#define CSI2_X_START_END_ISP (0x03 << 2)
#define CSI2_Y_START_END_ISP (0x04 << 2)
#define CSI2_INTERRUPT_CTRL_STAT (0x14 << 2)
#define CSI2_GEN_STAT0 (0x20 << 2)
#define CSI2_ERR_STAT0 (0x21 << 2)
#define CSI2_PIC_SIZE_STAT (0x22 << 2)
enum amcsi_status_e {
TVIN_AMCSI_STOP,
TVIN_AMCSI_RUNNING,
TVIN_AMCSI_START,
};
struct amcsi_dev_s {
int index;
dev_t devt;
struct cdev cdev;
struct device *dev;
struct platform_device *pdev;
unsigned int overflow_cnt;
enum amcsi_status_e dec_status;
struct vdin_parm_s para;
struct csi_parm_s csi_parm;
unsigned char reset;
unsigned int reset_count;
unsigned int irq_num;
struct tvin_frontend_s frontend;
unsigned int period;
unsigned int min_frmrate;
struct timer_list t;
void __iomem *csi_adapt_addr;
};
struct csi_adapt {
struct platform_device *p_dev;
struct resource csi_phy_reg;
struct resource csi_host_reg;
struct resource csi_adapt_reg;
void __iomem *csi_phy;
void __iomem *csi_host;
void __iomem *csi_adapt;
struct clk *csi_clk;
struct clk *adapt_clk;
};
void deinit_am_mipi_csi2_clock(void);
void am_mipi_csi2_para_init(struct platform_device *pdev);
void WRITE_CSI_ADPT_REG(int addr, uint32_t val);
uint32_t READ_CSI_PHY_REG(int addr);
uint32_t READ_CSI_HST_REG(int addr);
uint32_t READ_CSI_ADPT_REG(int addr);
uint32_t READ_CSI_ADPT_REG_BIT(int addr,
const uint32_t _start, const uint32_t _len);
#endif

View File

@@ -0,0 +1,385 @@
/*
* drivers/amlogic/media/vin/tvin/csi/mipi_hw.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/amlogic/media/mipi/am_mipi_csi2.h>
#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/amlogic/power_ctrl.h>
#include "csi.h"
#define HHI_CSI_PHY 0xff63c000
#define HHI_CSI_PHY_CNTL0 (0x0d3 << 2)
#define HHI_CSI_PHY_CNTL1 (0x0d4 << 2)
#define HHI_CSI_PHY_CNTL2 (0x0d5 << 2)
static struct csi_adapt g_csi;
static inline uint32_t WRITE_CBUS_REG(void __iomem *base, uint32_t addr,
unsigned long val)
{
void __iomem *io_addr = base + addr;
__raw_writel(val, io_addr);
return 0;
}
inline void phy_update_wr_reg_bits(unsigned int reg,
unsigned int mask, unsigned int val)
{
unsigned int tmp, orig;
void __iomem *base = g_csi.csi_phy;
if (base != NULL) {
orig = __raw_readl(base + reg);
tmp = orig & ~mask;
tmp |= val & mask;
__raw_writel(tmp, base + reg);
}
}
inline void WRITE_CSI_PHY_REG_BITS(unsigned int adr, unsigned int val,
unsigned int start, unsigned int len)
{
phy_update_wr_reg_bits(adr,
((1 << len) - 1) << start, val << start);
}
inline void WRITE_CSI_PHY_REG(int addr, uint32_t val)
{
void __iomem *reg_addr = g_csi.csi_phy + addr;
__raw_writel(val, reg_addr);
}
inline uint32_t READ_CSI_PHY_REG(int addr)
{
uint32_t val;
void __iomem *reg_addr = g_csi.csi_phy + addr;
val = __raw_readl(reg_addr);
return val;
}
inline void WRITE_CSI_HST_REG(int addr, uint32_t val)
{
void __iomem *reg_addr = g_csi.csi_host + addr;
__raw_writel(val, reg_addr);
}
inline uint32_t READ_CSI_HST_REG(int addr)
{
uint32_t val;
void __iomem *reg_addr = g_csi.csi_host + addr;
val = __raw_readl(reg_addr);
return val;
}
inline void WRITE_CSI_ADPT_REG(int addr, uint32_t val)
{
void __iomem *reg_addr = g_csi.csi_adapt + addr;
__raw_writel(val, reg_addr);
}
inline uint32_t READ_CSI_ADPT_REG(int addr)
{
uint32_t val;
void __iomem *reg_addr = g_csi.csi_adapt + addr;
val = __raw_readl(reg_addr);
return val;
}
inline uint32_t READ_CSI_ADPT_REG_BIT(int addr,
const uint32_t _start, const uint32_t _len)
{
void __iomem *reg_addr = g_csi.csi_adapt + addr;
return ((__raw_readl(reg_addr) >> (_start)) & ((1L << (_len)) - 1));
}
void mipi_phy_reg_wr_and_check(int32_t addr, int32_t data)
{
#ifdef MIPI_WR_AND_CHECK
uint32_t tmp;
#endif
WRITE_CSI_PHY_REG(addr, data);
#ifdef MIPI_WR_AND_CHECK
tmp = READ_CSI_PHY_REG(addr);
if (tmp != data) {
pr_info("%s, addr = %x, data = %x, read write unmatch\n",
__func__, addr, tmp);
}
#endif
}
void init_am_mipi_csi2_clock(void)
{
int32_t rc = 0;
uint32_t csi_rate = 200000000;
uint32_t adapt_rate = 666666667;
g_csi.csi_clk = devm_clk_get(&(g_csi.p_dev->dev),
"cts_csi_phy_clk_composite");
if (IS_ERR(g_csi.csi_clk)) {
pr_err("%s: cannot get clk_gate_csi !!!\n",
__func__);
g_csi.csi_clk = NULL;
return;
}
clk_set_rate(g_csi.csi_clk, csi_rate);
rc = clk_prepare_enable(g_csi.csi_clk);
if (rc != 0) {
pr_err("Failed to enable csi clk\n");
return;
}
g_csi.adapt_clk = devm_clk_get(&(g_csi.p_dev->dev),
"cts_csi_adapt_clk_composite");
if (IS_ERR(g_csi.adapt_clk)) {
pr_err("%s: cannot get clk_gate_adapt !!!\n",
__func__);
g_csi.adapt_clk = NULL;
return;
}
clk_set_rate(g_csi.adapt_clk, adapt_rate);
rc = clk_prepare_enable(g_csi.adapt_clk);
if (rc != 0) {
pr_err("Failed to enable adapt clk\n");
return;
}
}
void disable_am_mipi_csi2_clk(void)
{
clk_disable_unprepare(g_csi.csi_clk);
clk_disable_unprepare(g_csi.adapt_clk);
}
void deinit_am_mipi_csi2_clock(void)
{
if (g_csi.csi_clk != NULL) {
devm_clk_put(&g_csi.p_dev->dev, g_csi.csi_clk);
g_csi.csi_clk = NULL;
}
if (g_csi.adapt_clk != NULL) {
devm_clk_put(&g_csi.p_dev->dev, g_csi.adapt_clk);
g_csi.adapt_clk = NULL;
}
}
static void init_am_mipi_csi2_host(struct csi_parm_s *info)
{
pr_info("info->lanes = %d\n", info->lanes);
WRITE_CSI_HST_REG(CSI2_HOST_CSI2_RESETN, 1);
WRITE_CSI_HST_REG(CSI2_HOST_N_LANES, (info->lanes-1)&3);
WRITE_CSI_HST_REG(CSI2_HOST_MASK1, 0x0);
WRITE_CSI_HST_REG(CSI2_HOST_MASK2, 0x0);
udelay(1);
}
static int init_am_mipi_csi2_adapter(struct csi_parm_s *info)
{
unsigned int data32;
struct amcsi_dev_s *csi_devp;
csi_devp = container_of(info, struct amcsi_dev_s, csi_parm);
WRITE_CSI_ADPT_REG(CSI2_CLK_RESET, 0);
data32 = 0;
data32 |= CSI2_CFG_422TO444_MODE << 21;
data32 |= 0x1f << 16;
data32 |= CSI2_CFG_COLOR_EXPAND << 15;
data32 |= CSI2_CFG_BUFFER_PIC_SIZE << 11;
data32 |= CSI2_CFG_USE_NULL_PACKET << 10;
data32 |= CSI2_CFG_INV_FIELD << 9;
data32 |= CSI2_CFG_INTERLACE_EN << 8;
data32 |= CSI2_CFG_ALL_TO_MEM << 4;
data32 |= 0xf;
WRITE_CSI_ADPT_REG(CSI2_GEN_CTRL0, data32);
data32 = 0;
data32 |= (csi_devp->para.h_active - 1) << 16;
data32 |= 0 << 0;
WRITE_CSI_ADPT_REG(CSI2_X_START_END_ISP, data32);
data32 = 0;
data32 |= (csi_devp->para.v_active - 1) << 16;
data32 |= 0 << 0;
WRITE_CSI_ADPT_REG(CSI2_Y_START_END_ISP, data32);
WRITE_CSI_ADPT_REG(CSI2_INTERRUPT_CTRL_STAT, (1 << 1));
/*Enable clock*/
data32 = 0;
data32 |= 0 << 2;
data32 |= 1 << 1;
data32 |= 0 << 0;
WRITE_CSI_ADPT_REG(CSI2_CLK_RESET, data32);
return 0;
}
static void powerup_csi_analog(struct csi_parm_s *info)
{
void __iomem *base_addr;
base_addr = ioremap_nocache(HHI_CSI_PHY, 0x400);
if (base_addr == NULL) {
pr_err("%s: Failed to ioremap addr\n", __func__);
return;
}
WRITE_CBUS_REG(base_addr, HHI_CSI_PHY_CNTL0, 0x0b440585);
WRITE_CBUS_REG(base_addr, HHI_CSI_PHY_CNTL1, 0x803f0000);
WRITE_CBUS_REG(base_addr, HHI_CSI_PHY_CNTL2, 0xf002);
iounmap(base_addr);
power_ctrl_mempd0(1, 3, 6);
}
static void powerdown_csi_analog(void)
{
power_ctrl_mempd0(0, 3, 6);
}
static void init_am_mipi_phy(struct csi_parm_s *info)
{
uint32_t settle = 0;
uint32_t ui_val = 0;
uint32_t cycle_time = 5;
ui_val = 1000 / info->settle;
if ((1000 % info->settle) != 0)
ui_val += 1;
settle = (85 + 145 + (16 * ui_val)) / 2;
settle = settle / cycle_time;
pr_info("settle = 0x%04x\n", settle);
mipi_phy_reg_wr_and_check(MIPI_PHY_CLK_LANE_CTRL, 0x3d8);
mipi_phy_reg_wr_and_check(MIPI_PHY_TCLK_MISS, 0x9);
mipi_phy_reg_wr_and_check(MIPI_PHY_TCLK_SETTLE, 0x1f);
mipi_phy_reg_wr_and_check(MIPI_PHY_THS_EXIT, 0x1f);
mipi_phy_reg_wr_and_check(MIPI_PHY_THS_SKIP, 0xa);
mipi_phy_reg_wr_and_check(MIPI_PHY_THS_SETTLE, settle);
mipi_phy_reg_wr_and_check(MIPI_PHY_TINIT, 0x4e20);
mipi_phy_reg_wr_and_check(MIPI_PHY_TMBIAS, 0x100);
mipi_phy_reg_wr_and_check(MIPI_PHY_TULPS_C, 0x1000);
mipi_phy_reg_wr_and_check(MIPI_PHY_TULPS_S, 0x100);
mipi_phy_reg_wr_and_check(MIPI_PHY_TLP_EN_W, 0x0c);
mipi_phy_reg_wr_and_check(MIPI_PHY_TLPOK, 0x100);
mipi_phy_reg_wr_and_check(MIPI_PHY_TWD_INIT, 0x400000);
mipi_phy_reg_wr_and_check(MIPI_PHY_TWD_HS, 0x400000);
mipi_phy_reg_wr_and_check(MIPI_PHY_DATA_LANE_CTRL, 0x0);
mipi_phy_reg_wr_and_check(MIPI_PHY_DATA_LANE_CTRL1,
0x3 | (0x1f << 2) | (0x3 << 7));
mipi_phy_reg_wr_and_check(MIPI_PHY_MUX_CTRL0, 0x00000123);
mipi_phy_reg_wr_and_check(MIPI_PHY_MUX_CTRL1, 0x00000123);
mipi_phy_reg_wr_and_check(MIPI_PHY_CTRL, 0);
}
static void reset_am_mipi_csi2_host(void)
{
WRITE_CSI_HST_REG(CSI2_HOST_CSI2_RESETN, 0);
}
static void reset_am_mipi_csi2_adapter(void)
{
WRITE_CSI_ADPT_REG(CSI2_CLK_RESET, 1);
}
static void reset_am_mipi_phy(void)
{
WRITE_CSI_PHY_REG_BITS(MIPI_PHY_CTRL, 0x1, 31, 1);
}
void am_mipi_csi2_para_init(struct platform_device *pdev)
{
struct resource rs;
int i = 0;
int rtn = -1;
memset(&g_csi, 0, sizeof(struct csi_adapt));
g_csi.p_dev = pdev;
for (i = 0; i < 3; i++) {
rtn = of_address_to_resource(pdev->dev.of_node, i, &rs);
if (rtn != 0) {
pr_err("%s:Error idx %d get mipi csi reg resource\n",
__func__, i);
continue;
} else {
pr_info("%s: rs idx %d info: name: %s\n", __func__,
i, rs.name);
if (strcmp(rs.name, "csi_phy") == 0) {
g_csi.csi_phy_reg = rs;
g_csi.csi_phy =
ioremap_nocache(g_csi.csi_phy_reg.start,
resource_size(&g_csi.csi_phy_reg));
} else if (strcmp(rs.name, "csi_host") == 0) {
g_csi.csi_host_reg = rs;
g_csi.csi_host =
ioremap_nocache(g_csi.csi_host_reg.start,
resource_size(&g_csi.csi_host_reg));
} else if (strcmp(rs.name, "csi_adapt") == 0) {
g_csi.csi_adapt_reg = rs;
g_csi.csi_adapt =
ioremap_nocache(g_csi.csi_adapt_reg.start,
resource_size(&g_csi.csi_adapt_reg));
} else {
pr_err("%s:Error match address\n", __func__);
}
}
}
}
void am_mipi_csi2_init(struct csi_parm_s *info)
{
powerup_csi_analog(info);
init_am_mipi_phy(info);
init_am_mipi_csi2_host(info);
init_am_mipi_csi2_adapter(info);
}
void am_mipi_csi2_uninit(void)
{
reset_am_mipi_phy();
reset_am_mipi_csi2_host();
reset_am_mipi_csi2_adapter();
disable_am_mipi_csi2_clk();
powerdown_csi_analog();
}
void cal_csi_para(struct csi_parm_s *info)
{
}