From fd1f21d6c166fd7ce0a12cfde9c722e30a2245fb Mon Sep 17 00:00:00 2001 From: LongChang Ma Date: Tue, 17 Oct 2023 10:33:45 +0800 Subject: [PATCH] media: i2c: techpoint: add tp9951 driver Signed-off-by: LongChang Ma Change-Id: Ieee236964b12d2dc54c622641463e3bbd90c2ca6 --- drivers/media/i2c/techpoint/Makefile | 2 +- .../media/i2c/techpoint/techpoint_common.h | 1 + drivers/media/i2c/techpoint/techpoint_dev.c | 30 +- .../media/i2c/techpoint/techpoint_tp9951.c | 638 ++++++++++++++++++ .../media/i2c/techpoint/techpoint_tp9951.h | 76 +++ drivers/media/i2c/techpoint/techpoint_v4l2.c | 2 +- 6 files changed, 741 insertions(+), 8 deletions(-) create mode 100644 drivers/media/i2c/techpoint/techpoint_tp9951.c create mode 100644 drivers/media/i2c/techpoint/techpoint_tp9951.h diff --git a/drivers/media/i2c/techpoint/Makefile b/drivers/media/i2c/techpoint/Makefile index f7dc0e8111f7..68a820176736 100644 --- a/drivers/media/i2c/techpoint/Makefile +++ b/drivers/media/i2c/techpoint/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 techpoint-objs += techpoint_v4l2.o techpoint_dev.o \ techpoint_tp9930.o techpoint_tp2855.o \ - techpoint_tp9950.o + techpoint_tp9950.o techpoint_tp9951.o obj-$(CONFIG_VIDEO_TECHPOINT) += techpoint.o diff --git a/drivers/media/i2c/techpoint/techpoint_common.h b/drivers/media/i2c/techpoint/techpoint_common.h index db556c00b8d7..c7310f3e4cda 100644 --- a/drivers/media/i2c/techpoint/techpoint_common.h +++ b/drivers/media/i2c/techpoint/techpoint_common.h @@ -52,6 +52,7 @@ enum techpoint_chips { CHIP_TP2815, CHIP_TP9930, CHIP_TP9950, + CHIP_TP9951, }; enum techpoint_input_type { diff --git a/drivers/media/i2c/techpoint/techpoint_dev.c b/drivers/media/i2c/techpoint/techpoint_dev.c index 33115f0d7b95..5692fbc34daa 100644 --- a/drivers/media/i2c/techpoint/techpoint_dev.c +++ b/drivers/media/i2c/techpoint/techpoint_dev.c @@ -12,6 +12,7 @@ #include "techpoint_tp9950.h" #include "techpoint_tp2855.h" #include "techpoint_tp2815.h" +#include "techpoint_tp9951.h" static DEFINE_MUTEX(reg_sem); @@ -99,33 +100,40 @@ static int check_chip_id(struct techpoint *techpoint) techpoint_read_reg(client, CHIP_ID_L_REG, &chip_id_l); dev_err(dev, "chip_id_h:0x%2x chip_id_l:0x%2x\n", chip_id_h, chip_id_l); if (chip_id_h == TP9930_CHIP_ID_H_VALUE && - chip_id_l == TP9930_CHIP_ID_L_VALUE) { + chip_id_l == TP9930_CHIP_ID_L_VALUE) { //tp2832 dev_info(&client->dev, "techpoint check chip id CHIP_TP9930 !\n"); techpoint->chip_id = CHIP_TP9930; techpoint->input_type = TECHPOINT_DVP_BT1120; return 0; } else if (chip_id_h == TP2855_CHIP_ID_H_VALUE && - chip_id_l == TP2855_CHIP_ID_L_VALUE) { + chip_id_l == TP2855_CHIP_ID_L_VALUE) { //tp2855 dev_info(&client->dev, "techpoint check chip id CHIP_TP2855 !\n"); techpoint->chip_id = CHIP_TP2855; techpoint->input_type = TECHPOINT_MIPI; return 0; } else if (chip_id_h == TP2815_CHIP_ID_H_VALUE && - chip_id_l == TP2815_CHIP_ID_L_VALUE) { + chip_id_l == TP2815_CHIP_ID_L_VALUE) { //tp2815 dev_info(&client->dev, "techpoint check chip id CHIP_TP2815 !\n"); techpoint->chip_id = CHIP_TP2855; techpoint->input_type = TECHPOINT_MIPI; return 0; } else if (chip_id_h == TP9950_CHIP_ID_H_VALUE && - chip_id_l == TP9950_CHIP_ID_L_VALUE) { + chip_id_l == TP9950_CHIP_ID_L_VALUE) { //tp2850 dev_info(&client->dev, "techpoint check chip id CHIP_TP9950 !\n"); techpoint->chip_id = CHIP_TP9950; techpoint->input_type = TECHPOINT_MIPI; return 0; + } else if (chip_id_h == TP9951_CHIP_ID_H_VALUE && + chip_id_l == TP9951_CHIP_ID_L_VALUE) { //tp2860 + dev_info(&client->dev, + "techpoint check chip id CHIP_TP9951 !\n"); + techpoint->chip_id = CHIP_TP9951; + techpoint->input_type = TECHPOINT_MIPI; + return 0; } dev_info(&client->dev, "techpoint check chip id failed !\n"); @@ -143,6 +151,8 @@ int techpoint_initialize_devices(struct techpoint *techpoint) tp2855_initialize(techpoint); else if (techpoint->chip_id == CHIP_TP9950) tp9950_initialize(techpoint); + else if (techpoint->chip_id == CHIP_TP9951) + tp9951_initialize(techpoint); return 0; } @@ -185,6 +195,10 @@ static int detect_thread_function(void *data) detect_status = tp2855_get_channel_input_status (techpoint, i); + else if (techpoint->chip_id == CHIP_TP9951) + detect_status = + tp9951_get_channel_input_status + (techpoint, i); if (techpoint->detect_status[i] != detect_status) { @@ -202,8 +216,7 @@ static int detect_thread_function(void *data) else if (techpoint->chip_id == CHIP_TP2855) tp2855_set_decoder_mode(client, i, detect_status); - techpoint->detect_status[i] = - detect_status; + techpoint->detect_status[i] = detect_status; need_reset_wait = 5; } } @@ -273,6 +286,11 @@ static __maybe_unused int auto_detect_channel_fmt(struct techpoint *techpoint) tp9950_set_channel_reso(client, 0, reso); } + if (techpoint->chip_id == CHIP_TP9951) { + reso = tp9951_get_channel_reso(client, 0); + tp9951_set_channel_reso(client, 0, reso); + } + mutex_unlock(®_sem); return 0; diff --git a/drivers/media/i2c/techpoint/techpoint_tp9951.c b/drivers/media/i2c/techpoint/techpoint_tp9951.c new file mode 100644 index 000000000000..8ad43fa4549b --- /dev/null +++ b/drivers/media/i2c/techpoint/techpoint_tp9951.c @@ -0,0 +1,638 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * techpoint lib + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + */ + +#include "techpoint_tp9951.h" +#include "techpoint_dev.h" + +static struct techpoint_video_modes supported_modes[] = { +#if TP9951_DEF_PAL + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 960, + .height = 576, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .link_freq_value = TP9951_LINK_FREQ_148M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9951_BITS_PER_SAMPLE, + .lane = TP9951_LANES, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1, + .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_2, + .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_3, + }, +#endif +#if TP9951_DEF_NTSC + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 960, + .height = 480, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .link_freq_value = TP9951_LINK_FREQ_148M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9951_BITS_PER_SAMPLE, + .lane = TP9951_LANES, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1, + .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_2, + .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_3, + }, +#endif +#if TP9951_DEF_1080P + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1920, + .height = 1080, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + // .link_freq_value = TP9951_LINK_FREQ_594M, + .link_freq_value = TP9951_LINK_FREQ_297M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9951_BITS_PER_SAMPLE, + .lane = TP9951_LANES, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1, + .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_2, + .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_3, + }, +#endif +#if TP9951_DEF_720P + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1280, + .height = 720, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .link_freq_value = TP9951_LINK_FREQ_297M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9951_BITS_PER_SAMPLE, + .lane = TP9951_LANES, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1, + .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_2, + .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_3, + }, +#endif +}; + +int tp9951_initialize(struct techpoint *techpoint) +{ + int array_size = 0; + struct i2c_client *client = techpoint->client; + struct device *dev = &client->dev; + + techpoint->video_modes_num = ARRAY_SIZE(supported_modes); + array_size = + sizeof(struct techpoint_video_modes) * techpoint->video_modes_num; + techpoint->video_modes = devm_kzalloc(dev, array_size, GFP_KERNEL); + memcpy(techpoint->video_modes, supported_modes, array_size); + + techpoint->cur_video_mode = &techpoint->video_modes[0]; + + return 0; +} + +int tp9951_get_channel_input_status(struct techpoint *techpoint, u8 ch) +{ + u8 val = 0; + struct i2c_client *client = techpoint->client; + + if (ch != 0) // tp9951 just support 1 chn + return 0; + techpoint_write_reg(client, PAGE_REG, ch); + techpoint_read_reg(client, INPUT_STATUS_REG, &val); + dev_dbg(&client->dev, "input_status ch %d : %x\n", ch, val); + + return (val & INPUT_STATUS_MASK) ? 0 : 1; +} + +int tp9951_get_all_input_status(struct techpoint *techpoint, u8 *detect_status) +{ + u8 val = 0; + struct i2c_client *client = techpoint->client; + + // tp9951 just support 1 chn + techpoint_write_reg(client, PAGE_REG, 0); + techpoint_read_reg(client, INPUT_STATUS_REG, &val); + detect_status[0] = tp9951_get_channel_input_status(techpoint, 0); + return 0; +} + +static void tp9951_set_mipi_out(struct i2c_client *client, + enum techpoint_support_reso reso, + unsigned char lane) +{ + u8 tmp; + //mipi setting + techpoint_write_reg(client, 0x40, 0x08); //select MIPI page + techpoint_write_reg(client, 0x02, 0x7d); + techpoint_write_reg(client, 0x03, 0x75); + techpoint_write_reg(client, 0x04, 0x75); + techpoint_write_reg(client, 0x13, 0xef); + techpoint_write_reg(client, 0x20, 0x00); + techpoint_write_reg(client, 0x23, 0x9e); + + if (lane == MIPI_1LANE) { + techpoint_write_reg(client, 0x21, 0x11); + + if (TECHPOINT_S_RESO_1080P_30 == reso || TECHPOINT_S_RESO_1080P_25 == reso) { + techpoint_write_reg(client, 0x12, 0x54); + techpoint_write_reg(client, 0x14, 0x00); + techpoint_write_reg(client, 0x15, 0x02); + + techpoint_write_reg(client, 0x2a, 0x08); + techpoint_write_reg(client, 0x2b, 0x06); + techpoint_write_reg(client, 0x2c, 0x12); + techpoint_write_reg(client, 0x2e, 0x0a); + } else if (TECHPOINT_S_RESO_720P_30 == reso || TECHPOINT_S_RESO_720P_25 == reso) { + techpoint_write_reg(client, 0x12, 0x54); + techpoint_write_reg(client, 0x14, 0x00); + techpoint_write_reg(client, 0x15, 0x12); + + techpoint_write_reg(client, 0x2a, 0x04); + techpoint_write_reg(client, 0x2b, 0x03); + techpoint_write_reg(client, 0x2c, 0x0a); + techpoint_write_reg(client, 0x2e, 0x02); + } else if (TECHPOINT_S_RESO_NTSC == reso || TECHPOINT_S_RESO_PAL == reso) { + techpoint_write_reg(client, 0x12, 0x54); + techpoint_write_reg(client, 0x14, 0x51); + techpoint_write_reg(client, 0x15, 0x07); + + techpoint_write_reg(client, 0x2a, 0x02); + techpoint_write_reg(client, 0x2b, 0x01); + techpoint_write_reg(client, 0x2c, 0x06); + techpoint_write_reg(client, 0x2e, 0x02); + } + } else { // 2 lane + techpoint_write_reg(client, 0x21, 0x12); + + if (TECHPOINT_S_RESO_1080P_30 == reso || TECHPOINT_S_RESO_1080P_25 == reso) { + techpoint_write_reg(client, 0x12, 0x54); + techpoint_write_reg(client, 0x14, 0x41); + techpoint_write_reg(client, 0x15, 0x02); + + techpoint_write_reg(client, 0x2a, 0x04); + techpoint_write_reg(client, 0x2b, 0x03); + techpoint_write_reg(client, 0x2c, 0x0a); + techpoint_write_reg(client, 0x2e, 0x02); + } else if (TECHPOINT_S_RESO_720P_30 == reso || TECHPOINT_S_RESO_720P_25 == reso) { + techpoint_write_reg(client, 0x12, 0x54); + techpoint_write_reg(client, 0x14, 0x41); + techpoint_write_reg(client, 0x15, 0x12); + + techpoint_write_reg(client, 0x2a, 0x02); + techpoint_write_reg(client, 0x2b, 0x01); + techpoint_write_reg(client, 0x2c, 0x06); + techpoint_write_reg(client, 0x2e, 0x02); + } else if (TECHPOINT_S_RESO_NTSC == reso || TECHPOINT_S_RESO_PAL == reso) { + techpoint_write_reg(client, 0x12, 0x54); + techpoint_write_reg(client, 0x14, 0x62); + techpoint_write_reg(client, 0x15, 0x07); + + techpoint_write_reg(client, 0x2a, 0x02); + techpoint_write_reg(client, 0x2b, 0x00); + techpoint_write_reg(client, 0x2c, 0x04); + techpoint_write_reg(client, 0x2e, 0x02); + } + } + + techpoint_write_reg(client, 0x40, 0x00); //back to decoder page + techpoint_read_reg(client, 0x06, &tmp); //PLL reset + techpoint_write_reg(client, 0x06, 0x80 | tmp); + + techpoint_write_reg(client, 0x40, 0x08); //back to mipi page + + techpoint_read_reg(client, 0x14, &tmp); //PLL reset + techpoint_write_reg(client, 0x14, 0x80 | tmp); + techpoint_write_reg(client, 0x14, tmp); + + /* Enable MIPI CSI2 output */ + techpoint_write_reg(client, 0x28, 0x02); //stream off + techpoint_write_reg(client, 0x28, 0x00); //stream on + techpoint_write_reg(client, 0x40, 0x00); //back to decoder page +} + +int tp9951_set_channel_reso(struct i2c_client *client, int ch, + enum techpoint_support_reso reso) +{ + int val = reso; + + dev_info(&client->dev, "##$$ %s", __func__); + techpoint_write_reg(client, 0x40, 0x00); //select decoder page + techpoint_write_reg(client, 0x06, 0x12); //default value + techpoint_write_reg(client, 0x42, 0x00); //common setting for all format + techpoint_write_reg(client, 0x4e, 0x00); //common setting for MIPI output + techpoint_write_reg(client, 0x54, 0x00); //common setting for MIPI output + techpoint_write_reg(client, 0x41, ch); //video MUX select + + switch (val) { + case TECHPOINT_S_RESO_720P_25: +#if TP9951_DEF_720P + default: +#endif + dev_err(&client->dev, "set channel 720P_25\n"); + techpoint_write_reg(client, 0x02, 0x42); + techpoint_write_reg(client, 0x07, 0xc0); + techpoint_write_reg(client, 0x0b, 0xc0); + techpoint_write_reg(client, 0x0c, 0x13); + techpoint_write_reg(client, 0x0d, 0x50); + + techpoint_write_reg(client, 0x15, 0x13); + techpoint_write_reg(client, 0x16, 0x15); + techpoint_write_reg(client, 0x17, 0x00); + techpoint_write_reg(client, 0x18, 0x19); + techpoint_write_reg(client, 0x19, 0xd0); + techpoint_write_reg(client, 0x1a, 0x25); + techpoint_write_reg(client, 0x1c, 0x07);//1280*720, 25fps + techpoint_write_reg(client, 0x1d, 0xbc);//1280*720, 25fps + + techpoint_write_reg(client, 0x20, 0x30); + techpoint_write_reg(client, 0x21, 0x84); + techpoint_write_reg(client, 0x22, 0x36); + techpoint_write_reg(client, 0x23, 0x3c); + + techpoint_write_reg(client, 0x2b, 0x60); + techpoint_write_reg(client, 0x2c, 0x2a); + techpoint_write_reg(client, 0x2d, 0x30); + techpoint_write_reg(client, 0x2e, 0x70); + + techpoint_write_reg(client, 0x30, 0x48); + techpoint_write_reg(client, 0x31, 0xbb); + techpoint_write_reg(client, 0x32, 0x2e); + techpoint_write_reg(client, 0x33, 0x90); + techpoint_write_reg(client, 0x35, 0x25); + techpoint_write_reg(client, 0x38, 0x00); + techpoint_write_reg(client, 0x39, 0x18); + if (STD_HDA) { + techpoint_write_reg(client, 0x02, 0x46); + techpoint_write_reg(client, 0x0d, 0x71); + techpoint_write_reg(client, 0x18, 0x1b); + techpoint_write_reg(client, 0x20, 0x40); + techpoint_write_reg(client, 0x21, 0x46); + techpoint_write_reg(client, 0x25, 0xfe); + techpoint_write_reg(client, 0x26, 0x01); + techpoint_write_reg(client, 0x2c, 0x3a); + techpoint_write_reg(client, 0x2d, 0x5a); + techpoint_write_reg(client, 0x2e, 0x40); + techpoint_write_reg(client, 0x30, 0x9e); + techpoint_write_reg(client, 0x31, 0x20); + techpoint_write_reg(client, 0x32, 0x10); + techpoint_write_reg(client, 0x33, 0x90); + } + + tp9951_set_mipi_out(client, reso, MIPI_2LANE); // 2 lane + + break; + case TECHPOINT_S_RESO_1080P_25: // FHD25 +#if TP9951_DEF_1080P + default: +#endif + dev_err(&client->dev, "set channel 1080P_25\n"); + techpoint_write_reg(client, 0x02, 0x40); + techpoint_write_reg(client, 0x07, 0xc0); + techpoint_write_reg(client, 0x0b, 0xc0); + techpoint_write_reg(client, 0x0c, 0x03); + techpoint_write_reg(client, 0x0d, 0x50); + + techpoint_write_reg(client, 0x15, 0x03); + techpoint_write_reg(client, 0x16, 0xd2); + techpoint_write_reg(client, 0x17, 0x80); + techpoint_write_reg(client, 0x18, 0x29); + techpoint_write_reg(client, 0x19, 0x38); + techpoint_write_reg(client, 0x1a, 0x47); + techpoint_write_reg(client, 0x1c, 0x0a);//1920*1080, 25fps + techpoint_write_reg(client, 0x1d, 0x50);// + + techpoint_write_reg(client, 0x20, 0x30); + techpoint_write_reg(client, 0x21, 0x84); + techpoint_write_reg(client, 0x22, 0x36); + techpoint_write_reg(client, 0x23, 0x3c); + + techpoint_write_reg(client, 0x2b, 0x60); + techpoint_write_reg(client, 0x2c, 0x2a); + techpoint_write_reg(client, 0x2d, 0x30); + techpoint_write_reg(client, 0x2e, 0x70); + + techpoint_write_reg(client, 0x30, 0x48); + techpoint_write_reg(client, 0x31, 0xbb); + techpoint_write_reg(client, 0x32, 0x2e); + techpoint_write_reg(client, 0x33, 0x90); + techpoint_write_reg(client, 0x35, 0x05); + techpoint_write_reg(client, 0x38, 0x00); + techpoint_write_reg(client, 0x39, 0x1C); + if (STD_HDA) { + techpoint_write_reg(client, 0x02, 0x44); + techpoint_write_reg(client, 0x0d, 0x73); + techpoint_write_reg(client, 0x15, 0x01); + techpoint_write_reg(client, 0x16, 0xf0); + techpoint_write_reg(client, 0x18, 0x2a); + techpoint_write_reg(client, 0x20, 0x3c); + techpoint_write_reg(client, 0x21, 0x46); + techpoint_write_reg(client, 0x25, 0xfe); + techpoint_write_reg(client, 0x26, 0x0d); + techpoint_write_reg(client, 0x2c, 0x3a); + techpoint_write_reg(client, 0x2d, 0x54); + techpoint_write_reg(client, 0x2e, 0x40); + techpoint_write_reg(client, 0x30, 0xa5); + techpoint_write_reg(client, 0x31, 0x86); + techpoint_write_reg(client, 0x32, 0xfb); + techpoint_write_reg(client, 0x33, 0x60); + } + + tp9951_set_mipi_out(client, reso, MIPI_2LANE); // 2 lane + + break; + case TECHPOINT_S_RESO_1080P_30: // FHD30 + dev_err(&client->dev, "set channel PAL\n"); + techpoint_write_reg(client, 0x02, 0x40); + techpoint_write_reg(client, 0x07, 0xc0); + techpoint_write_reg(client, 0x0b, 0xc0); + techpoint_write_reg(client, 0x0c, 0x03); + techpoint_write_reg(client, 0x0d, 0x50); + + techpoint_write_reg(client, 0x15, 0x03); + techpoint_write_reg(client, 0x16, 0xd2); + techpoint_write_reg(client, 0x17, 0x80); + techpoint_write_reg(client, 0x18, 0x29); + techpoint_write_reg(client, 0x19, 0x38); + techpoint_write_reg(client, 0x1a, 0x47); + techpoint_write_reg(client, 0x1c, 0x08); //1920*1080, 30fps + techpoint_write_reg(client, 0x1d, 0x98); // + + techpoint_write_reg(client, 0x20, 0x30); + techpoint_write_reg(client, 0x21, 0x84); + techpoint_write_reg(client, 0x22, 0x36); + techpoint_write_reg(client, 0x23, 0x3c); + + techpoint_write_reg(client, 0x2b, 0x60); + techpoint_write_reg(client, 0x2c, 0x2a); + techpoint_write_reg(client, 0x2d, 0x30); + techpoint_write_reg(client, 0x2e, 0x70); + + techpoint_write_reg(client, 0x30, 0x48); + techpoint_write_reg(client, 0x31, 0xbb); + techpoint_write_reg(client, 0x32, 0x2e); + techpoint_write_reg(client, 0x33, 0x90); + + techpoint_write_reg(client, 0x35, 0x05); + techpoint_write_reg(client, 0x38, 0x00); + techpoint_write_reg(client, 0x39, 0x1C); + + if (STD_HDA) { //AHD1080p30 extra + techpoint_write_reg(client, 0x02, 0x44); + techpoint_write_reg(client, 0x0d, 0x72); + + techpoint_write_reg(client, 0x15, 0x01); + techpoint_write_reg(client, 0x16, 0xf0); + techpoint_write_reg(client, 0x18, 0x2a); + + techpoint_write_reg(client, 0x20, 0x38); + techpoint_write_reg(client, 0x21, 0x46); + + techpoint_write_reg(client, 0x25, 0xfe); + techpoint_write_reg(client, 0x26, 0x0d); + + techpoint_write_reg(client, 0x2c, 0x3a); + techpoint_write_reg(client, 0x2d, 0x54); + techpoint_write_reg(client, 0x2e, 0x40); + + techpoint_write_reg(client, 0x30, 0xa5); + techpoint_write_reg(client, 0x31, 0x95); + techpoint_write_reg(client, 0x32, 0xe0); + techpoint_write_reg(client, 0x33, 0x60); + } + + tp9951_set_mipi_out(client, reso, MIPI_2LANE); // 2 lane + break; + + case TECHPOINT_S_RESO_PAL: +#if TP9951_DEF_PAL + default: +#endif + +#if CVBS_960H + dev_err(&client->dev, "set channel CVBS_960H\n"); + + techpoint_write_reg(client, 0x02, 0x47); + techpoint_write_reg(client, 0x0c, 0x13); + techpoint_write_reg(client, 0x0d, 0x51); + + techpoint_write_reg(client, 0x15, 0x13); + techpoint_write_reg(client, 0x16, 0x76); + techpoint_write_reg(client, 0x17, 0x80); + techpoint_write_reg(client, 0x18, 0x17); + techpoint_write_reg(client, 0x19, 0x20); + techpoint_write_reg(client, 0x1a, 0x17); + techpoint_write_reg(client, 0x1c, 0x09); + techpoint_write_reg(client, 0x1d, 0x48); + + techpoint_write_reg(client, 0x20, 0x48); + techpoint_write_reg(client, 0x21, 0x84); + techpoint_write_reg(client, 0x22, 0x37); + techpoint_write_reg(client, 0x23, 0x3f); + + techpoint_write_reg(client, 0x2b, 0x70); + techpoint_write_reg(client, 0x2c, 0x2a); + techpoint_write_reg(client, 0x2d, 0x64); + techpoint_write_reg(client, 0x2e, 0x56); + + techpoint_write_reg(client, 0x30, 0x7a); + techpoint_write_reg(client, 0x31, 0x4a); + techpoint_write_reg(client, 0x32, 0x4d); + techpoint_write_reg(client, 0x33, 0xf0); + + techpoint_write_reg(client, 0x35, 0x65); + techpoint_write_reg(client, 0x38, 0x00); + techpoint_write_reg(client, 0x39, 0x04); + +#else //PAL 720H + dev_err(&client->dev, "set channel PAL 720H\n"); + techpoint_write_reg(client, 0x02, 0x47); + techpoint_write_reg(client, 0x06, 0x32); + techpoint_write_reg(client, 0x0c, 0x13); + techpoint_write_reg(client, 0x0d, 0x51); + + techpoint_write_reg(client, 0x15, 0x03); + techpoint_write_reg(client, 0x16, 0xf0); + techpoint_write_reg(client, 0x17, 0xa0); + techpoint_write_reg(client, 0x18, 0x17); + techpoint_write_reg(client, 0x19, 0x20); + techpoint_write_reg(client, 0x1a, 0x15); + techpoint_write_reg(client, 0x1c, 0x06); + techpoint_write_reg(client, 0x1d, 0xc0); + + techpoint_write_reg(client, 0x20, 0x48); + techpoint_write_reg(client, 0x21, 0x84); + techpoint_write_reg(client, 0x22, 0x37); + techpoint_write_reg(client, 0x23, 0x3f); + + techpoint_write_reg(client, 0x2b, 0x70); + techpoint_write_reg(client, 0x2c, 0x2a); + techpoint_write_reg(client, 0x2d, 0x4b); + techpoint_write_reg(client, 0x2e, 0x56); + + techpoint_write_reg(client, 0x30, 0x7a); + techpoint_write_reg(client, 0x31, 0x4a); + techpoint_write_reg(client, 0x32, 0x4d); + techpoint_write_reg(client, 0x33, 0xfb); + + techpoint_write_reg(client, 0x35, 0x65); + techpoint_write_reg(client, 0x38, 0x00); + techpoint_write_reg(client, 0x39, 0x04); +#endif + tp9951_set_mipi_out(client, reso, MIPI_2LANE); // 2 lane + + break; + case TECHPOINT_S_RESO_NTSC: +#if TP9951_DEF_NTSC + default: +#endif + +#if CVBS_960H + dev_err(&client->dev, "set channel NTSC CVBS_960H\n"); + techpoint_write_reg(client, 0x02, 0x47); + techpoint_write_reg(client, 0x0c, 0x13); + techpoint_write_reg(client, 0x0d, 0x50); + + techpoint_write_reg(client, 0x15, 0x13); + techpoint_write_reg(client, 0x16, 0x60); + techpoint_write_reg(client, 0x17, 0x80); + techpoint_write_reg(client, 0x18, 0x12); + techpoint_write_reg(client, 0x19, 0xf0); + techpoint_write_reg(client, 0x1a, 0x07); + techpoint_write_reg(client, 0x1c, 0x09); + techpoint_write_reg(client, 0x1d, 0x38); + + techpoint_write_reg(client, 0x20, 0x40); + techpoint_write_reg(client, 0x21, 0x84); + techpoint_write_reg(client, 0x22, 0x36); + techpoint_write_reg(client, 0x23, 0x3c); + + techpoint_write_reg(client, 0x2b, 0x70); + techpoint_write_reg(client, 0x2c, 0x2a); + techpoint_write_reg(client, 0x2d, 0x68); + techpoint_write_reg(client, 0x2e, 0x57); + + techpoint_write_reg(client, 0x30, 0x62); + techpoint_write_reg(client, 0x31, 0xbb); + techpoint_write_reg(client, 0x32, 0x96); + techpoint_write_reg(client, 0x33, 0xc0); + + techpoint_write_reg(client, 0x35, 0x65); + techpoint_write_reg(client, 0x38, 0x00); + techpoint_write_reg(client, 0x39, 0x04); +#else + dev_err(&client->dev, "set channel NTSC 720H\n"); + techpoint_write_reg(client, 0x02, 0x47); + techpoint_write_reg(client, 0x0c, 0x13); + techpoint_write_reg(client, 0x0d, 0x50); + + techpoint_write_reg(client, 0x15, 0x03); + techpoint_write_reg(client, 0x16, 0xd6); + techpoint_write_reg(client, 0x17, 0xa0); + techpoint_write_reg(client, 0x18, 0x12); + techpoint_write_reg(client, 0x19, 0xf0); + techpoint_write_reg(client, 0x1a, 0x05); + techpoint_write_reg(client, 0x1c, 0x06); + techpoint_write_reg(client, 0x1d, 0xb4); + + techpoint_write_reg(client, 0x20, 0x40); + techpoint_write_reg(client, 0x21, 0x84); + techpoint_write_reg(client, 0x22, 0x36); + techpoint_write_reg(client, 0x23, 0x3c); + + techpoint_write_reg(client, 0x2b, 0x70); + techpoint_write_reg(client, 0x2c, 0x2a); + techpoint_write_reg(client, 0x2d, 0x4b); + techpoint_write_reg(client, 0x2e, 0x57); + + techpoint_write_reg(client, 0x30, 0x62); + techpoint_write_reg(client, 0x31, 0xbb); + techpoint_write_reg(client, 0x32, 0x96); + techpoint_write_reg(client, 0x33, 0xcb); + + techpoint_write_reg(client, 0x35, 0x65); + techpoint_write_reg(client, 0x38, 0x00); + techpoint_write_reg(client, 0x39, 0x04); +#endif + break; + } + +#if TECHPOINT_TEST_PATTERN + techpoint_write_reg(client, 0x2a, 0x3c); +#endif + + return 0; +} + +// detect for reference only, the accuracy may be affected by the current invoked decoding standard. +int tp9951_get_channel_reso(struct i2c_client *client, int ch) +{ + u8 detect_fmt = 0xff; + u8 reso = 0xff; + + techpoint_write_reg(client, 0x40, ch); + techpoint_read_reg(client, 0x03, &detect_fmt); + reso = detect_fmt & 0x7; + + switch (reso) { + case TP9951_CVSTD_720P_25: +#if TP9951_DEF_720P + default: +#endif + dev_err(&client->dev, "detect channel %d 720P_25\n", ch); + return TECHPOINT_S_RESO_720P_25; + case TP9951_CVSTD_1080P_25: +#if TP9951_DEF_1080P + default: +#endif + dev_err(&client->dev, "detect channel %d 1080P_25\n", ch); + return TECHPOINT_S_RESO_1080P_25; + case TP9951_CVSTD_PAL: +#if TP9951_DEF_PAL + default: +#endif + dev_err(&client->dev, "detect channel %d PAL\n", ch); + return TECHPOINT_S_RESO_PAL; + case TP9951_CVSTD_NTSC: +#if TP9951_DEF_NTSC + default: +#endif + dev_err(&client->dev, "detect channel %d NTSC\n", ch); + return TECHPOINT_S_RESO_NTSC; + } + + return reso; +} + +int tp9951_set_quick_stream(struct i2c_client *client, u32 stream) +{ + // mutex_lock(&techpoint->mutex); + if (stream) { + techpoint_write_reg(client, 0x40, 0x8); + techpoint_write_reg(client, 0x28, 0x0); + } else { + techpoint_write_reg(client, 0x40, 0x8); + techpoint_write_reg(client, 0x28, 0x2); + usleep_range(40 * 1000, 50 * 1000); + } + // mutex_unlock(&techpoint->mutex); + return 0; +} diff --git a/drivers/media/i2c/techpoint/techpoint_tp9951.h b/drivers/media/i2c/techpoint/techpoint_tp9951.h new file mode 100644 index 000000000000..76cbda2d7ef9 --- /dev/null +++ b/drivers/media/i2c/techpoint/techpoint_tp9951.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * techpoint tp9951 regs + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + */ + +#ifndef _TECHPOINT_TP9951_H +#define _TECHPOINT_TP9951_H + +#include "techpoint_common.h" + +#define DEBUG + +#define TP9951_DEF_1080P 1 +#define TP9951_DEF_720P 0 +#define TP9951_DEF_PAL 0 +#define TP9951_DEF_NTSC 0 + +#define STD_TVI 0 +#define STD_HDA 1 + +// device id 0x2860 +#define TP9951_CHIP_ID_H_REG 0xFE +#define TP9951_CHIP_ID_H_VALUE 0x28 +#define TP9951_CHIP_ID_L_REG 0xFF +#define TP9951_CHIP_ID_L_VALUE 0x60 + +#define TP9951_LINK_FREQ_148M (148500000UL >> 1) +#define TP9951_LINK_FREQ_297M (297000000UL >> 1) +#define TP9951_LINK_FREQ_594M (594000000UL >> 1) +#define TP9951_LANES 2 +#define TP9951_BITS_PER_SAMPLE 8 + +enum tp9952_support_mipi_lane { + MIPI_2LANE, + MIPI_1LANE, +}; + +#define CVBS_960H (0) //1->960H 0->720H + +enum tp9951_support_reso { + TP9951_CVSTD_720P_60 = 0, + TP9951_CVSTD_720P_50, + TP9951_CVSTD_1080P_30, + TP9951_CVSTD_1080P_25, + TP9951_CVSTD_720P_30, + TP9951_CVSTD_720P_25, + TP9951_CVSTD_SD, + TP9951_CVSTD_OTHER, + TP9951_CVSTD_720P_275, + TP9951_CVSTD_QHD30, //960×540 only support with 2lane mode + TP9951_CVSTD_QHD25, //960×540 only support with 2lane mode + TP9951_CVSTD_PAL, + TP9951_CVSTD_NTSC, + TP9951_CVSTD_UVGA25, //1280x960p25, must use with MIPI_4CH4LANE_445M + TP9951_CVSTD_UVGA30, //1280x960p30, must use with MIPI_4CH4LANE_445M + TP9951_CVSTD_A_UVGA30, //HDA 1280x960p30, must use with MIPI_4CH4LANE_378M + TP9951_CVSTD_F_UVGA30, //FH 1280x960p30, 1800x1000 + TP9951_CVSTD_HD30864, //total 1600x900 86.4M + TP9951_CVSTD_HD30HDR, //special 720p30 with ISX019/SC120AT,total 1650x900 + TP9951_CVSTD_1080P_60,//only support with 2lane mode + TP9951_CVSTD_1080P_50,//only support with 2lane mode + TP9951_CVSTD_1080P_28, + TP9951_CVSTD_1080P_275, +}; + +int tp9951_initialize(struct techpoint *techpoint); +int tp9951_get_channel_input_status(struct techpoint *techpoint, u8 ch); +int tp9951_get_all_input_status(struct techpoint *techpoint, u8 *detect_status); +int tp9951_set_channel_reso(struct i2c_client *client, int ch, + enum techpoint_support_reso reso); +int tp9951_get_channel_reso(struct i2c_client *client, int ch); +int tp9951_set_quick_stream(struct i2c_client *client, u32 stream); + +#endif // _TECHPOINT_TP9951_H diff --git a/drivers/media/i2c/techpoint/techpoint_v4l2.c b/drivers/media/i2c/techpoint/techpoint_v4l2.c index 82ef4480323d..39f6a3b71e77 100644 --- a/drivers/media/i2c/techpoint/techpoint_v4l2.c +++ b/drivers/media/i2c/techpoint/techpoint_v4l2.c @@ -860,6 +860,7 @@ static const struct of_device_id techpoint_of_match[] = { { .compatible = "techpoint,tp2815" }, { .compatible = "techpoint,tp9930" }, { .compatible = "techpoint,tp9950" }, + { .compatible = "techpoint,tp9951" }, { }, }; @@ -1297,7 +1298,6 @@ static int techpoint_audio_probe(struct techpoint *techpoint) } if (techpoint->chip_id == CHIP_TP9930) { - techpoint_write_reg(techpoint->client, 0x40, 0x00); for (i = 0; i < 0xff; i++) techpoint_write_reg(techpoint->client, i, 0xbb);