/* * tp2825B.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tp2802_def.h" #include "video/tp2825B.h" static struct i2c_client *tp28xx_client0; #define DEBUG 0 // printk debug information on/off #if 0 #define DEFAULT_FORMAT TP2802_720P30V2 #define DEFAULT_WIDTH 1280 #define DEFAULT_HEIGHT 720 #define DEFAULT_FRAMERATE 30 #else #define DEFAULT_FORMAT TP2802_PAL #define DEFAULT_WIDTH 720 #define DEFAULT_HEIGHT 576 #define DEFAULT_FRAMERATE 25 #endif #define DEFAULT_VIN_CH 0 #define DEFAULT_V4L2_CODE MEDIA_BUS_FMT_UYVY8_2X8 #define DRV_NAME "tp2825" static int HDC_enable = 1; static int mode = DEFAULT_FORMAT; static int test; static int chips = 1; static int output[] = { //EMB422_16BIT, //for TP2825B SEP656_8BIT, //for TP2850 }; static unsigned int id[MAX_CHIPS]; #define TP2825B_I2C_A 0x44 #define TP2825B_I2C_B 0x45 unsigned char tp2802_i2c_addr[] = { TP2825B_I2C_A, TP2825B_I2C_B }; #define TP2802_I2C_ADDR(chip_id) (tp2802_i2c_addr[chip_id]) typedef struct { unsigned int count[CHANNELS_PER_CHIP]; unsigned int mode[CHANNELS_PER_CHIP]; unsigned int scan[CHANNELS_PER_CHIP]; unsigned int gain[CHANNELS_PER_CHIP][4]; unsigned int std[CHANNELS_PER_CHIP]; unsigned int state[CHANNELS_PER_CHIP]; unsigned int force[CHANNELS_PER_CHIP]; unsigned char addr; } tp2802wd_info; static tp2802wd_info watchdog_info[MAX_CHIPS]; volatile static unsigned int watchdog_state = 0; struct task_struct *task_watchdog_deamon = NULL; //static DEFINE_SPINLOCK(watchdog_lock); struct semaphore watchdog_lock; #define WATCHDOG_EXIT 0 #define WATCHDOG_RUNNING 1 #define WDT 1 struct tp2825_v4l2_dev { struct i2c_client *i2c_client; struct gpio_desc *pwdn_gpio; struct v4l2_subdev sd; struct media_pad pad; struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */ struct v4l2_mbus_framefmt fmt; struct v4l2_fract frame_interval; int cur_fr; /* lock to protect all members below */ struct mutex lock; bool streaming; struct attribute_group attrs; }; int TP2802_watchdog_init(void); void TP2802_watchdog_exit(void); static void TP2825B_PTZ_mode(unsigned char, unsigned char, unsigned char); static int tp2802_set_video_mode(unsigned char addr, unsigned char mode, unsigned char ch, unsigned char std); static void tp2802_set_reg_page(unsigned char addr, unsigned char ch); unsigned int ConvertACPV1Data(unsigned char dat) { unsigned int i, tmp = 0; for (i = 0; i < 8; i++) { tmp <<= 3; if (0x01 & dat) tmp |= 0x06; else tmp |= 0x04; dat >>= 1; } return tmp; } void tp28xx_byte_write(unsigned char chip, unsigned char reg_addr, unsigned char value) { // unsigned char chip_addr; // chip_addr = TP2802_I2C_ADDR(chip); // gpio_i2c_write(chip_addr, addr, data); unsigned char buf[2]; struct i2c_client *client = tp28xx_client0; unsigned char chip_addr; // if (id[chip] == 0xffff) return; chip_addr = tp2802_i2c_addr[chip]; client->addr = chip_addr; buf[0] = reg_addr; buf[1] = value; i2c_master_send(client, buf, 2); udelay(300); } unsigned char tp28xx_byte_read(unsigned char chip, unsigned char reg_addr) { // unsigned char chip_addr; // chip_addr = TP2802_I2C_ADDR(chip); // return gpio_i2c_read(chip_addr, addr); unsigned char ret_data = 0xFF; int ret; struct i2c_client *client = tp28xx_client0; static struct i2c_msg msg[2]; unsigned char buffer[2]; unsigned int data_width = 1; //if (id[chip] == 0xffff) return 0xff; client->addr = tp2802_i2c_addr[chip] ; buffer[0] = reg_addr & 0xFF; msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = buffer; msg[1].addr = client->addr; msg[1].flags = client->flags | I2C_M_RD; msg[1].len = 1; msg[1].buf = buffer; ret = i2c_transfer(client->adapter, msg, 2); if (ret != 2) { printk("[%s %d] hi_i2c_transfer error, ret=%d.\n", __FUNCTION__, __LINE__, ret); return 0xff; } memcpy(&ret_data, buffer, data_width); return ret_data; } static void tp2802_write_table(unsigned char chip, unsigned char addr, unsigned char *tbl_ptr, unsigned char tbl_cnt) { unsigned char i = 0; for (i = 0; i < tbl_cnt; i++) tp28xx_byte_write(chip, (addr + i), *(tbl_ptr + i)); } static void tp28xx_reg2buf(u8 chip, u32 cnt, char *buf) { #define REG_DUMP_STEP 16 u8 val = 0; s32 i, j; for (i = 0; i < cnt / REG_DUMP_STEP; i++) { sprintf(buf, "%s0x%02x:", buf, i * REG_DUMP_STEP); for (j = 0; j < REG_DUMP_STEP; j++) { val = tp28xx_byte_read(chip, i * REG_DUMP_STEP + j); if (buf) sprintf(buf, "%s %02x", buf, val); if (j == 7) sprintf(buf, "%s ", buf); } sprintf(buf, "%s\n", buf); } } static ssize_t tp28xx_dump_reg(u8 chip, char *buf) { if (!buf) return 0; sprintf(buf, "Chip%d MIPI:\n", chip); tp2802_set_reg_page(chip, MIPI_PAGE); tp28xx_reg2buf(chip, 0x40, buf); sprintf(buf, "%s\nChip%d VIDEO:\n", buf, chip); tp2802_set_reg_page(chip, VIDEO_PAGE); tp28xx_reg2buf(chip, 0x100, buf); return strlen(buf); } static ssize_t dump_reg_show(struct device *dev, struct device_attribute *devattr, char *buf) { return tp28xx_dump_reg(0, buf); } static DEVICE_ATTR_RO(dump_reg); static struct attribute *tp2825_attr[] = { &dev_attr_dump_reg.attr, NULL }; unsigned char ReverseByte(unsigned char dat) { static const unsigned char BitReverseTable256[] = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF }; return BitReverseTable256[dat]; } void HDC_QHD_SetData(unsigned char chip, unsigned char reg, unsigned int dat) { unsigned int i; unsigned char ret = 0; unsigned char crc = 0; if (dat > 0xff) { tp28xx_byte_write(chip, reg + 0, 0x00); tp28xx_byte_write(chip, reg + 1, 0x07); tp28xx_byte_write(chip, reg + 2, 0xff); tp28xx_byte_write(chip, reg + 3, 0xff); tp28xx_byte_write(chip, reg + 4, 0xfc); } else { for (i = 0; i < 8; i++) { ret >>= 1; if (0x80 & dat) { ret |= 0x80; crc += 0x80; } dat <<= 1; } tp28xx_byte_write(chip, reg + 0, 0x00); tp28xx_byte_write(chip, reg + 1, 0x06); tp28xx_byte_write(chip, reg + 2, ret); tp28xx_byte_write(chip, reg + 3, 0x7f | crc); tp28xx_byte_write(chip, reg + 4, 0xfc); } } void HDC_SetData(unsigned char chip, unsigned char reg, unsigned int dat) { unsigned int i; unsigned char ret = 0; unsigned char crc = 0; if (dat > 0xff) { tp28xx_byte_write(chip, reg + 0, 0x07); tp28xx_byte_write(chip, reg + 1, 0xff); tp28xx_byte_write(chip, reg + 2, 0xff); tp28xx_byte_write(chip, reg + 3, 0xff); tp28xx_byte_write(chip, reg + 4, 0xfc); } else { for (i = 0; i < 8; i++) { ret >>= 1; if (0x80 & dat) { ret |= 0x80; crc += 0x80; } dat <<= 1; } tp28xx_byte_write(chip, reg + 0, 0x06); tp28xx_byte_write(chip, reg + 1, ret); tp28xx_byte_write(chip, reg + 2, 0x7f | crc); tp28xx_byte_write(chip, reg + 3, 0xff); tp28xx_byte_write(chip, reg + 4, 0xfc); } } void HDA_SetACPV2Data(unsigned char chip, unsigned char reg, unsigned char dat) { unsigned int i; unsigned int PTZ_pelco = 0; for (i = 0; i < 8; i++) { PTZ_pelco <<= 3; if (0x80 & dat) PTZ_pelco |= 0x06; else PTZ_pelco |= 0x04; dat <<= 1; } tp28xx_byte_write(chip, reg + 0, (PTZ_pelco >> 16) & 0xff); tp28xx_byte_write(chip, reg + 1, (PTZ_pelco >> 8) & 0xff); tp28xx_byte_write(chip, reg + 2, (PTZ_pelco) & 0xff); } void HDA_SetACPV1Data(unsigned char chip, unsigned char reg, unsigned char dat) { unsigned int i; unsigned int PTZ_pelco = 0; for (i = 0; i < 8; i++) { PTZ_pelco <<= 3; if (0x01 & dat) PTZ_pelco |= 0x06; else PTZ_pelco |= 0x04; dat >>= 1; } tp28xx_byte_write(chip, reg + 0, (PTZ_pelco >> 16) & 0xff); tp28xx_byte_write(chip, reg + 1, (PTZ_pelco >> 8) & 0xff); tp28xx_byte_write(chip, reg + 2, (PTZ_pelco) & 0xff); } int tp2802_open(struct inode * inode, struct file * file) { return SUCCESS; } int tp2802_close(struct inode * inode, struct file * file) { return SUCCESS; } static void tp2802_set_work_mode_1080p25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_1080p25_raster, 9); } static void tp2802_set_work_mode_1080p30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_1080p30_raster, 9); } static void tp2802_set_work_mode_720p25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_720p25_raster, 9); } static void tp2802_set_work_mode_720p30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_720p30_raster, 9); } static void tp2802_set_work_mode_720p50(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_720p50_raster, 9); } static void tp2802_set_work_mode_720p60(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_720p60_raster, 9); } static void tp2802_set_work_mode_PAL(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_PAL_raster, 9); } static void tp2802_set_work_mode_NTSC(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_NTSC_raster, 9); } static void tp2802_set_work_mode_3M(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_3M_raster, 9); } static void tp2802_set_work_mode_5M(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_5M_raster, 9); } static void tp2802_set_work_mode_4M(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_4M_raster, 9); } static void tp2802_set_work_mode_3M20(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_3M20_raster, 9); } #if 0 static void tp2802_set_work_mode_4M12(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_4M12_raster, 9); } #endif static void tp2802_set_work_mode_6M10(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_6M10_raster, 9); } #if 0 static void tp2802_set_work_mode_QHDH30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QHDH30_raster, 9); } static void tp2802_set_work_mode_QHDH25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QHDH25_raster, 9); } #endif static void tp2802_set_work_mode_QHD15(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QHD15_raster, 9); } #if 0 static void tp2802_set_work_mode_QXGAH30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QXGAH30_raster, 9); } static void tp2802_set_work_mode_QXGAH25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QXGAH25_raster, 9); } #endif static void tp2802_set_work_mode_QHD30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QHD30_raster, 9); } static void tp2802_set_work_mode_QHD25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QHD25_raster, 9); } static void tp2802_set_work_mode_QXGA30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QXGA30_raster, 9); } static void tp2802_set_work_mode_QXGA25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_QXGA25_raster, 9); } /* static void tp2802_set_work_mode_4M30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_4M30_raster, 9); } static void tp2802_set_work_mode_4M25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_4M25_raster, 9); } */ static void tp2802_set_work_mode_5M20(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_5M20_raster, 9); } /* static void tp2802_set_work_mode_5MH20(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_5MH20_raster, 9); } static void tp2802_set_work_mode_4MH30(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_4MH30_raster, 9); } static void tp2802_set_work_mode_4MH25(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_4MH25_raster, 9); } */ static void tp2802_set_work_mode_8M15(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_8M15_raster, 9); } #if 0 static void tp2802_set_work_mode_8MH15(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_8MH15_raster, 9); } #endif static void tp2802_set_work_mode_8M12(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_8M12_raster, 9); } #if 0 static void tp2802_set_work_mode_8MH12(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_8MH12_raster, 9); } #endif static void tp2802_set_work_mode_720p30HDR(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_720p30HDR_raster, 9); } static void tp2802_set_work_mode_6M20(unsigned chip) { // Start address 0x15, Size = 9B tp2802_write_table(chip, 0x15, tbl_tp2802_6M20_raster, 9); } //#define AMEND #include "tp2825b_tbl.c" // long tp2802_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned int __user *argp = (unsigned int __user *)arg; unsigned int i, j, chip, tmp, ret = 0; tp2802_register dev_register; tp2802_image_adjust image_adjust; tp2802_work_mode work_mode; tp2802_video_mode video_mode; tp2802_video_loss video_loss; tp2802_PTZ_data PTZ_data; switch (_IOC_NR(cmd)) { case _IOC_NR(TP2802_READ_REG): { if (copy_from_user(&dev_register, argp, sizeof(tp2802_register))) return FAILURE; down(&watchdog_lock); chip = dev_register.chip; tp2802_set_reg_page(chip, dev_register.ch); dev_register.value = tp28xx_byte_read(chip, dev_register.reg_addr); up(&watchdog_lock); if (copy_to_user(argp, &dev_register, sizeof(tp2802_register))) return FAILURE; break; } case _IOC_NR(TP2802_WRITE_REG): { if (copy_from_user(&dev_register, argp, sizeof(tp2802_register))) return FAILURE; down(&watchdog_lock); chip = dev_register.chip; tp2802_set_reg_page(chip, dev_register.ch); tp28xx_byte_write(chip, dev_register.reg_addr, dev_register.value); up(&watchdog_lock); break; } case _IOC_NR(TP2802_SET_VIDEO_MODE): { if (copy_from_user(&video_mode, argp, sizeof(tp2802_video_mode))) return FAILURE; if (video_mode.ch >= CHANNELS_PER_CHIP) return FAILURE; down(&watchdog_lock); ret = tp2802_set_video_mode(video_mode.chip, video_mode.mode, video_mode.ch, video_mode.std); up(&watchdog_lock); if (!(ret)) { watchdog_info[video_mode.chip].mode[video_mode.ch] = video_mode.mode; watchdog_info[video_mode.chip].std[video_mode.ch] = video_mode.std; return SUCCESS; } else { printk("Invalid mode:%d\n", video_mode.mode); return FAILURE; } break; } case _IOC_NR(TP2802_GET_VIDEO_MODE): { if (copy_from_user(&video_mode, argp, sizeof(tp2802_video_mode))) return FAILURE; //if (video_mode.ch >= CHANNELS_PER_CHIP) return FAILURE; if (video_mode.ch >= CHANNELS_PER_CHIP) video_mode.ch = 0; #if (WDT) video_mode.mode = watchdog_info[video_mode.chip].mode[video_mode.ch]; video_mode.std = watchdog_info[video_mode.chip].std[video_mode.ch]; #else down(&watchdog_lock); chip = video_mode.chip; tp2802_set_reg_page(chip, video_mode.ch); tmp = tp28xx_byte_read(chip, 0x03); tmp &= 0x7; /* [2:0] - CVSTD */ video_mode.mode = tmp; up(&watchdog_lock); #endif if (copy_to_user(argp, &video_mode, sizeof(tp2802_video_mode))) return FAILURE; break; } case _IOC_NR(TP2802_GET_VIDEO_LOSS):/* get video loss state */ { if (copy_from_user(&video_loss, argp, sizeof(tp2802_video_loss))) return FAILURE; //if (video_loss.ch >= CHANNELS_PER_CHIP) return FAILURE; if (video_mode.ch >= CHANNELS_PER_CHIP) video_mode.ch = 0; #if (WDT) video_loss.is_lost = (VIDEO_LOCKED == watchdog_info[video_loss.chip].state[video_loss.ch]) ? 0 : 1; if (video_loss.is_lost) video_loss.is_lost = (VIDEO_UNLOCK == watchdog_info[video_loss.chip].state[video_loss.ch]) ? 0 : 1; #else down(&watchdog_lock); chip = video_loss.chip; tp2802_set_reg_page(chip, video_loss.ch); tmp = tp28xx_byte_read(chip, 0x01); tmp = (tmp & 0x80) >> 7; if (!tmp) { if (0x08 == tp28xx_byte_read(chip, 0x2f)) { tmp = tp28xx_byte_read(chip, 0x04); if (tmp < 0x30) tmp = 0; else tmp = 1; } } video_loss.is_lost = tmp; /* [7] - VDLOSS */ up(&watchdog_lock); #endif if (copy_to_user(argp, &video_loss, sizeof(video_loss))) return FAILURE; break; } case _IOC_NR(TP2802_SET_IMAGE_ADJUST): { if (copy_from_user(&image_adjust, argp, sizeof(tp2802_image_adjust))) return FAILURE; if (image_adjust.ch >= CHANNELS_PER_CHIP) return FAILURE; down(&watchdog_lock); chip = image_adjust.chip; tp2802_set_reg_page(chip, image_adjust.ch); // Set Brightness tp28xx_byte_write(chip, BRIGHTNESS, image_adjust.brightness); // Set Contrast tp28xx_byte_write(chip, CONTRAST, image_adjust.contrast); // Set Saturation tp28xx_byte_write(chip, SATURATION, image_adjust.saturation); // Set Hue tp28xx_byte_write(chip, HUE, image_adjust.hue); // Set Sharpness tmp = tp28xx_byte_read(chip, SHARPNESS); tmp &= 0xe0; tmp |= (image_adjust.sharpness & 0x1F); tp28xx_byte_write(chip, SHARPNESS, tmp); up(&watchdog_lock); break; } case _IOC_NR(TP2802_GET_IMAGE_ADJUST): { if (copy_from_user(&image_adjust, argp, sizeof(tp2802_image_adjust))) return FAILURE; if (image_adjust.ch >= CHANNELS_PER_CHIP) return FAILURE; down(&watchdog_lock); chip = image_adjust.chip; tp2802_set_reg_page(chip, image_adjust.ch); // Get Brightness image_adjust.brightness = tp28xx_byte_read(chip, BRIGHTNESS); // Get Contrast image_adjust.contrast = tp28xx_byte_read(chip, CONTRAST); // Get Saturation image_adjust.saturation = tp28xx_byte_read(chip, SATURATION); // Get Hue image_adjust.hue = tp28xx_byte_read(chip, HUE); // Get Sharpness image_adjust.sharpness = 0x1F & tp28xx_byte_read(chip, SHARPNESS); up(&watchdog_lock); if (copy_to_user(argp, &image_adjust, sizeof(tp2802_image_adjust))) return FAILURE; break; } case _IOC_NR(TP2802_SET_PTZ_DATA): { if (copy_from_user(&PTZ_data, argp, sizeof(tp2802_PTZ_data))) return FAILURE; //if (PTZ_data.ch > PTZ_PIN_PTZ2) return FAILURE; down(&watchdog_lock); chip = PTZ_data.chip; { tp28xx_byte_write(chip, 0x40, 0x0); //bank switch TP2825B_PTZ_mode(chip, PTZ_data.ch, PTZ_data.mode); for (i = 0; i < 24; i++) tp28xx_byte_write(chip, 0x55 + i, 0x00); if (PTZ_HDC == PTZ_data.mode || PTZ_HDC_8M12 == PTZ_data.mode) { //HDC 1080p HDC_SetData(chip, 0x56, PTZ_data.data[0]); HDC_SetData(chip, 0x5c, PTZ_data.data[1]); HDC_SetData(chip, 0x62, PTZ_data.data[2]); HDC_SetData(chip, 0x68, PTZ_data.data[3]); TP2825B_StartTX(chip, PTZ_data.ch); HDC_SetData(chip, 0x56, PTZ_data.data[4]); HDC_SetData(chip, 0x5c, PTZ_data.data[5]); HDC_SetData(chip, 0x62, PTZ_data.data[6]); HDC_SetData(chip, 0x68, 0xffff); TP2825B_StartTX(chip, PTZ_data.ch); } else if (PTZ_HDC_FIFO == PTZ_data.mode) { //HDC 1080p FIFO mode for (i = 0; i < 7; i++) tp28xx_byte_write(chip, 0x6e, PTZ_data.data[i]); TP2825B_StartTX(chip, PTZ_data.ch); } else if (PTZ_HDC_QHD == PTZ_data.mode || PTZ_HDC_8M15 == PTZ_data.mode) { //HDC QHD HDC_QHD_SetData(chip, 0x56, PTZ_data.data[0]); HDC_QHD_SetData(chip, 0x5c, PTZ_data.data[1]); HDC_QHD_SetData(chip, 0x62, PTZ_data.data[2]); HDC_QHD_SetData(chip, 0x68, PTZ_data.data[3]); TP2825B_StartTX(chip, PTZ_data.ch); HDC_QHD_SetData(chip, 0x56, PTZ_data.data[4]); HDC_QHD_SetData(chip, 0x5c, PTZ_data.data[5]); HDC_QHD_SetData(chip, 0x62, PTZ_data.data[6]); HDC_QHD_SetData(chip, 0x68, 0xffff); TP2825B_StartTX(chip, PTZ_data.ch); } else if (PTZ_HDA_4M25 == PTZ_data.mode || PTZ_HDA_4M15 == PTZ_data.mode) { //HDA QHD for (i = 0; i < 8; i++) tp28xx_byte_write(chip, 0x6e, 0x00); TP2825B_StartTX(chip, PTZ_data.ch); for (i = 0; i < 8; i++) tp28xx_byte_write(chip, 0x6e, ReverseByte(PTZ_data.data[i])); TP2825B_StartTX(chip, PTZ_data.ch); } else if (PTZ_HDA_1080P == PTZ_data.mode || PTZ_HDA_3M18 == PTZ_data.mode || PTZ_HDA_3M25 == PTZ_data.mode) { //HDA 1080p HDA_SetACPV2Data(chip, 0x58, 0x00); HDA_SetACPV2Data(chip, 0x5e, 0x00); HDA_SetACPV2Data(chip, 0x64, 0x00); HDA_SetACPV2Data(chip, 0x6a, 0x00); TP2825B_StartTX(chip, PTZ_data.ch); HDA_SetACPV2Data(chip, 0x58, PTZ_data.data[0]); HDA_SetACPV2Data(chip, 0x5e, PTZ_data.data[1]); HDA_SetACPV2Data(chip, 0x64, PTZ_data.data[2]); HDA_SetACPV2Data(chip, 0x6a, PTZ_data.data[3]); TP2825B_StartTX(chip, PTZ_data.ch); } else if (PTZ_HDA_720P == PTZ_data.mode) { //HDA 720p HDA_SetACPV1Data(chip, 0x55, 0x00); HDA_SetACPV1Data(chip, 0x58, 0x00); HDA_SetACPV1Data(chip, 0x5b, 0x00); HDA_SetACPV1Data(chip, 0x5e, 0x00); TP2825B_StartTX(chip, PTZ_data.ch); HDA_SetACPV1Data(chip, 0x55, PTZ_data.data[0]); HDA_SetACPV1Data(chip, 0x58, PTZ_data.data[1]); HDA_SetACPV1Data(chip, 0x5b, PTZ_data.data[2]); HDA_SetACPV1Data(chip, 0x5e, PTZ_data.data[3]); TP2825B_StartTX(chip, PTZ_data.ch); } else if (PTZ_HDA_CVBS == PTZ_data.mode) {//HDA 960H HDA_SetACPV1Data(chip, 0x55, 0x00); HDA_SetACPV1Data(chip, 0x58, 0x00); HDA_SetACPV1Data(chip, 0x5b, 0x00); HDA_SetACPV1Data(chip, 0x5e, 0x00); //TP2825B_StartTX(chip, PTZ_data.ch); TP2825B_StartTX(chip, PTZ_data.ch); HDA_SetACPV1Data(chip, 0x55, PTZ_data.data[0]); HDA_SetACPV1Data(chip, 0x58, PTZ_data.data[1]); HDA_SetACPV1Data(chip, 0x5b, PTZ_data.data[2]); HDA_SetACPV1Data(chip, 0x5e, PTZ_data.data[3]); //TP2825B_StartTX(chip, PTZ_data.ch); TP2825B_StartTX(chip, PTZ_data.ch); } else { //TVI // line1 tp28xx_byte_write(chip, 0x56, 0x02); tp28xx_byte_write(chip, 0x57, PTZ_data.data[0]); tp28xx_byte_write(chip, 0x58, PTZ_data.data[1]); tp28xx_byte_write(chip, 0x59, PTZ_data.data[2]); tp28xx_byte_write(chip, 0x5A, PTZ_data.data[3]); // line2 tp28xx_byte_write(chip, 0x5C, 0x02); tp28xx_byte_write(chip, 0x5D, PTZ_data.data[4]); tp28xx_byte_write(chip, 0x5E, PTZ_data.data[5]); tp28xx_byte_write(chip, 0x5F, PTZ_data.data[6]); tp28xx_byte_write(chip, 0x60, PTZ_data.data[7]); // line3 tp28xx_byte_write(chip, 0x62, 0x02); tp28xx_byte_write(chip, 0x63, PTZ_data.data[0]); tp28xx_byte_write(chip, 0x64, PTZ_data.data[1]); tp28xx_byte_write(chip, 0x65, PTZ_data.data[2]); tp28xx_byte_write(chip, 0x66, PTZ_data.data[3]); // line4 tp28xx_byte_write(chip, 0x68, 0x02); tp28xx_byte_write(chip, 0x69, PTZ_data.data[4]); tp28xx_byte_write(chip, 0x6A, PTZ_data.data[5]); tp28xx_byte_write(chip, 0x6B, PTZ_data.data[6]); tp28xx_byte_write(chip, 0x6C, PTZ_data.data[7]); TP2825B_StartTX(chip, PTZ_data.ch); } } up(&watchdog_lock); break; } case _IOC_NR(TP2802_GET_PTZ_DATA): { if (copy_from_user(&PTZ_data, argp, sizeof(tp2802_PTZ_data))) return FAILURE; if (PTZ_data.ch >= CHANNELS_PER_CHIP) return FAILURE; down(&watchdog_lock); chip = PTZ_data.chip; { tp28xx_byte_write(chip, 0x40, 0x0); //bank switch // line1 PTZ_data.data[0] = tp28xx_byte_read(chip, 0x8C); PTZ_data.data[1] = tp28xx_byte_read(chip, 0x8D); PTZ_data.data[2] = tp28xx_byte_read(chip, 0x8E); PTZ_data.data[3] = tp28xx_byte_read(chip, 0x8F); //line2 PTZ_data.data[4] = tp28xx_byte_read(chip, 0x92); PTZ_data.data[5] = tp28xx_byte_read(chip, 0x93); PTZ_data.data[6] = tp28xx_byte_read(chip, 0x94); PTZ_data.data[7] = tp28xx_byte_read(chip, 0x95); // line3 PTZ_data.data[8] = tp28xx_byte_read(chip, 0x98); PTZ_data.data[9] = tp28xx_byte_read(chip, 0x99); PTZ_data.data[10] = tp28xx_byte_read(chip, 0x9a); PTZ_data.data[11] = tp28xx_byte_read(chip, 0x9b); //line4 PTZ_data.data[12] = tp28xx_byte_read(chip, 0x9e); PTZ_data.data[13] = tp28xx_byte_read(chip, 0x9f); PTZ_data.data[14] = tp28xx_byte_read(chip, 0xa0); PTZ_data.data[15] = tp28xx_byte_read(chip, 0xa1); } up(&watchdog_lock); if (copy_to_user(argp, &PTZ_data, sizeof(tp2802_PTZ_data))) return FAILURE; break; } case _IOC_NR(TP2802_SET_SCAN_MODE): { if (copy_from_user(&work_mode, argp, sizeof(tp2802_work_mode))) return FAILURE; down(&watchdog_lock); if (work_mode.ch >= CHANNELS_PER_CHIP) { for (i = 0; i < CHANNELS_PER_CHIP; i++) watchdog_info[work_mode.chip].scan[i] = work_mode.mode; } else { watchdog_info[work_mode.chip].scan[work_mode.ch] = work_mode.mode; } up(&watchdog_lock); break; } case _IOC_NR(TP2802_DUMP_REG): { if (copy_from_user(&dev_register, argp, sizeof(tp2802_register))) return FAILURE; down(&watchdog_lock); tp2802_set_reg_page(dev_register.chip, MIPI_PAGE); printk("MIPI\n"); for (j = 0; j < 0x40; j++) { dev_register.value = tp28xx_byte_read(dev_register.chip, j); printk("%02x:%02x\n", j, dev_register.value); } printk("VIDEO\n"); tp2802_set_reg_page(dev_register.chip, VIDEO_PAGE); for (j = 0x00; j < 0x100; j++) { dev_register.value = tp28xx_byte_read(dev_register.chip, j); printk("%02x:%02x\n", j, dev_register.value); } up(&watchdog_lock); if (copy_to_user(argp, &dev_register, sizeof(tp2802_register))) return FAILURE; break; } case _IOC_NR(TP2802_FORCE_DETECT): { if (copy_from_user(&work_mode, argp, sizeof(tp2802_work_mode))) return FAILURE; down(&watchdog_lock); if (work_mode.ch >= CHANNELS_PER_CHIP) { for (i = 0; i < CHANNELS_PER_CHIP; i++) watchdog_info[work_mode.chip].force[i] = 1; } else { watchdog_info[work_mode.chip].force[work_mode.ch] = 1; } up(&watchdog_lock); break; } case _IOC_NR(TP2802_SET_BURST_DATA): { if (copy_from_user(&PTZ_data, argp, sizeof(tp2802_PTZ_data))) return FAILURE; //if (PTZ_data.ch >= CHANNELS_PER_CHIP) return FAILURE; down(&watchdog_lock); chip = PTZ_data.chip; { tp28xx_byte_write(chip, 0x40, 0x0); //bank switch TP2825B_PTZ_mode(chip, PTZ_data.ch, PTZ_data.mode); tp28xx_byte_write(chip, 0x55, 0x00); tp28xx_byte_write(chip, 0x5b, 0x00); //line1 tp28xx_byte_write(chip, 0x56, 0x03); tp28xx_byte_write(chip, 0x57, PTZ_data.data[0]); tp28xx_byte_write(chip, 0x58, PTZ_data.data[1]); tp28xx_byte_write(chip, 0x59, PTZ_data.data[2]); tp28xx_byte_write(chip, 0x5A, PTZ_data.data[3]); //line2 tp28xx_byte_write(chip, 0x5C, 0x03); tp28xx_byte_write(chip, 0x5D, PTZ_data.data[4]); tp28xx_byte_write(chip, 0x5E, PTZ_data.data[5]); tp28xx_byte_write(chip, 0x5F, PTZ_data.data[6]); tp28xx_byte_write(chip, 0x60, PTZ_data.data[7]); //line3 tp28xx_byte_write(chip, 0x62, 0x03); tp28xx_byte_write(chip, 0x63, PTZ_data.data[8]); tp28xx_byte_write(chip, 0x64, PTZ_data.data[9]); tp28xx_byte_write(chip, 0x65, PTZ_data.data[10]); tp28xx_byte_write(chip, 0x66, PTZ_data.data[11]); //line4 tp28xx_byte_write(chip, 0x68, 0x03); tp28xx_byte_write(chip, 0x69, PTZ_data.data[12]); tp28xx_byte_write(chip, 0x6A, PTZ_data.data[13]); tp28xx_byte_write(chip, 0x6B, PTZ_data.data[14]); tp28xx_byte_write(chip, 0x6C, PTZ_data.data[15]); TP2825B_StartTX(chip, PTZ_data.ch); } up(&watchdog_lock); break; } case _IOC_NR(TP2802_SET_VIDEO_INPUT): { if (copy_from_user(&dev_register, argp, sizeof(tp2802_register))) return FAILURE; if (dev_register.value > DIFF_VIN34) return FAILURE; down(&watchdog_lock); chip = dev_register.chip; tp28xx_byte_write(chip, 0x40, 0x0); //bank switch tmp = tp28xx_byte_read(chip, 0x41); tmp &= 0xf0; tmp |= dev_register.value; tp28xx_byte_write(chip, 0x41, tmp); if (dev_register.value < DIFF_VIN12) { //single tp28xx_byte_write(chip, 0x38, 0x40); tp28xx_byte_write(chip, 0x3d, 0x60); //tp28xx_byte_write(chip, 0x3e, 0x00); } else { //differential tp28xx_byte_write(chip, 0x38, 0x4e); tp28xx_byte_write(chip, 0x3d, 0x40); //tp28xx_byte_write(chip, 0x3e, 0x80); } watchdog_info[chip].force[0] = 1; //reset when Vin is changed up(&watchdog_lock); if (copy_to_user(argp, &dev_register, sizeof(tp2802_register))) return FAILURE; break; } case _IOC_NR(TP2802_GET_VIDEO_INPUT): { if (copy_from_user(&dev_register, argp, sizeof(tp2802_register))) return FAILURE; down(&watchdog_lock); tp28xx_byte_write(dev_register.chip, 0x40, 0x0); //bank switch dev_register.value = tp28xx_byte_read(dev_register.chip, 0x41) & 0xF; up(&watchdog_lock); if (copy_to_user(argp, &dev_register, sizeof(tp2802_register))) return FAILURE; break; } case _IOC_NR(TP2802_SET_PTZ_MODE): { if (copy_from_user(&PTZ_data, argp, sizeof(tp2802_PTZ_data))) return FAILURE; if (PTZ_data.ch > PTZ_PIN_PTZ2) return FAILURE; down(&watchdog_lock); chip = PTZ_data.chip; //if (TP2825B == id[chip]) { TP2825B_PTZ_mode(chip, PTZ_data.ch, PTZ_data.mode); } up(&watchdog_lock); break; } case _IOC_NR(TP2802_SET_RX_MODE): { if (copy_from_user(&PTZ_data, argp, sizeof(tp2802_PTZ_data))) return FAILURE; down(&watchdog_lock); chip = PTZ_data.chip; tp28xx_byte_write(chip, 0x40, 0x0); //bank switch TP2825B_RX_init(chip, PTZ_data.mode); up(&watchdog_lock); break; } case _IOC_NR(TP2802_SET_FIFO_DATA): // { if (copy_from_user(&PTZ_data, argp, sizeof(tp2802_PTZ_data))) return FAILURE; if (PTZ_data.ch >= CHANNELS_PER_CHIP) return FAILURE; down(&watchdog_lock); chip = PTZ_data.chip; { //TP2854_PTZ_mode(chip, PTZ_data.ch, PTZ_data.mode); /* if (PTZ_data.mode < 128) { while((128 - tp28xx_byte_read(chip, 0xde)) < PTZ_data.mode) msleep(2); //while(tp28xx_byte_read(chip, 0xde)) msleep(2); } else */ { while ((255 - tp28xx_byte_read(chip, 0xde)) < PTZ_data.mode) msleep(2); //while(tp28xx_byte_read(chip, 0xde)) msleep(2); } //printk("ptz_mode %x\n", PTZ_data.mode); for (i = 0; i < PTZ_data.mode; i++) tp28xx_byte_write(chip, 0xdf, PTZ_data.data[i]); } up(&watchdog_lock); break; } default: { printk("Invalid tp2802 ioctl cmd!\n"); ret = -1; break; } } return ret; } static void TP2825B_Set_REG0X02(unsigned char chip, unsigned char data) { if (MUX656_8BIT == output[chip] || SEP656_8BIT == output[chip]) tp28xx_byte_write(chip, 0x02, data); else tp28xx_byte_write(chip, 0x02, data & 0x7f); } ////////////////////////////////////////////////////////////////////////////////////////////// static void TP2826_C1080P25_DataSet(unsigned char chip) { tp28xx_byte_write(chip, 0x13, 0x40); tp28xx_byte_write(chip, 0x20, 0x50); tp28xx_byte_write(chip, 0x26, 0x01); tp28xx_byte_write(chip, 0x27, 0x5a); tp28xx_byte_write(chip, 0x28, 0x04); tp28xx_byte_write(chip, 0x2b, 0x60); tp28xx_byte_write(chip, 0x2d, 0x54); tp28xx_byte_write(chip, 0x2e, 0x40); tp28xx_byte_write(chip, 0x30, 0x41); tp28xx_byte_write(chip, 0x31, 0x82); tp28xx_byte_write(chip, 0x32, 0x27); tp28xx_byte_write(chip, 0x33, 0xa2); } static void TP2826_C720P25_DataSet(unsigned char chip) { tp28xx_byte_write(chip, 0x13, 0x40); tp28xx_byte_write(chip, 0x20, 0x3a); tp28xx_byte_write(chip, 0x26, 0x01); tp28xx_byte_write(chip, 0x27, 0x5a); tp28xx_byte_write(chip, 0x28, 0x04); tp28xx_byte_write(chip, 0x2b, 0x60); tp28xx_byte_write(chip, 0x2d, 0x36); tp28xx_byte_write(chip, 0x2e, 0x40); tp28xx_byte_write(chip, 0x30, 0x48); tp28xx_byte_write(chip, 0x31, 0x67); tp28xx_byte_write(chip, 0x32, 0x6f); tp28xx_byte_write(chip, 0x33, 0x33); } static void TP2826_C720P50_DataSet(unsigned char chip) { tp28xx_byte_write(chip, 0x13, 0x40); tp28xx_byte_write(chip, 0x20, 0x3a); tp28xx_byte_write(chip, 0x26, 0x01); tp28xx_byte_write(chip, 0x27, 0x5a); tp28xx_byte_write(chip, 0x28, 0x04); tp28xx_byte_write(chip, 0x2b, 0x60); tp28xx_byte_write(chip, 0x2d, 0x42); tp28xx_byte_write(chip, 0x2e, 0x40); tp28xx_byte_write(chip, 0x30, 0x41); tp28xx_byte_write(chip, 0x31, 0x82); tp28xx_byte_write(chip, 0x32, 0x27); tp28xx_byte_write(chip, 0x33, 0xa3); } static void TP2826_C1080P30_DataSet(unsigned char chip) { tp28xx_byte_write(chip, 0x13, 0x40); tp28xx_byte_write(chip, 0x20, 0x3c); tp28xx_byte_write(chip, 0x26, 0x01); tp28xx_byte_write(chip, 0x27, 0x5a); tp28xx_byte_write(chip, 0x28, 0x04); tp28xx_byte_write(chip, 0x2b, 0x60); tp28xx_byte_write(chip, 0x2d, 0x4c); tp28xx_byte_write(chip, 0x2e, 0x40); tp28xx_byte_write(chip, 0x30, 0x41); tp28xx_byte_write(chip, 0x31, 0x82); tp28xx_byte_write(chip, 0x32, 0x27); tp28xx_byte_write(chip, 0x33, 0xa4); } static void TP2826_C720P30_DataSet(unsigned char chip) { tp28xx_byte_write(chip, 0x13, 0x40); tp28xx_byte_write(chip, 0x20, 0x30); tp28xx_byte_write(chip, 0x26, 0x01); tp28xx_byte_write(chip, 0x27, 0x5a); tp28xx_byte_write(chip, 0x28, 0x04); tp28xx_byte_write(chip, 0x2b, 0x60); tp28xx_byte_write(chip, 0x2d, 0x37); tp28xx_byte_write(chip, 0x2e, 0x40); tp28xx_byte_write(chip, 0x30, 0x48); tp28xx_byte_write(chip, 0x31, 0x67); tp28xx_byte_write(chip, 0x32, 0x6f); tp28xx_byte_write(chip, 0x33, 0x30); } static void TP2826_C720P60_DataSet(unsigned char chip) { tp28xx_byte_write(chip, 0x13, 0x40); tp28xx_byte_write(chip, 0x20, 0x30); tp28xx_byte_write(chip, 0x26, 0x01); tp28xx_byte_write(chip, 0x27, 0x5a); tp28xx_byte_write(chip, 0x28, 0x04); tp28xx_byte_write(chip, 0x2b, 0x60); tp28xx_byte_write(chip, 0x2d, 0x37); tp28xx_byte_write(chip, 0x2e, 0x40); tp28xx_byte_write(chip, 0x30, 0x41); tp28xx_byte_write(chip, 0x31, 0x82); tp28xx_byte_write(chip, 0x32, 0x27); tp28xx_byte_write(chip, 0x33, 0xa0); } ////////////////////////////////////////////////////////////////////////////// static int tp2802_set_video_mode(unsigned char chip, unsigned char mode, unsigned char ch, unsigned char std) { int err = 0; unsigned int tmp; pr_debug("%s() Set Chip%d ch%d mode %#x std %d\n", __func__, chip, ch, mode, std); switch (mode) { case TP2802_1080P25: tp2802_set_work_mode_1080p25(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); if (STD_HDA == std) { if (TP2860 == id[chip]) { TP2860_A1080P25_DataSet(chip); //TP2860_144_A1080P25_DataSet(chip); } else { TP2825B_A1080P25_DataSet(chip); } } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2826_C1080P25_DataSet(chip); if (STD_HDC == std) { tp28xx_byte_write(chip, 0x15, 0x13); tp28xx_byte_write(chip, 0x16, 0x60); tp28xx_byte_write(chip, 0x17, 0x80); tp28xx_byte_write(chip, 0x18, 0x29); tp28xx_byte_write(chip, 0x19, 0x38); tp28xx_byte_write(chip, 0x1A, 0x47); tp28xx_byte_write(chip, 0x1C, 0x09); tp28xx_byte_write(chip, 0x1D, 0x60); } } if (STD_HDA == std && TP2860 == id[chip]) { TP2860_SYSCLK_A1080P(chip); //TP2860_SYSCLK_144M(chip); } else { TP2825B_SYSCLK_V1(chip); } break; case TP2802_1080P30: tp2802_set_work_mode_1080p30(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); if (STD_HDA == std) { if (TP2860 == id[chip]) { TP2860_A1080P30_DataSet(chip); //TP2860_144_A1080P30_DataSet(chip); } else { TP2825B_A1080P30_DataSet(chip); } } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2826_C1080P30_DataSet(chip); if (STD_HDC == std) { tp28xx_byte_write(chip, 0x15, 0x13); tp28xx_byte_write(chip, 0x16, 0x60); tp28xx_byte_write(chip, 0x17, 0x80); tp28xx_byte_write(chip, 0x18, 0x29); tp28xx_byte_write(chip, 0x19, 0x38); tp28xx_byte_write(chip, 0x1A, 0x47); tp28xx_byte_write(chip, 0x1C, 0x09); tp28xx_byte_write(chip, 0x1D, 0x60); } } if (STD_HDA == std && TP2860 == id[chip]) { TP2860_SYSCLK_A1080P(chip); //TP2860_SYSCLK_144M(chip); } else { TP2825B_SYSCLK_V1(chip); } break; case TP2802_720P25: tp2802_set_work_mode_720p25(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V1_DataSet(chip); TP2825B_SYSCLK_V1(chip); break; case TP2802_720P30: tp2802_set_work_mode_720p30(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V1_DataSet(chip); TP2825B_SYSCLK_V1(chip); break; case TP2802_720P50: tp2802_set_work_mode_720p50(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V1_DataSet(chip); if (STD_HDA == std) { } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2826_C720P50_DataSet(chip); if (STD_HDC == std) { tp28xx_byte_write(chip, 0x15, 0x13); tp28xx_byte_write(chip, 0x16, 0x0a); tp28xx_byte_write(chip, 0x17, 0x00); tp28xx_byte_write(chip, 0x18, 0x19); tp28xx_byte_write(chip, 0x19, 0xd0); tp28xx_byte_write(chip, 0x1A, 0x25); tp28xx_byte_write(chip, 0x1C, 0x06); tp28xx_byte_write(chip, 0x1D, 0x7a); } } TP2825B_SYSCLK_V1(chip); break; case TP2802_720P60: tp2802_set_work_mode_720p60(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V1_DataSet(chip); if (STD_HDA == std) { // TP2826_A720P60_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2826_C720P60_DataSet(chip); if (STD_HDC == std) { tp28xx_byte_write(chip, 0x15, 0x13); tp28xx_byte_write(chip, 0x16, 0x08); tp28xx_byte_write(chip, 0x17, 0x00); tp28xx_byte_write(chip, 0x18, 0x19); tp28xx_byte_write(chip, 0x19, 0xd0); tp28xx_byte_write(chip, 0x1A, 0x25); tp28xx_byte_write(chip, 0x1C, 0x06); tp28xx_byte_write(chip, 0x1D, 0x72); } } TP2825B_SYSCLK_V1(chip); break; case TP2802_720P30V2: tp2802_set_work_mode_720p60(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V2_DataSet(chip); if (STD_HDA == std) { if (TP2860 == id[chip]) { TP2860_A720P30_DataSet(chip); } else { TP2825B_A720P30_DataSet(chip); } } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2826_C720P30_DataSet(chip); if (STD_HDC == std) { tp28xx_byte_write(chip, 0x15, 0x13); tp28xx_byte_write(chip, 0x16, 0x08); tp28xx_byte_write(chip, 0x17, 0x00); tp28xx_byte_write(chip, 0x18, 0x19); tp28xx_byte_write(chip, 0x19, 0xd0); tp28xx_byte_write(chip, 0x1A, 0x25); tp28xx_byte_write(chip, 0x1C, 0x06); tp28xx_byte_write(chip, 0x1D, 0x72); } } if (STD_HDA == std && TP2860 == id[chip]) TP2860_SYSCLK_A720P(chip); else TP2825B_SYSCLK_V2(chip); break; case TP2802_720P25V2: tp2802_set_work_mode_720p50(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V2_DataSet(chip); if (STD_HDA == std) { if (TP2860 == id[chip]) TP2860_A720P25_DataSet(chip); else TP2825B_A720P25_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2826_C720P25_DataSet(chip); if (STD_HDC == std) { tp28xx_byte_write(chip, 0x15, 0x13); tp28xx_byte_write(chip, 0x16, 0x0a); tp28xx_byte_write(chip, 0x17, 0x00); tp28xx_byte_write(chip, 0x18, 0x19); tp28xx_byte_write(chip, 0x19, 0xd0); tp28xx_byte_write(chip, 0x1A, 0x25); tp28xx_byte_write(chip, 0x1C, 0x06); tp28xx_byte_write(chip, 0x1D, 0x7a); } } if (STD_HDA == std && TP2860 == id[chip]) TP2860_SYSCLK_A720P(chip); else TP2825B_SYSCLK_V2(chip); break; case TP2802_PAL: tp2802_set_work_mode_PAL(chip); TP2825B_Set_REG0X02(chip, 0xCF); TP2825B_PAL_DataSet(chip); TP2825B_SYSCLK_CVBS(chip); break; case TP2802_NTSC: tp2802_set_work_mode_NTSC(chip); TP2825B_Set_REG0X02(chip, 0xCF); TP2825B_NTSC_DataSet(chip); TP2825B_SYSCLK_CVBS(chip); break; case TP2802_3M18: tp2802_set_work_mode_3M(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x16); tp28xx_byte_write(chip, 0x36, 0x30); TP2825B_SYSCLK_V1(chip); break; case TP2802_5M12: tp2802_set_work_mode_5M(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x17); tp28xx_byte_write(chip, 0x36, 0xd0); if (STD_HDA == std) { TP2825B_A5MP12_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { if (STD_HDC == std) { } } TP2825B_SYSCLK_V1(chip); break; case TP2802_4M15: tp2802_set_work_mode_4M(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x16); tp28xx_byte_write(chip, 0x36, 0x72); TP2825B_SYSCLK_V1(chip); break; case TP2802_3M20: tp2802_set_work_mode_3M20(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x16); tp28xx_byte_write(chip, 0x36, 0x72); tp28xx_byte_write(chip, 0x2d, 0x26); TP2825B_SYSCLK_V1(chip); break; case TP2802_6M10: tp2802_set_work_mode_6M10(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x17); tp28xx_byte_write(chip, 0x36, 0xbc); TP2825B_SYSCLK_V1(chip); break; case TP2802_QHD30: tp2802_set_work_mode_QHD30(chip); TP2825B_Set_REG0X02(chip, 0xD8); TP2825B_QHDP30_25_DataSet(chip); if (STD_HDA == std) { TP2825B_AQHDP30_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2825B_CQHDP30_DataSet(chip); if (STD_HDC == std) { } } TP2825B_SYSCLK_V3(chip); break; case TP2802_QHD25: tp2802_set_work_mode_QHD25(chip); TP2825B_Set_REG0X02(chip, 0xD8); TP2825B_QHDP30_25_DataSet(chip); if (STD_HDA == std) { TP2825B_AQHDP25_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2825B_CQHDP25_DataSet(chip); if (STD_HDC == std) { } } TP2825B_SYSCLK_V3(chip); break; case TP2802_QHD15: tp2802_set_work_mode_QHD15(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x15); tp28xx_byte_write(chip, 0x36, 0xdc); if (STD_HDA == std) { TP2825B_AQHDP15_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { if (STD_HDC == std) { } } TP2825B_SYSCLK_V1(chip); break; case TP2802_QXGA18: tp2802_set_work_mode_3M(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V1_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x16); tp28xx_byte_write(chip, 0x36, 0x72); if (STD_HDA == std) { TP2825B_AQXGAP18_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { if (STD_HDC == std) { } } TP2825B_SYSCLK_V1(chip); break; case TP2802_QXGA25: tp2802_set_work_mode_QXGA25(chip); TP2825B_Set_REG0X02(chip, 0xC8); tp28xx_byte_write(chip, 0x35, 0x16); tp28xx_byte_write(chip, 0x36, 0x72); if (STD_HDA == std) { TP2825B_AQXGAP25_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { if (STD_HDC == std) { } } TP2825B_SYSCLK_V3(chip); break; case TP2802_QXGA30: tp2802_set_work_mode_QXGA30(chip); TP2825B_Set_REG0X02(chip, 0xC8); tp28xx_byte_write(chip, 0x35, 0x16); tp28xx_byte_write(chip, 0x36, 0x72); if (STD_HDA == std) { TP2825B_AQXGAP30_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { if (STD_HDC == std) { } } TP2825B_SYSCLK_V3(chip); break; case TP2802_5M20: tp2802_set_work_mode_5M20(chip); TP2825B_Set_REG0X02(chip, 0xD8); TP2825B_5MP20_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x17); tp28xx_byte_write(chip, 0x36, 0xbc); if (STD_HDA == std) { TP2825B_A5MP20_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2825B_C5MP20_DataSet(chip); if (STD_HDC == std) { } } TP2825B_SYSCLK_V3(chip); break; case TP2802_8M15: tp2802_set_work_mode_8M15(chip); TP2825B_Set_REG0X02(chip, 0xD8); TP2825B_8MP15_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x18); tp28xx_byte_write(chip, 0x36, 0xca); if (STD_HDA == std) { TP2825B_A8MP15_DataSet(chip); } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2825B_C8MP15_DataSet(chip); if (STD_HDC == std) { } } TP2825B_SYSCLK_V3(chip); break; case TP2802_8M12: tp2802_set_work_mode_8M12(chip); TP2825B_Set_REG0X02(chip, 0xD8); TP2825B_8MP15_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x18); tp28xx_byte_write(chip, 0x36, 0xca); if (STD_HDA == std) { } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2825B_C8MP12_DataSet(chip); if (STD_HDC == std) { tp28xx_byte_write(chip, 0x1c, 0x13); tp28xx_byte_write(chip, 0x1d, 0x10); } } TP2825B_SYSCLK_V3(chip); break; case TP2802_1080P60: TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_1080P60_DataSet(chip); TP2825B_SYSCLK_V3(chip); break; case TP2802_1080P50: TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_1080P50_DataSet(chip); TP2825B_SYSCLK_V3(chip); break; case TP2802_720P14: tp2802_set_work_mode_720p30(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V2_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x33); tp28xx_byte_write(chip, 0x36, 0x20); TP2825B_SYSCLK_V2(chip); break; case TP2802_720P30HDR: tp2802_set_work_mode_720p30HDR(chip); TP2825B_Set_REG0X02(chip, 0xCA); TP2825B_V2_DataSet(chip); tp28xx_byte_write(chip, 0x35, 0x33); tp28xx_byte_write(chip, 0x36, 0x39); tp28xx_byte_write(chip, 0x2d, 0x28); TP2825B_SYSCLK_V2(chip); break; case TP2802_6M20: tp2802_set_work_mode_6M20(chip); TP2825B_Set_REG0X02(chip, 0xC8); tp28xx_byte_write(chip, 0x35, 0x17); tp28xx_byte_write(chip, 0x36, 0xd0); if (STD_HDA == std) { } else if (STD_HDC == std || STD_HDC_DEFAULT == std) { TP2825B_C6MP20_DataSet(chip); if (STD_HDC == std) { } } TP2825B_SYSCLK_V3(chip); break; case TP2802_960P30: if (STD_HDA == std) { TP2825B_Set_REG0X02(chip, 0xC8); TP2860_A960P30_DataSet(chip); TP2860_SYSCLK_94500K(chip); } else { TP2825B_Set_REG0X02(chip, 0xC8); TP2860_960P30_DataSet(chip); TP2860_SYSCLK_111375K(chip); } break; // case TP2802_960P25: // TP2825B_Set_REG0X02(chip, 0xC8); // TP2860_960P25_DataSet(chip); // TP2860_SYSCLK_111375K(chip); // break; case TP2802_8M15V2: TP2825B_Set_REG0X02(chip, 0xC8); TP2831_8MP15V2_DataSet(chip); TP2825B_SYSCLK_V3(chip); break; case TP2802_1080P15: tp28xx_byte_write(chip, 0x35, 0x25); tp2802_set_work_mode_1080p30(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V2_DataSet(chip); if (STD_HDA == std) TP2825B_A1080P30_DataSet(chip); TP2825B_SYSCLK_V2(chip); break; case TP2802_1080P12: tp28xx_byte_write(chip, 0x35, 0x25); tp2802_set_work_mode_1080p25(chip); TP2825B_Set_REG0X02(chip, 0xC8); TP2825B_V2_DataSet(chip); if (STD_HDA == std) TP2825B_A1080P25_DataSet(chip); TP2825B_SYSCLK_V2(chip); break; case TP2802_5M20V2: TP2825B_Set_REG0X02(chip, 0xC8); TP2831_5MP20V2_DataSet(chip); TP2825B_SYSCLK_V3(chip); break; case TP2802_5M12V2: TP2825B_Set_REG0X02(chip, 0xC8); TP2831_5MP12V2_DataSet(chip); TP2825B_SYSCLK_V1(chip); break; case TP2802_960P25: if (STD_HDA == std) { TP2825B_Set_REG0X02(chip, 0xC8); TP2860_A960P25_DataSet(chip); TP2860_SYSCLK_A1080P(chip); } else { TP2825B_Set_REG0X02(chip, 0xC8); TP2860_960P25_DataSet(chip); TP2860_SYSCLK_111375K(chip); } break; default: err = -1; break; } if (TP2802_PAL == mode || TP2802_NTSC == mode) { //960x480/960x576 tmp = tp28xx_byte_read(chip, 0x35); tmp |= 0x40; tp28xx_byte_write(chip, 0x35, tmp); } tmp = tp28xx_byte_read(chip, 0x06); tmp |= 0x80; tp28xx_byte_write(chip, 0x06, tmp); /* if (MUX656_8BIT == output[chip] || SEP656_8BIT == output[chip]) { if (TP2802_PAL == mode || TP2802_NTSC == mode) //960x480/960x576 { #if (CVBS_960H) tp28xx_byte_write(chip, 0xfa, 0x0b); tmp = tp28xx_byte_read(chip, 0x35); tmp |= 0x40; tp28xx_byte_write(chip, 0x35, tmp); #endif } else { tp28xx_byte_write(chip, 0xfa, 0x08); } } else { //16bit output tp28xx_byte_write(chip, 0xfa, 0x0b); } */ return err; } static void tp2802_set_reg_page(unsigned char chip, unsigned char ch) { switch (ch) { case MIPI_PAGE: tp28xx_byte_write(chip, 0x40, 0x08); break; default: tp28xx_byte_write(chip, 0x40, 0x00); break; } } /* static void tp2802_manual_agc(unsigned char chip, unsigned char ch) { unsigned int agc, tmp; tp28xx_byte_write(chip, 0x2F, 0x02); agc = tp28xx_byte_read(chip, 0x04); printk("AGC=0x%04x ch%02x\r\n", agc, ch); agc += tp28xx_byte_read(chip, 0x04); agc += tp28xx_byte_read(chip, 0x04); agc += tp28xx_byte_read(chip, 0x04); agc &= 0x3f0; agc >>=1; if (agc > 0x1ff) agc = 0x1ff; #if (DEBUG) printk("AGC=0x%04x ch%02x\r\n", agc, ch); #endif tp28xx_byte_write(chip, 0x08, agc&0xff); tmp = tp28xx_byte_read(chip, 0x06); tmp &=0xf9; tmp |=(agc>>7)&0x02; tmp |=0x04; tp28xx_byte_write(chip, 0x06,tmp); } */ static void TP28xx_reset_default(int chip, unsigned char ch) { TP2825B_reset_default(chip, ch); } //////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// static void tp2802_comm_init(int chip) { if (TP2825B == id[chip]) { tp28xx_byte_write(chip, 0x40, 0x00); //default Vin1 tp28xx_byte_write(chip, 0x35, 0x25); tp28xx_byte_write(chip, 0xfd, 0x80); tp28xx_byte_write(chip, 0xfa, 0x03); TP2825B_reset_default(chip, VIDEO_PAGE); tp2802_set_video_mode(chip, mode, VIDEO_PAGE, STD_TVI); #if (WDT) tp28xx_byte_write(chip, 0x26, 0x04); #endif //MUX output TP2825B_output(chip); TP2825B_RX_init(chip, PTZ_RX_TVI_CMD); } else if (TP2850 == id[chip]) { tp28xx_byte_write(chip, 0x40, 0x00); tp28xx_byte_write(chip, 0x41, DEFAULT_VIN_CH); tp28xx_byte_write(chip, 0x35, 0x25); tp28xx_byte_write(chip, 0xfd, 0x80); tp28xx_byte_write(chip, 0xf0, 0x10); //default PTZ1 tp28xx_byte_write(chip, 0xfa, 0x83); TP2825B_reset_default(chip, VIDEO_PAGE); tp2802_set_video_mode(chip, mode, VIDEO_PAGE, STD_TVI); #if (WDT) tp28xx_byte_write(chip, 0x26, 0x04); #endif //MUX output TP2850_output(chip); TP2825B_RX_init(chip, PTZ_RX_TVI_CMD); } else if (TP2860 == id[chip]) { tp28xx_byte_write(chip, 0x40, 0x00); //default Vin1 tp28xx_byte_write(chip, 0x42, 0x00); tp28xx_byte_write(chip, 0xfd, 0x80); tp28xx_byte_write(chip, 0xf0, 0x10); //default PTZ1 tp28xx_byte_write(chip, 0x72, 0x10); tp28xx_byte_write(chip, 0xd9, 0x68); tp28xx_byte_write(chip, 0xda, 0xc0); tp28xx_byte_write(chip, 0xdb, 0x07); tp28xx_byte_write(chip, 0xdc, 0x10); tp28xx_byte_write(chip, 0xdd, 0x80); tp28xx_byte_write(chip, 0xd8, 0x85); TP2825B_reset_default(chip, VIDEO_PAGE); tp2802_set_video_mode(chip, mode, VIDEO_PAGE, STD_TVI); #if (WDT) tp28xx_byte_write(chip, 0x26, 0x04); #endif //MUX output TP2860_output(chip); TP2825B_RX_init(chip, PTZ_RX_TVI_CMD); } } static struct file_operations tp2802_fops = { .owner = THIS_MODULE, .unlocked_ioctl = tp2802_ioctl, .open = tp2802_open, .release = tp2802_close }; static struct miscdevice tp2802_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DRV_NAME, .fops = &tp2802_fops, }; module_param(mode, uint, S_IRUGO); module_param(test, uint, 0644); module_param(chips, uint, S_IRUGO); module_param_array(output, uint, &chips, S_IRUGO); static int __init tp2802_module_init(void) { int ret = 0, i = 0, val = 0; // unsigned char chip; /* // 1st check the module parameters if ((mode < TP2802_1080P25) || (mode > TP2802_720P60)) { printk("TP2802 module param 'mode' Invalid!\n"); return FAILURE; } */ printk("TP2825B driver version %d.%d.%d loaded\n", (TP2825_VERSION_CODE >> 16) & 0xff, (TP2825_VERSION_CODE >> 8) & 0xff, TP2825_VERSION_CODE & 0xff); if (chips <= 0 || chips > MAX_CHIPS) { printk("TP2825B module param 'chips' invalid value:%d\n", chips); return FAILURE; } /* register misc device*/ ret = misc_register(&tp2802_dev); if (ret) { printk("ERROR: could not register TP2825B device module\n"); return ret; } sema_init(&watchdog_lock, 1); /* initize each tp2802*/ for (i = 0; i < chips; i++) { val = tp28xx_byte_read(i, 0xfe); val <<= 8; val += tp28xx_byte_read(i, 0xff); if (TP2825B == val) printk("Chip%d: Detected TP2825B\n", i); else if (TP2850 == val) printk("Chip%d: Detected TP2850/TP9950\n", i); else if (TP2860 == val) printk("Chip%d: Detected TP2860\n", i); else printk("Chip%d: Invalid chip %2x\n", i, val); id[i] = val; // tp28xx_byte_write(chip, 0x26, 0x04); tp2802_comm_init(i); } #if (WDT) ret = TP2802_watchdog_init(); if (ret) { misc_deregister(&tp2802_dev); printk("ERROR: could not create watchdog\n"); return ret; } #endif printk("TP2825B Driver Init Successful!\n"); return SUCCESS; } static void tp2802_module_exit(void) { #if (WDT) TP2802_watchdog_exit(); #endif misc_deregister(&tp2802_dev); } ///////////////////////////////////////////////////////////////// unsigned char TP2825B_read_egain(unsigned char chip) { unsigned char gain; gain = tp28xx_byte_read(chip, 0x03); gain >>= 4; return gain; } ///////////////////////////////////////////////////////////////// unsigned char tp28xx_read_egain(unsigned char chip) { unsigned char gain; tp28xx_byte_write(chip, 0x2f, 0x00); gain = tp28xx_byte_read(chip, 0x04); return gain; } ////////////////////////////////////////////////////////////////// /****************************************************************************** * * TP2802_watchdog_deamon() * ******************************************************************************/ static int TP2802_watchdog_deamon(void *data) { //unsigned long flags; int iChip, i = 0; struct sched_param param = { .sched_priority = 99 }; tp2802wd_info *wdi = NULL; //struct timeval start, end; //int interval; unsigned char status, cvstd, gain, agc, tmp, flag_locked; unsigned char rx1, rx2; printk("TP2802_watchdog_deamon: start!\n"); sched_setscheduler(current, SCHED_FIFO, ¶m); current->flags |= PF_NOFREEZE; set_current_state(TASK_INTERRUPTIBLE); while (watchdog_state != WATCHDOG_EXIT) { down(&watchdog_lock); //do_gettimeofday(&start); for (iChip = 0; iChip < chips; iChip++) { wdi = &watchdog_info[iChip]; for (i = 0; i < CHANNELS_PER_CHIP; i++) { //scan four inputs: if (SCAN_DISABLE == wdi->scan[i]) continue; tp2802_set_reg_page(iChip, i); status = tp28xx_byte_read(iChip, 0x01); //state machine for video checking if (status & FLAG_LOSS) { //no video if (VIDEO_UNPLUG != wdi->state[i]) { //switch to no video wdi->state[i] = VIDEO_UNPLUG; wdi->count[i] = 0; if (SCAN_MANUAL != wdi->scan[i]) wdi->mode[i] = INVALID_FORMAT; #if (DEBUG) printk("video loss ch%02x chip%2x\r\n", i, iChip); #endif } if (0 == wdi->count[i]) { //first time into no video if (SCAN_MANUAL != wdi->scan[i]) { //tp2802_set_video_mode(iChip, DEFAULT_FORMAT, i, STD_TVI); TP28xx_reset_default(iChip, i); } wdi->count[i]++; } else { if (wdi->count[i] < MAX_COUNT) wdi->count[i]++; continue; } } else { //there is video if (TP2802_PAL == wdi->mode[i] || TP2802_NTSC == wdi->mode[i]) flag_locked = FLAG_HV_LOCKED; else flag_locked = FLAG_HV_LOCKED; if (flag_locked == (status & flag_locked)) { //video locked if (VIDEO_LOCKED == wdi->state[i]) { if (wdi->count[i] < MAX_COUNT) wdi->count[i]++; } else if (VIDEO_UNPLUG == wdi->state[i]) { wdi->state[i] = VIDEO_IN; wdi->count[i] = 0; #if (DEBUG) printk("1video in ch%02x chip%2x\r\n", i, iChip); #endif } else if (wdi->mode[i] != INVALID_FORMAT) { //if (FLAG_HV_LOCKED == (FLAG_HV_LOCKED & status))//H&V locked { wdi->state[i] = VIDEO_LOCKED; wdi->count[i] = 0; #if (DEBUG) printk("video locked %02x ch%02x chip%2x\r\n", status, i, iChip); #endif } } } else { //video in but unlocked if (VIDEO_UNPLUG == wdi->state[i]) { wdi->state[i] = VIDEO_IN; wdi->count[i] = 0; #if (DEBUG) printk("2video in ch%02x chip%2x\r\n", i, iChip); #endif } else if (VIDEO_LOCKED == wdi->state[i]) { wdi->state[i] = VIDEO_UNLOCK; wdi->count[i] = 0; #if (DEBUG) printk("video unstable ch%02x chip%2x\r\n", i, iChip); #endif } else { if (wdi->count[i] < MAX_COUNT) wdi->count[i]++; if (VIDEO_UNLOCK == wdi->state[i] && wdi->count[i] > 2) { wdi->state[i] = VIDEO_IN; wdi->count[i] = 0; if (SCAN_MANUAL != wdi->scan[i]) TP28xx_reset_default(iChip, i); #if (DEBUG) printk("video unlocked ch%02x chip%2x\r\n", i, iChip); #endif } } } if (wdi->force[i]) { //manual reset for V1/2 switching wdi->state[i] = VIDEO_UNPLUG; wdi->count[i] = 0; wdi->mode[i] = INVALID_FORMAT; wdi->force[i] = 0; TP28xx_reset_default(iChip, i); //tp2802_set_video_mode(iChip, DEFAULT_FORMAT, i); } } //printk("video state %2x detected ch%02x count %4x\r\n", wdi->state[i], i, wdi->count[i]); if (VIDEO_IN == wdi->state[i]) { if (SCAN_MANUAL != wdi->scan[i]) { //tp28xx_byte_write(iChip, 0x40, 0x08); //tp28xx_byte_write(iChip, 0x13, 0x24); //tp28xx_byte_write(iChip, 0x40, 0x00); //tp28xx_byte_write(iChip, 0x35, 0x25); cvstd = tp28xx_byte_read(iChip, 0x03); #if (DEBUG) printk("video format %2x detected ch%02x chip%2x count%2x\r\n", cvstd, i, iChip, wdi->count[i]); #endif cvstd &= 0x0f; wdi->std[i] = STD_TVI; if (SCAN_HDA == wdi->scan[i]) wdi->std[i] = STD_HDA; else if (SCAN_HDC == wdi->scan[i]) wdi->std[i] = STD_HDC; /* if (TP2802_SD == (cvstd&0x07)) { if (wdi->count[i] & 0x01) { wdi->mode[i] = TP2802_PAL; } else { wdi->mode[i] = TP2802_NTSC; } tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if ((cvstd&0x07) < 6) */ /* bob 20210825 if ((cvstd&0x07) < 6) { if (TP2802_720P25 == (cvstd&0x07)) { wdi->mode[i] = TP2802_720P25V2; } else if (TP2802_720P30 == (cvstd&0x07)) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_QHD15; else wdi->mode[i] = TP2802_720P30V2; } else if (TP2802_720P60 == (cvstd&0x07)) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_QHD30; else wdi->mode[i] = TP2802_720P60; } else if (TP2802_720P50 == (cvstd&0x07)) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_QHD25; else wdi->mode[i] = TP2802_720P50; } else if (TP2802_1080P30 == (cvstd&0x07)) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_8M15; else wdi->mode[i] = TP2802_1080P30; } else if (TP2802_1080P25 == (cvstd&0x07)) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_8M12; else wdi->mode[i] = TP2802_1080P25; } tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else //format is 7 */ { tp28xx_byte_write(iChip, 0x2f, 0x09); tmp = tp28xx_byte_read(iChip, 0x04); #if (DEBUG) printk("detection %02x ch%02x chip%2x\r\n", tmp, i, iChip); #endif if (0x67 == tmp) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_QHD15; else wdi->mode[i] = TP2802_720P30V2; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x7b == tmp) { wdi->mode[i] = TP2802_720P25V2; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x44 == tmp) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_8M15; else wdi->mode[i] = TP2802_1080P30; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x52 == tmp) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_8M12; else wdi->mode[i] = TP2802_1080P25; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x33 == tmp) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_QHD30; else wdi->mode[i] = TP2802_720P60; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x3d == tmp) { if (wdi->count[i] & 1) wdi->mode[i] = TP2802_QHD25; else wdi->mode[i] = TP2802_720P50; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x4e == tmp) { if (SCAN_HDA == wdi->scan[i]) wdi->mode[i] = TP2802_QXGA18; else if (SCAN_AUTO == wdi->scan[i] && wdi->count[i] < 3) wdi->mode[i] = TP2802_QXGA18; else wdi->mode[i] = TP2802_3M18; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x5d == tmp) { if ((wdi->count[i] % 3) == 0) { wdi->mode[i] = TP2802_5M12; wdi->std[i] = STD_HDA; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if ((wdi->count[i] % 3) == 1) { wdi->mode[i] = TP2802_4M15; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else { wdi->mode[i] = TP2802_720P30HDR; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } } else if (0x5c == tmp) { wdi->mode[i] = TP2802_5M12; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x75 == tmp) { wdi->mode[i] = TP2802_6M10; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x38 == tmp) { wdi->mode[i] = TP2802_QXGA25; //current only HDA wdi->std[i] = STD_HDA; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x2e == tmp) { wdi->mode[i] = TP2802_QXGA30; //current only HDA wdi->std[i] = STD_HDA; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x3a == tmp) { if (TP2802_5M20 != wdi->mode[i]) { wdi->mode[i] = TP2802_5M20; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); //soft reset agc = tp28xx_byte_read(iChip, 0x06); agc |= 0x80; tp28xx_byte_write(iChip, 0x06, agc); } } else if (0x39 == tmp) { if (TP2802_6M20 != wdi->mode[i]) { wdi->mode[i] = TP2802_6M20; wdi->std[i] = STD_HDC; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } } else if (0x89 == tmp) { wdi->mode[i] = TP2802_1080P15; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x22 == tmp) { wdi->mode[i] = TP2802_1080P60; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x29 == tmp) { wdi->mode[i] = TP2802_1080P50; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x93 == tmp) { wdi->mode[i] = TP2802_NTSC; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x94 == tmp) { wdi->mode[i] = TP2802_PAL; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x7d == tmp) { wdi->mode[i] = TP2802_8M7; wdi->std[i] = STD_HDA; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0xa4 == tmp) { wdi->mode[i] = TP2802_1080P12; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x6a == tmp) { wdi->mode[i] = TP2802_5M12V2; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } else if (0x54 == tmp) { if (TP2802_960P25 != wdi->mode[i]) { wdi->mode[i] = TP2802_960P25; wdi->std[i] = STD_HDA; tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } } } } } #define EQ_COUNT 10 if (VIDEO_LOCKED == wdi->state[i]) { //check signal lock if (0 == wdi->count[i]) { tmp = tp28xx_byte_read(iChip, 0x26); tmp |= 0x01; tp28xx_byte_write(iChip, 0x26, tmp); if ((SCAN_AUTO == wdi->scan[i] || SCAN_TVI == wdi->scan[i])) { if ((TP2802_720P30V2 == wdi->mode[i]) || (TP2802_720P25V2 == wdi->mode[i])) { tmp = tp28xx_byte_read(iChip, 0x03); #if (DEBUG) printk("CVSTD%02x ch%02x chip%2x\r\n", tmp, i, iChip); #endif if (!(0x08 & tmp)) { #if (DEBUG) printk("720P V1 Detected ch%02x chip%2x\r\n", i, iChip); #endif wdi->mode[i] &= 0xf7; tp2802_set_video_mode(iChip, wdi->mode[i], i, STD_TVI); //to speed the switching } } //these code need to keep bottom { tmp = tp28xx_byte_read(iChip, 0xa7); tmp &= 0xfe; tp28xx_byte_write(iChip, 0xa7, tmp); //tp28xx_byte_write(iChip, 0x2f, 0x0f); tp28xx_byte_write(iChip, 0x1f, 0x06); tp28xx_byte_write(iChip, 0x1e, 0x60); } } } else if (1 == wdi->count[i]) { tmp = tp28xx_byte_read(iChip, 0xa7); tmp |= 0x01; tp28xx_byte_write(iChip, 0xa7, tmp); #if (DEBUG) tmp = tp28xx_byte_read(iChip, 0x01); printk("status%02x ch%02x\r\n", tmp, i); tmp = tp28xx_byte_read(iChip, 0x03); printk("CVSTD%02x ch%02x\r\n", tmp, i); #endif } else if (wdi->count[i] < EQ_COUNT - 3) { if (SCAN_AUTO == wdi->scan[i]) { if (STD_TVI == wdi->std[i]) { tmp = tp28xx_byte_read(iChip, 0x01); if ((TP2802_PAL == wdi->mode[i]) || (TP2802_NTSC == wdi->mode[i])) { //nothing to do } else if (TP2802_QXGA18 == wdi->mode[i]) { if (0x60 == (tmp & 0x64)) { wdi->std[i] = STD_HDA; //no CVI QXGA18 tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } } else if (TP2802_QHD15 == wdi->mode[i] || TP2802_5M12 == wdi->mode[i]) { if (0x60 == (tmp & 0x64)) { wdi->std[i] = STD_HDA; //no CVI QHD15/5M20/5M12.5 tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); } } else if (TP2802_QHD25 == wdi->mode[i] || TP2802_QHD30 == wdi->mode[i] || TP2802_8M12 == wdi->mode[i] || TP2802_8M15 == wdi->mode[i] || TP2802_5M20 == wdi->mode[i]) { agc = tp28xx_byte_read(iChip, 0x10); tp28xx_byte_write(iChip, 0x10, 0x00); tp28xx_byte_write(iChip, 0x2f, 0x0f); rx1 = tp28xx_byte_read(iChip, 0x04); tp28xx_byte_write(iChip, 0x10, agc); if (rx1 > 0x30) wdi->std[i] = STD_HDA; else if (0x60 == (tmp & 0x64)) wdi->std[i] = STD_HDC; #if (DEBUG) printk("RX1=%02x standard to %02x ch%02x\r\n", rx1, wdi->std[i], i); #endif if (STD_TVI != wdi->std[i]) tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); else if (TP2802_8M12 == wdi->mode[i] || TP2802_8M15 == wdi->mode[i]) tp28xx_byte_write(iChip, 0x20, 0x50); //restore TVI clamping } else if (0x60 == (tmp & 0x64)) { rx2 = tp28xx_byte_read(iChip, 0x94); //capture line7 to match 3M/4M RT if (HDC_enable) { if (0xff == rx2) wdi->std[i] = STD_HDC; else if (0x00 == rx2) wdi->std[i] = STD_HDC_DEFAULT; else wdi->std[i] = STD_HDA; } else { wdi->std[i] = STD_HDA; } if (STD_TVI != wdi->std[i]) { tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); #if (DEBUG) printk("RX2=%02x standard to %02x ch%02x\r\n", rx2, wdi->std[i], i); #endif } } } } } else if (wdi->count[i] < EQ_COUNT) { } else if (wdi->count[i] == EQ_COUNT) { gain = tp28xx_read_egain(iChip); if (STD_TVI != wdi->std[i]) tp28xx_byte_write(iChip, 0x07, 0x80 | (gain >> 2)); // manual mode } else if (wdi->count[i] == EQ_COUNT + 1) { if (SCAN_AUTO == wdi->scan[i]) { if (HDC_enable) { if (STD_HDC_DEFAULT == wdi->std[i]) { tp28xx_byte_write(iChip, 0x2f, 0x0c); tmp = tp28xx_byte_read(iChip, 0x04); status = tp28xx_byte_read(iChip, 0x01); //if (0x10 == (0x11 & status) && (tmp < 0x18 || tmp > 0xf0)) if (0x10 == (0x11 & status)) //if ((tmp < 0x18 || tmp > 0xf0)) { wdi->std[i] = STD_HDC; } else { wdi->std[i] = STD_HDA; } tp2802_set_video_mode(iChip, wdi->mode[i], i, wdi->std[i]); #if (DEBUG) printk("reg01=%02x reg04@2f=0c %02x std%02x ch%02x\r\n", status, tmp, wdi->std[i], i); #endif } } } } else { if (SCAN_AUTO == wdi->scan[i]) { /* if (wdi->mode[i] < TP2802_3M18) { tmp = tp28xx_byte_read(iChip, 0x03); // tmp &= 0x07; if (tmp != (wdi->mode[i]&0x07) && tmp < TP2802_SD) { #if (DEBUG) printk("correct %02x from %02x ch%02x\r\n", tmp, wdi->mode[i], i); #endif wdi->force[i] = 1; } } */ } } } } } //do_gettimeofday(&end); //interval = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec); //printk("WDT elapsed time %d.%dms\n", interval/1000, interval%1000); up(&watchdog_lock); /* sleep 0.5 seconds */ schedule_timeout_interruptible(msecs_to_jiffies(1000) + 1); } set_current_state(TASK_RUNNING); printk("TP2802_watchdog_deamon: exit!\n"); return 0; } /****************************************************************************** * * TP2825_watchdog_init() * ******************************************************************************/ int __init TP2802_watchdog_init(void) { struct task_struct *p_dog; int i, j; watchdog_state = WATCHDOG_RUNNING; memset(&watchdog_info, 0, sizeof(watchdog_info)); for (i = 0; i < MAX_CHIPS; i++) { watchdog_info[i].addr = tp2802_i2c_addr[i]; for (j = 0; j < CHANNELS_PER_CHIP; j++) { watchdog_info[i].count[j] = 0; watchdog_info[i].force[j] = 0; //watchdog_info[i].loss[j] = 1; watchdog_info[i].mode[j] = INVALID_FORMAT; watchdog_info[i].scan[j] = SCAN_AUTO; watchdog_info[i].state[j] = VIDEO_UNPLUG; watchdog_info[i].std[j] = STD_TVI; } } p_dog = kthread_create(TP2802_watchdog_deamon, NULL, "WatchDog"); if (IS_ERR(p_dog)) { printk("TP2802_watchdog_init: create watchdog_deamon failed!\n"); return -1; } wake_up_process(p_dog); task_watchdog_deamon = p_dog; printk("TP2802_watchdog_init: done!\n"); return 0; } /****************************************************************************** * * TP2825_watchdog_exit() * ******************************************************************************/ void TP2802_watchdog_exit(void) { struct task_struct *p_dog = task_watchdog_deamon; watchdog_state = WATCHDOG_EXIT; if (p_dog == NULL) return; wake_up_process(p_dog); kthread_stop(p_dog); yield(); task_watchdog_deamon = NULL; printk("TP2802_watchdog_exit: done!\n"); } /****************************************************************************** * V4L2 API of TP2825 ******************************************************************************/ static inline struct tp2825_v4l2_dev *to_tp2825_dev(struct v4l2_subdev *sd) { return container_of(sd, struct tp2825_v4l2_dev, sd); } static int tp2825_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *fi) { struct tp2825_v4l2_dev *sensor = to_tp2825_dev(sd); fi->interval = sensor->frame_interval; return 0; } static int tp2825_s_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *fi) { struct tp2825_v4l2_dev *sensor = to_tp2825_dev(sd); if (fi->pad != 0) return -EINVAL; if (sensor->streaming) return -EBUSY; dev_dbg(&sensor->i2c_client->dev, "Set FR %d-%d\n", fi->interval.numerator, fi->interval.denominator); // sensor->frame_interval = fi->interval; return 0; } static int tp2825_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad != 0) return -EINVAL; code->code = DEFAULT_V4L2_CODE; return 0; } static int tp2825_s_stream(struct v4l2_subdev *sd, int enable) { struct tp2825_v4l2_dev *sensor = to_tp2825_dev(sd); dev_dbg(&sensor->i2c_client->dev, "Streaming %s\n", enable ? "On" : "Off"); sensor->streaming = enable; if (test) { if (enable) { dev_info(&sensor->i2c_client->dev, "Enter test mode\n"); tp28xx_byte_write(0, 0x2A, 0x3C); } else { dev_info(&sensor->i2c_client->dev, "Exit test mode\n"); tp28xx_byte_write(0, 0x2A, 0x30); } } return 0; } static int tp2825_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct tp2825_v4l2_dev *sensor = to_tp2825_dev(sd); if (format->pad != 0) return -EINVAL; format->format = sensor->fmt; return 0; } static int tp2825_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct tp2825_v4l2_dev *sensor = to_tp2825_dev(sd); struct v4l2_mbus_framefmt *fmt = &format->format; if (format->pad != 0) return -EINVAL; if (sensor->streaming) return -EBUSY; dev_dbg(&sensor->i2c_client->dev, "Set format: code %#x, colorspace %#x, %d x %d\n", fmt->code, fmt->colorspace, fmt->width, fmt->height); return 0; } static const struct v4l2_subdev_core_ops tp2825_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops tp2825_video_ops = { .g_frame_interval = tp2825_g_frame_interval, .s_frame_interval = tp2825_s_frame_interval, .s_stream = tp2825_s_stream, }; static const struct v4l2_subdev_pad_ops tp2825_pad_ops = { .enum_mbus_code = tp2825_enum_mbus_code, .get_fmt = tp2825_get_fmt, .set_fmt = tp2825_set_fmt, }; static const struct v4l2_subdev_ops tp2825_subdev_ops = { .core = &tp2825_core_ops, .video = &tp2825_video_ops, .pad = &tp2825_pad_ops, }; static int tp2825_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct fwnode_handle *endpoint = NULL; struct tp2825_v4l2_dev *sensor = NULL; struct v4l2_mbus_framefmt *fmt = NULL; int ret = 0; sensor = devm_kzalloc(dev, sizeof(struct tp2825_v4l2_dev), GFP_KERNEL); if (!sensor) return -ENOMEM; /* request optional power down pin */ sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); if (IS_ERR_OR_NULL(sensor->pwdn_gpio)) dev_dbg(dev, "Failed to parse powerdown-gpio\n"); else gpiod_set_value_cansleep(sensor->pwdn_gpio, 0); tp28xx_client0 = client; sensor->i2c_client = client; ret = tp2802_module_init(); if (ret) return -EINVAL; fmt = &sensor->fmt; fmt->code = DEFAULT_V4L2_CODE; fmt->colorspace = V4L2_COLORSPACE_SRGB; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); fmt->width = DEFAULT_WIDTH; fmt->height = DEFAULT_HEIGHT; fmt->field = V4L2_FIELD_NONE; sensor->frame_interval.numerator = 1; sensor->frame_interval.denominator = DEFAULT_FRAMERATE; sensor->cur_fr = DEFAULT_FRAMERATE; endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); if (!endpoint) { dev_err(dev, "endpoint node not found\n"); return -EINVAL; } ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep); fwnode_handle_put(endpoint); if (ret) { dev_err(dev, "Could not parse endpoint\n"); return ret; } if (sensor->ep.bus_type != V4L2_MBUS_BT656) { dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type); return -EINVAL; } v4l2_i2c_subdev_init(&sensor->sd, client, &tp2825_subdev_ops); sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); if (ret) return ret; ret = v4l2_async_register_subdev_sensor_common(&sensor->sd); if (ret) return ret; sensor->attrs.attrs = tp2825_attr; ret = sysfs_create_group(&dev->kobj, &sensor->attrs); if (ret) return ret; dev_info(dev, "Register %s to V4L2 device\n", DRV_NAME); return 0; } static int tp2825_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct tp2825_v4l2_dev *sensor = to_tp2825_dev(sd); tp2802_module_exit(); v4l2_async_unregister_subdev(&sensor->sd); media_entity_cleanup(&sensor->sd.entity); return 0; } static const struct i2c_device_id tp2825_id[] = { {DRV_NAME, 0}, {}, }; MODULE_DEVICE_TABLE(i2c, tp2825_id); static const struct of_device_id tp2825_dt_ids[] = { { .compatible = "techpoint,tp2825" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tp2825_dt_ids); static struct i2c_driver tp2825_i2c_driver = { .driver = { .name = DRV_NAME, .of_match_table = tp2825_dt_ids, }, .id_table = tp2825_id, .probe_new = tp2825_probe, .remove = tp2825_remove, }; module_i2c_driver(tp2825_i2c_driver); MODULE_DESCRIPTION("TechPoint TP2825B Linux Module"); MODULE_LICENSE("GPL");