diff --git a/drivers/media/i2c/techpoint/Makefile b/drivers/media/i2c/techpoint/Makefile index 9749e0688d2b..f7dc0e8111f7 100644 --- a/drivers/media/i2c/techpoint/Makefile +++ b/drivers/media/i2c/techpoint/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 techpoint-objs += techpoint_v4l2.o techpoint_dev.o \ - techpoint_tp9930.o techpoint_tp2855.o + techpoint_tp9930.o techpoint_tp2855.o \ + techpoint_tp9950.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 2ac5f26581e7..8abfc9d2e245 100644 --- a/drivers/media/i2c/techpoint/techpoint_common.h +++ b/drivers/media/i2c/techpoint/techpoint_common.h @@ -2,7 +2,7 @@ /* * Rockchip CIF Driver * - * Copyright (C) 2021 Rockchip Electronics Co., Ltd. + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. */ #ifndef _TECHPOINT_COMMON_H @@ -28,11 +28,12 @@ #include #include #include +#include +#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) #define TECHPOINT_CAMERA_XVCLK_FREQ "xvclk_freq" -#define TECHPOINT_CHANNEL_NUMS "channel_nums" #define TECHPOINT_TEST_PATTERN 0 #define DEF_1080P 1 @@ -50,6 +51,7 @@ enum techpoint_chips { CHIP_TP2855, CHIP_TP2815, CHIP_TP9930, + CHIP_TP9950, }; enum techpoint_input_type { @@ -63,6 +65,8 @@ enum techpoint_support_reso { TECHPOINT_S_RESO_1080P_25, TECHPOINT_S_RESO_720P_30, TECHPOINT_S_RESO_1080P_30, + TECHPOINT_S_RESO_PAL, + TECHPOINT_S_RESO_NTSC, TECHPOINT_S_RESO_NUMS, }; @@ -123,7 +127,7 @@ struct techpoint { struct techpoint_audio *audio_in; struct techpoint_audio *audio_out; int i2c_idx; - u32 channel_nums; + u32 data_lanes; enum techpoint_chips chip_id; struct techpoint_video_modes *video_modes; diff --git a/drivers/media/i2c/techpoint/techpoint_dev.c b/drivers/media/i2c/techpoint/techpoint_dev.c index 0dd7d8f658db..a1eb0c221900 100644 --- a/drivers/media/i2c/techpoint/techpoint_dev.c +++ b/drivers/media/i2c/techpoint/techpoint_dev.c @@ -2,13 +2,14 @@ /* * techpoint dev driver * - * Copyright (C) 2021 Rockchip Electronics Co., Ltd. + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. * * V0.0X01.0X00 first version. */ #include "techpoint_dev.h" #include "techpoint_tp9930.h" +#include "techpoint_tp9950.h" #include "techpoint_tp2855.h" #include "techpoint_tp2815.h" @@ -118,6 +119,13 @@ static int check_chip_id(struct techpoint *techpoint) 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) { + dev_info(&client->dev, + "techpoint check chip id CHIP_TP9950 !\n"); + techpoint->chip_id = CHIP_TP9950; + techpoint->input_type = TECHPOINT_MIPI; + return 0; } else { dev_info(&client->dev, "techpoint check chip id failed !\n"); } @@ -134,6 +142,8 @@ int techpoint_initialize_devices(struct techpoint *techpoint) tp9930_initialize(techpoint); } else if (techpoint->chip_id == CHIP_TP2855) { tp2855_initialize(techpoint); + } else if (techpoint->chip_id == CHIP_TP9950) { + tp9950_initialize(techpoint); } sema_init(®_sem, 1); @@ -258,6 +268,11 @@ static __maybe_unused int auto_detect_channel_fmt(struct techpoint *techpoint) } } + if (techpoint->chip_id == CHIP_TP9950) { + reso = tp9950_get_channel_reso(client, 0); + tp9950_set_channel_reso(client, 0, reso); + } + up(®_sem); return 0; diff --git a/drivers/media/i2c/techpoint/techpoint_tp9950.c b/drivers/media/i2c/techpoint/techpoint_tp9950.c new file mode 100644 index 000000000000..f96051a5998c --- /dev/null +++ b/drivers/media/i2c/techpoint/techpoint_tp9950.c @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * techpoint lib + * + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. + */ + +#include "techpoint_tp9950.h" +#include "techpoint_dev.h" + +static struct techpoint_video_modes supported_modes[] = { +#if TP9950_DEF_PAL + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 960, + .height = 576, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .link_freq_value = TP9950_LINK_FREQ_148M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9950_BITS_PER_SAMPLE, + .lane = TP9950_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 TP9950_DEF_NTSC + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 960, + .height = 480, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .link_freq_value = TP9950_LINK_FREQ_148M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9950_BITS_PER_SAMPLE, + .lane = TP9950_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 TP9950_DEF_1080P + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1920, + .height = 1080, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .link_freq_value = TP9950_LINK_FREQ_594M, + .link_freq_value = TP9950_LINK_FREQ_297M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9950_BITS_PER_SAMPLE, + .lane = TP9950_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 TP9950_DEF_720P + { + .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1280, + .height = 720, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .link_freq_value = TP9950_LINK_FREQ_297M, + .common_reg_list = NULL, + .common_reg_size = 0, + .bpp = TP9950_BITS_PER_SAMPLE, + .lane = TP9950_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 tp9950_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 tp9950_get_channel_input_status(struct i2c_client *client, u8 ch) +{ + u8 val = 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 tp9950_get_all_input_status(struct i2c_client *client, u8 *detect_status) +{ + u8 val = 0, i; + + for (i = 0; i < PAD_MAX; i++) { + techpoint_write_reg(client, PAGE_REG, i); + techpoint_read_reg(client, INPUT_STATUS_REG, &val); + detect_status[i] = tp9950_get_channel_input_status(client, i); + } + + return 0; +} + +int tp9950_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, 0x41, 0x00); + techpoint_write_reg(client, 0x40, 0x08); + techpoint_write_reg(client, 0x01, 0xf8); + techpoint_write_reg(client, 0x02, 0x01); + techpoint_write_reg(client, 0x08, 0x03); + techpoint_write_reg(client, 0x20, 0x12); + techpoint_write_reg(client, 0x39, 0x00); + + techpoint_write_reg(client, 0x40, 0x00); + techpoint_write_reg(client, 0x4c, 0x40); + techpoint_write_reg(client, 0x4e, 0x00); + techpoint_write_reg(client, 0x27, 0x2d); + techpoint_write_reg(client, 0xfd, 0x80); + + switch (val) { + case TECHPOINT_S_RESO_720P_25: +#if TP9950_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, 0x0a); + 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); + } + techpoint_write_reg(client, 0x40, 0x08); + techpoint_write_reg(client, 0x23, 0x02); + techpoint_write_reg(client, 0x13, 0x24); + techpoint_write_reg(client, 0x14, 0x46); + techpoint_write_reg(client, 0x15, 0x09); + techpoint_write_reg(client, 0x25, 0x08); + techpoint_write_reg(client, 0x26, 0x01); + techpoint_write_reg(client, 0x27, 0x0e); + techpoint_write_reg(client, 0x10, 0x88); + techpoint_write_reg(client, 0x10, 0x08); + techpoint_write_reg(client, 0x23, 0x00); + techpoint_write_reg(client, 0x40, 0x00); + break; + case TECHPOINT_S_RESO_1080P_25: +#if TP9950_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, 0x0a); + 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); + } + techpoint_write_reg(client, 0x40, 0x08); + techpoint_write_reg(client, 0x23, 0x02); + techpoint_write_reg(client, 0x13, 0x04); + techpoint_write_reg(client, 0x14, 0x46); + techpoint_write_reg(client, 0x15, 0x09); + techpoint_write_reg(client, 0x25, 0x08); + techpoint_write_reg(client, 0x26, 0x04); + techpoint_write_reg(client, 0x27, 0x0c); + techpoint_write_reg(client, 0x10, 0x88); + techpoint_write_reg(client, 0x10, 0x08); + techpoint_write_reg(client, 0x23, 0x00); + techpoint_write_reg(client, 0x40, 0x00); + /* techpoint_write_reg(client, 0x41, 0xc0); */ + break; + case TECHPOINT_S_RESO_PAL: +#if TP9950_DEF_PAL + default: +#endif + dev_err(&client->dev, "set channel PAL\n"); + techpoint_write_reg(client, 0x02, 0x47); + techpoint_write_reg(client, 0x07, 0x80); + techpoint_write_reg(client, 0x0b, 0x80); + 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); + techpoint_write_reg(client, 0x40, 0x08); + techpoint_write_reg(client, 0x23, 0x02); + techpoint_write_reg(client, 0x13, 0x24); + techpoint_write_reg(client, 0x14, 0x57); + techpoint_write_reg(client, 0x15, 0x0e); + techpoint_write_reg(client, 0x25, 0x02); + techpoint_write_reg(client, 0x26, 0x00); + techpoint_write_reg(client, 0x27, 0x03); + techpoint_write_reg(client, 0x10, 0x88); + techpoint_write_reg(client, 0x10, 0x08); + techpoint_write_reg(client, 0x23, 0x00); + techpoint_write_reg(client, 0x40, 0x00); + break; + case TECHPOINT_S_RESO_NTSC: +#if TP9950_DEF_NTSC + default: +#endif + dev_err(&client->dev, "set channel NTSC\n"); + techpoint_write_reg(client, 0x02, 0x47); + techpoint_write_reg(client, 0x07, 0x80); + techpoint_write_reg(client, 0x0b, 0x80); + 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); + + techpoint_write_reg(client, 0x40, 0x08); + techpoint_write_reg(client, 0x23, 0x02); + techpoint_write_reg(client, 0x13, 0x24); + techpoint_write_reg(client, 0x14, 0x57); + techpoint_write_reg(client, 0x15, 0x0e); + + techpoint_write_reg(client, 0x25, 0x02); + techpoint_write_reg(client, 0x26, 0x00); + techpoint_write_reg(client, 0x27, 0x03); + + techpoint_write_reg(client, 0x10, 0x88); + techpoint_write_reg(client, 0x10, 0x08); + techpoint_write_reg(client, 0x23, 0x00); + techpoint_write_reg(client, 0x40, 0x00); + break; + } + +#if TECHPOINT_TEST_PATTERN + techpoint_write_reg(client, 0x2a, 0x3c); +#endif + + return 0; +} + +int tp9950_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 TP9950_CVSTD_720P_25: +#if TP9950_DEF_720P + default: +#endif + dev_err(&client->dev, "detect channel %d 720P_25\n", ch); + return TECHPOINT_S_RESO_720P_25; + case TP9950_CVSTD_1080P_25: +#if TP9950_DEF_1080P + default: +#endif + dev_err(&client->dev, "detect channel %d 1080P_25\n", ch); + return TECHPOINT_S_RESO_1080P_25; + case TP9950_CVSTD_PAL: +#if TP9950_DEF_PAL + default: +#endif + dev_err(&client->dev, "detect channel %d PAL\n", ch); + return TECHPOINT_S_RESO_PAL; + case TP9950_CVSTD_NTSC: +#if TP9950_DEF_NTSC + default: +#endif + dev_err(&client->dev, "detect channel %d NTSC\n", ch); + return TECHPOINT_S_RESO_NTSC; + } + + return reso; +} + +int tp9950_set_quick_stream(struct i2c_client *client, u32 stream) +{ + return 0; +} diff --git a/drivers/media/i2c/techpoint/techpoint_tp9950.h b/drivers/media/i2c/techpoint/techpoint_tp9950.h new file mode 100644 index 000000000000..8d43682fe1ae --- /dev/null +++ b/drivers/media/i2c/techpoint/techpoint_tp9950.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * techpoint tp9950 regs + * + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. + */ + +#ifndef _TECHPOINT_TP9950_H +#define _TECHPOINT_TP9950_H + +#include "techpoint_common.h" + +#define DEBUG + +#define TP9950_DEF_1080P 0 +#define TP9950_DEF_720P 1 +#define TP9950_DEF_PAL 0 +#define TP9950_DEF_NTSC 0 + +#define STD_TVI 0 +#define STD_HDA 1 + +#define TP9950_CHIP_ID_H_REG 0xFE +#define TP9950_CHIP_ID_H_VALUE 0x28 +#define TP9950_CHIP_ID_L_REG 0xFF +#define TP9950_CHIP_ID_L_VALUE 0x50 + +#define TP9950_LINK_FREQ_148M (148500000UL >> 1) +#define TP9950_LINK_FREQ_297M (297000000UL >> 1) +#define TP9950_LINK_FREQ_594M (594000000UL >> 1) +#define TP9950_LANES 2 +#define TP9950_BITS_PER_SAMPLE 8 + +enum tp9950_support_reso { + TP9950_CVSTD_720P_60 = 0, + TP9950_CVSTD_720P_50, + TP9950_CVSTD_1080P_30, + TP9950_CVSTD_1080P_25, + TP9950_CVSTD_720P_30, + TP9950_CVSTD_720P_25, + TP9950_CVSTD_SD, + TP9950_CVSTD_OTHER, + TP9950_CVSTD_PAL, + TP9950_CVSTD_NTSC, +}; + +int tp9950_initialize(struct techpoint *techpoint); +int tp9950_get_channel_input_status(struct i2c_client *client, u8 ch); +int tp9950_get_all_input_status(struct i2c_client *client, u8 *detect_status); +int tp9950_set_channel_reso(struct i2c_client *client, int ch, + enum techpoint_support_reso reso); +int tp9950_get_channel_reso(struct i2c_client *client, int ch); +int tp9950_set_quick_stream(struct i2c_client *client, u32 stream); + +#endif // _TECHPOINT_TP9950_H diff --git a/drivers/media/i2c/techpoint/techpoint_v4l2.c b/drivers/media/i2c/techpoint/techpoint_v4l2.c index bab8436f2ed6..23b14b3c8c49 100644 --- a/drivers/media/i2c/techpoint/techpoint_v4l2.c +++ b/drivers/media/i2c/techpoint/techpoint_v4l2.c @@ -2,7 +2,7 @@ /* * techpoint v4l2 driver * - * Copyright (C) 2021 Rockchip Electronics Co., Ltd. + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. * */ @@ -76,6 +76,9 @@ static int techpoint_analyze_dts(struct techpoint *techpoint) struct i2c_client *client = techpoint->client; struct device *dev = &client->dev; struct device_node *node = dev->of_node; + struct device_node *endpoint; + struct fwnode_handle *fwnode; + int rval; ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, &techpoint->module_index); @@ -95,10 +98,18 @@ static int techpoint_analyze_dts(struct techpoint *techpoint) if (ret) techpoint->xvclk_freq_value = 27000000; - ret = of_property_read_u32(node, TECHPOINT_CHANNEL_NUMS, - &techpoint->channel_nums); - if (ret) - techpoint->channel_nums = 4; + endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); + if (!endpoint) { + dev_err(dev, "Failed to get endpoint\n"); + return -EINVAL; + } + fwnode = of_fwnode_handle(endpoint); + rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); + if (rval <= 0) { + dev_warn(dev, " Get mipi lane num failed!\n"); + return -1; + } + techpoint->data_lanes = rval; techpoint->xvclk = devm_clk_get(dev, "xvclk"); if (IS_ERR(techpoint->xvclk)) { @@ -266,14 +277,11 @@ err_clk: static void __techpoint_power_off(struct techpoint *techpoint) { int ret; - struct device *dev = &techpoint->client->dev; #if TECHPOINT_SHARING_POWER return; #endif - dev_dbg(dev, "%s\n", __func__); - if (!IS_ERR(techpoint->reset_gpio)) gpiod_set_value_cansleep(techpoint->reset_gpio, 1); @@ -284,7 +292,7 @@ static void __techpoint_power_off(struct techpoint *techpoint) ret = pinctrl_select_state(techpoint->pinctrl, techpoint->pins_sleep); if (ret < 0) - dev_dbg(dev, "could not set pins\n"); + dev_err(&techpoint->client->dev, "could not set pins\n"); } if (!IS_ERR(techpoint->power_gpio)) @@ -430,10 +438,7 @@ static int techpoint_get_fmt(struct v4l2_subdev *sd, fmt->format.height = mode->height; fmt->format.code = mode->bus_fmt; fmt->format.field = V4L2_FIELD_NONE; - if (fmt->pad < PAD_MAX && fmt->pad >= PAD0) - fmt->reserved[0] = mode->vc[fmt->pad]; - else - fmt->reserved[0] = mode->vc[PAD0]; + fmt->reserved[0] = mode->vc[fmt->pad]; } mutex_unlock(&techpoint->mutex); @@ -504,7 +509,13 @@ static int techpoint_g_mbus_config(struct v4l2_subdev *sd, V4L2_MBUS_PCLK_SAMPLE_FALLING; } else if (techpoint->input_type == TECHPOINT_MIPI) { cfg->type = V4L2_MBUS_CSI2; - cfg->flags = V4L2_MBUS_CSI2_4_LANE | V4L2_MBUS_CSI2_CHANNELS; + if (techpoint->data_lanes == 4) { + cfg->flags = V4L2_MBUS_CSI2_4_LANE | V4L2_MBUS_CSI2_CHANNELS; + } else if (techpoint->data_lanes == 2) { + cfg->flags = V4L2_MBUS_CSI2_2_LANE | + V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CHANNEL_1; + } } return 0; @@ -632,8 +643,11 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, } ret = techpoint_ioctl(sd, cmd, inf); - if (!ret) + if (!ret) { ret = copy_to_user(up, inf, sizeof(*inf)); + if (ret) + ret = -EFAULT; + } kfree(inf); break; case RKMODULE_AWB_CFG: @@ -643,9 +657,11 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, return ret; } - ret = copy_from_user(cfg, up, sizeof(*cfg)); - if (!ret) - ret = techpoint_ioctl(sd, cmd, cfg); + if (copy_from_user(cfg, up, sizeof(*cfg))) { + kfree(cfg); + return -EFAULT; + } + ret = techpoint_ioctl(sd, cmd, cfg); kfree(cfg); break; case RKMODULE_GET_VC_FMT_INFO: @@ -656,8 +672,11 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, } ret = techpoint_ioctl(sd, cmd, vc_fmt_inf); - if (!ret) + if (!ret) { ret = copy_to_user(up, vc_fmt_inf, sizeof(*vc_fmt_inf)); + if (ret) + ret = -EFAULT; + } kfree(vc_fmt_inf); break; case RKMODULE_GET_VC_HOTPLUG_INFO: @@ -668,8 +687,11 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, } ret = techpoint_ioctl(sd, cmd, vc_hp_inf); - if (!ret) + if (!ret) { ret = copy_to_user(up, vc_hp_inf, sizeof(*vc_hp_inf)); + if (ret) + ret = -EFAULT; + } kfree(vc_hp_inf); break; case RKMODULE_GET_BT656_MBUS_INFO: @@ -680,8 +702,11 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, } ret = techpoint_ioctl(sd, cmd, bt565_inf); - if (!ret) + if (!ret) { ret = copy_to_user(up, bt565_inf, sizeof(*bt565_inf)); + if (ret) + ret = -EFAULT; + } kfree(bt565_inf); break; case RKMODULE_GET_VICAP_RST_INFO: @@ -692,10 +717,12 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, } ret = techpoint_ioctl(sd, cmd, vicap_rst_inf); - if (!ret) - ret = - copy_to_user(up, vicap_rst_inf, - sizeof(*vicap_rst_inf)); + if (!ret) { + ret = copy_to_user(up, vicap_rst_inf, + sizeof(*vicap_rst_inf)); + if (ret) + ret = -EFAULT; + } kfree(vicap_rst_inf); break; case RKMODULE_SET_VICAP_RST_INFO: @@ -705,8 +732,10 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, return ret; } - ret = copy_from_user(vicap_rst_inf, up, sizeof(*vicap_rst_inf)); - if (!ret) + if (copy_from_user(vicap_rst_inf, up, sizeof(*vicap_rst_inf))) { + kfree(vicap_rst_inf); + return -EFAULT; + } ret = techpoint_ioctl(sd, cmd, vicap_rst_inf); kfree(vicap_rst_inf); break; @@ -718,14 +747,19 @@ static long techpoint_compat_ioctl32(struct v4l2_subdev *sd, } ret = techpoint_ioctl(sd, cmd, stream_seq); - if (!ret) + if (!ret) { ret = copy_to_user(up, stream_seq, sizeof(*stream_seq)); + if (ret) + return -EFAULT; + } kfree(stream_seq); break; case RKMODULE_SET_QUICK_STREAM: - ret = copy_from_user(&stream, up, sizeof(u32)); - if (!ret) - ret = techpoint_ioctl(sd, cmd, &stream); + if (copy_from_user(&stream, up, sizeof(u32))) + return -EFAULT; + ret = techpoint_ioctl(sd, cmd, &stream); + if (ret) + ret = -EFAULT; break; default: ret = -ENOIOCTLCMD; @@ -825,6 +859,7 @@ static const struct of_device_id techpoint_of_match[] = { { .compatible = "techpoint,tp2855" }, { .compatible = "techpoint,tp2815" }, { .compatible = "techpoint,tp9930" }, + { .compatible = "techpoint,tp9950" }, { }, }; @@ -1333,7 +1368,7 @@ static int techpoint_probe(struct i2c_client *client, struct techpoint *techpoint; struct v4l2_subdev *sd; __maybe_unused char facing[2]; - int ret, index; + int ret = 0, index; dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16,