saa7114.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,074 行 · 第 1/2 页
C
1,074 行
case VIDEO_MODE_PAL: v4l_dbg(1, debug, client, "PAL\n"); decoder->reg[REG_ADDR(0x06)] = SAA_7114_PAL_HSYNC_START; decoder->reg[REG_ADDR(0x07)] = SAA_7114_PAL_HSYNC_STOP; decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8; // PLL free when playback, PLL close when capture decoder->reg[REG_ADDR(0x0e)] = 0x81; decoder->reg[REG_ADDR(0x0f)] = 0x24; hoff = SAA_7114_PAL_HOFFSET; voff = SAA_7114_PAL_VOFFSET; w = SAA_7114_PAL_WIDTH; h = SAA_7114_PAL_HEIGHT; break; default: v4l_dbg(1, debug, client, "Unknown video mode\n"); return -EINVAL; } decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff); // hoffset low decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f; // hoffset high decoder->reg[REG_ADDR(0x96)] = LOBYTE(w); // width low decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f; // width high decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff); // voffset low decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f; // voffset high decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2); // height low decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f; // height high decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w); // out width low decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f; // out width high decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h); // out height low decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f; // out height high decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff); // hoffset low decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f; // hoffset high decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w); // width low decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f; // width high decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff); // voffset low decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f; // voffset high decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2); // height low decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f; // height high decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w); // out width low decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f; // out width high decoder->reg[REG_ADDR(0xce)] = LOBYTE(h); // out height low decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f; // out height high saa7114_write(client, 0x80, 0x06); // i-port and scaler back end clock selection, task A&B off saa7114_write(client, 0x88, 0xd8); // sw reset scaler saa7114_write(client, 0x88, 0xf8); // sw reset scaler release saa7114_write_block(client, decoder->reg + (0x06 << 1), 3 << 1); saa7114_write_block(client, decoder->reg + (0x0e << 1), 2 << 1); saa7114_write_block(client, decoder->reg + (0x5a << 1), 2 << 1); saa7114_write_block(client, decoder->reg + (0x94 << 1), (0x9f + 1 - 0x94) << 1); saa7114_write_block(client, decoder->reg + (0xc4 << 1), (0xcf + 1 - 0xc4) << 1); saa7114_write(client, 0x88, 0xd8); // sw reset scaler saa7114_write(client, 0x88, 0xf8); // sw reset scaler release saa7114_write(client, 0x80, 0x36); // i-port and scaler back end clock selection decoder->norm = *iarg; break; } case DECODER_SET_INPUT: { int *iarg = arg; v4l_dbg(1, debug, client, "set input (%d)\n", *iarg); if (*iarg < 0 || *iarg > 7) { return -EINVAL; } if (decoder->input != *iarg) { v4l_dbg(1, debug, client, "now setting %s input\n", *iarg >= 6 ? "S-Video" : "Composite"); decoder->input = *iarg; /* select mode */ decoder->reg[REG_ADDR(0x02)] = (decoder-> reg[REG_ADDR(0x02)] & 0xf0) | (decoder-> input < 6 ? 0x0 : 0x9); saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]); /* bypass chrominance trap for modes 6..9 */ decoder->reg[REG_ADDR(0x09)] = (decoder-> reg[REG_ADDR(0x09)] & 0x7f) | (decoder-> input < 6 ? 0x0 : 0x80); saa7114_write(client, 0x09, decoder->reg[REG_ADDR(0x09)]); decoder->reg[REG_ADDR(0x0e)] = decoder->input < 6 ? decoder-> reg[REG_ADDR(0x0e)] | 1 : decoder-> reg[REG_ADDR(0x0e)] & ~1; saa7114_write(client, 0x0e, decoder->reg[REG_ADDR(0x0e)]); } break; } case DECODER_SET_OUTPUT: { int *iarg = arg; v4l_dbg(1, debug, client, "set output\n"); /* not much choice of outputs */ if (*iarg != 0) { return -EINVAL; } break; } case DECODER_ENABLE_OUTPUT: { int *iarg = arg; int enable = (*iarg != 0); v4l_dbg(1, debug, client, "%s output\n", enable ? "enable" : "disable"); decoder->playback = !enable; if (decoder->enable != enable) { decoder->enable = enable; /* RJ: If output should be disabled (for * playing videos), we also need a open PLL. * The input is set to 0 (where no input * source is connected), although this * is not necessary. * * If output should be enabled, we have to * reverse the above. */ if (decoder->enable) { decoder->reg[REG_ADDR(0x08)] = 0xb8; decoder->reg[REG_ADDR(0x12)] = 0xc9; decoder->reg[REG_ADDR(0x13)] = 0x80; decoder->reg[REG_ADDR(0x87)] = 0x01; } else { decoder->reg[REG_ADDR(0x08)] = 0x7c; decoder->reg[REG_ADDR(0x12)] = 0x00; decoder->reg[REG_ADDR(0x13)] = 0x00; decoder->reg[REG_ADDR(0x87)] = 0x00; } saa7114_write_block(client, decoder->reg + (0x12 << 1), 2 << 1); saa7114_write(client, 0x08, decoder->reg[REG_ADDR(0x08)]); saa7114_write(client, 0x87, decoder->reg[REG_ADDR(0x87)]); saa7114_write(client, 0x88, 0xd8); // sw reset scaler saa7114_write(client, 0x88, 0xf8); // sw reset scaler release saa7114_write(client, 0x80, 0x36); } break; } case DECODER_SET_PICTURE: { struct video_picture *pic = arg; v4l_dbg(1, debug, client, "decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n", pic->brightness, pic->contrast, pic->colour, pic->hue); if (decoder->bright != pic->brightness) { /* We want 0 to 255 we get 0-65535 */ decoder->bright = pic->brightness; saa7114_write(client, 0x0a, decoder->bright >> 8); } if (decoder->contrast != pic->contrast) { /* We want 0 to 127 we get 0-65535 */ decoder->contrast = pic->contrast; saa7114_write(client, 0x0b, decoder->contrast >> 9); } if (decoder->sat != pic->colour) { /* We want 0 to 127 we get 0-65535 */ decoder->sat = pic->colour; saa7114_write(client, 0x0c, decoder->sat >> 9); } if (decoder->hue != pic->hue) { /* We want -128 to 127 we get 0-65535 */ decoder->hue = pic->hue; saa7114_write(client, 0x0d, (decoder->hue - 32768) >> 8); } break; } default: return -EINVAL; } return 0;}/* ----------------------------------------------------------------------- */static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };I2C_CLIENT_INSMOD;static int saa7114_probe(struct i2c_client *client, const struct i2c_device_id *id){ int i, err[30]; short int hoff = SAA_7114_NTSC_HOFFSET; short int voff = SAA_7114_NTSC_VOFFSET; short int w = SAA_7114_NTSC_WIDTH; short int h = SAA_7114_NTSC_HEIGHT; struct saa7114 *decoder; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); decoder = kzalloc(sizeof(struct saa7114), GFP_KERNEL); if (decoder == NULL) return -ENOMEM; decoder->norm = VIDEO_MODE_NTSC; decoder->input = -1; decoder->enable = 1; decoder->bright = 32768; decoder->contrast = 32768; decoder->hue = 32768; decoder->sat = 32768; decoder->playback = 0; // initially capture mode useda i2c_set_clientdata(client, decoder); memcpy(decoder->reg, init, sizeof(init)); decoder->reg[REG_ADDR(0x94)] = LOBYTE(hoff); // hoffset low decoder->reg[REG_ADDR(0x95)] = HIBYTE(hoff) & 0x0f; // hoffset high decoder->reg[REG_ADDR(0x96)] = LOBYTE(w); // width low decoder->reg[REG_ADDR(0x97)] = HIBYTE(w) & 0x0f; // width high decoder->reg[REG_ADDR(0x98)] = LOBYTE(voff); // voffset low decoder->reg[REG_ADDR(0x99)] = HIBYTE(voff) & 0x0f; // voffset high decoder->reg[REG_ADDR(0x9a)] = LOBYTE(h + 2); // height low decoder->reg[REG_ADDR(0x9b)] = HIBYTE(h + 2) & 0x0f; // height high decoder->reg[REG_ADDR(0x9c)] = LOBYTE(w); // out width low decoder->reg[REG_ADDR(0x9d)] = HIBYTE(w) & 0x0f; // out width high decoder->reg[REG_ADDR(0x9e)] = LOBYTE(h); // out height low decoder->reg[REG_ADDR(0x9f)] = HIBYTE(h) & 0x0f; // out height high decoder->reg[REG_ADDR(0xc4)] = LOBYTE(hoff); // hoffset low decoder->reg[REG_ADDR(0xc5)] = HIBYTE(hoff) & 0x0f; // hoffset high decoder->reg[REG_ADDR(0xc6)] = LOBYTE(w); // width low decoder->reg[REG_ADDR(0xc7)] = HIBYTE(w) & 0x0f; // width high decoder->reg[REG_ADDR(0xc8)] = LOBYTE(voff); // voffset low decoder->reg[REG_ADDR(0xc9)] = HIBYTE(voff) & 0x0f; // voffset high decoder->reg[REG_ADDR(0xca)] = LOBYTE(h + 2); // height low decoder->reg[REG_ADDR(0xcb)] = HIBYTE(h + 2) & 0x0f; // height high decoder->reg[REG_ADDR(0xcc)] = LOBYTE(w); // out width low decoder->reg[REG_ADDR(0xcd)] = HIBYTE(w) & 0x0f; // out width high decoder->reg[REG_ADDR(0xce)] = LOBYTE(h); // out height low decoder->reg[REG_ADDR(0xcf)] = HIBYTE(h) & 0x0f; // out height high decoder->reg[REG_ADDR(0xb8)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xb9)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xba)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xbb)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xbc)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xbd)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xbe)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xbf)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xe8)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xe9)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xea)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xeb)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_CHROMA_OFFSET)); decoder->reg[REG_ADDR(0xec)] = LOBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xed)] = HIBYTE(LOWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xee)] = LOBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0xef)] = HIBYTE(HIWORD(SAA_7114_VERTICAL_LUMA_OFFSET)); decoder->reg[REG_ADDR(0x13)] = 0x80; // RTC0 on decoder->reg[REG_ADDR(0x87)] = 0x01; // I-Port decoder->reg[REG_ADDR(0x12)] = 0xc9; // RTS0 decoder->reg[REG_ADDR(0x02)] = 0xc0; // set composite1 input, aveasy decoder->reg[REG_ADDR(0x09)] = 0x00; // chrominance trap decoder->reg[REG_ADDR(0x0e)] |= 1; // combfilter on v4l_dbg(1, debug, client, "starting init\n"); err[0] = saa7114_write_block(client, decoder->reg + (0x20 << 1), 0x10 << 1); err[1] = saa7114_write_block(client, decoder->reg + (0x30 << 1), 0x10 << 1); err[2] = saa7114_write_block(client, decoder->reg + (0x63 << 1), (0x7f + 1 - 0x63) << 1); err[3] = saa7114_write_block(client, decoder->reg + (0x89 << 1), 6 << 1); err[4] = saa7114_write_block(client, decoder->reg + (0xb8 << 1), 8 << 1); err[5] = saa7114_write_block(client, decoder->reg + (0xe8 << 1), 8 << 1); for (i = 0; i <= 5; i++) { if (err[i] < 0) { v4l_dbg(1, debug, client, "init error %d at stage %d, leaving attach.\n", i, err[i]); kfree(decoder); return -EIO; } } for (i = 6; i < 8; i++) { v4l_dbg(1, debug, client, "reg[0x%02x] = 0x%02x (0x%02x)\n", i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } v4l_dbg(1, debug, client, "performing decoder reset sequence\n"); err[6] = saa7114_write(client, 0x80, 0x06); // i-port and scaler backend clock selection, task A&B off err[7] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler err[8] = saa7114_write(client, 0x88, 0xf8); // sw reset scaler release for (i = 6; i <= 8; i++) { if (err[i] < 0) { v4l_dbg(1, debug, client, "init error %d at stage %d, leaving attach.\n", i, err[i]); kfree(decoder); return -EIO; } } v4l_dbg(1, debug, client, "performing the rest of init\n"); err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]); err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1); // big seq err[11] = saa7114_write_block(client, decoder->reg + (0x40 << 1), (0x5f + 1 - 0x40) << 1); // slicer err[12] = saa7114_write_block(client, decoder->reg + (0x81 << 1), 2 << 1); // ? err[13] = saa7114_write_block(client, decoder->reg + (0x83 << 1), 5 << 1); // ? err[14] = saa7114_write_block(client, decoder->reg + (0x90 << 1), 4 << 1); // Task A err[15] = saa7114_write_block(client, decoder->reg + (0x94 << 1), 12 << 1); err[16] = saa7114_write_block(client, decoder->reg + (0xa0 << 1), 8 << 1); err[17] = saa7114_write_block(client, decoder->reg + (0xa8 << 1), 8 << 1); err[18] = saa7114_write_block(client, decoder->reg + (0xb0 << 1), 8 << 1); err[19] = saa7114_write_block(client, decoder->reg + (0xc0 << 1), 4 << 1); // Task B err[15] = saa7114_write_block(client, decoder->reg + (0xc4 << 1), 12 << 1); err[16] = saa7114_write_block(client, decoder->reg + (0xd0 << 1), 8 << 1); err[17] = saa7114_write_block(client, decoder->reg + (0xd8 << 1), 8 << 1); err[18] = saa7114_write_block(client, decoder->reg + (0xe0 << 1), 8 << 1); for (i = 9; i <= 18; i++) { if (err[i] < 0) { v4l_dbg(1, debug, client, "init error %d at stage %d, leaving attach.\n", i, err[i]); kfree(decoder); return -EIO; } } for (i = 6; i < 8; i++) { v4l_dbg(1, debug, client, "reg[0x%02x] = 0x%02x (0x%02x)\n", i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } for (i = 0x11; i <= 0x13; i++) { v4l_dbg(1, debug, client, "reg[0x%02x] = 0x%02x (0x%02x)\n", i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } v4l_dbg(1, debug, client, "setting video input\n"); err[19] = saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]); err[20] = saa7114_write(client, 0x09, decoder->reg[REG_ADDR(0x09)]); err[21] = saa7114_write(client, 0x0e, decoder->reg[REG_ADDR(0x0e)]); for (i = 19; i <= 21; i++) { if (err[i] < 0) { v4l_dbg(1, debug, client, "init error %d at stage %d, leaving attach.\n", i, err[i]); kfree(decoder); return -EIO; } } v4l_dbg(1, debug, client, "performing decoder reset sequence\n"); err[22] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler err[23] = saa7114_write(client, 0x88, 0xf8); // sw reset scaler release err[24] = saa7114_write(client, 0x80, 0x36); // i-port and scaler backend clock selection, task A&B off for (i = 22; i <= 24; i++) { if (err[i] < 0) { v4l_dbg(1, debug, client, "init error %d at stage %d, leaving attach.\n", i, err[i]); kfree(decoder); return -EIO; } } err[25] = saa7114_write(client, 0x06, init[REG_ADDR(0x06)]); err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]); err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]); v4l_dbg(1, debug, client, "chip version %x, decoder status 0x%02x\n", saa7114_read(client, 0x00) >> 4, saa7114_read(client, 0x1f)); v4l_dbg(1, debug, client, "power save control: 0x%02x, scaler status: 0x%02x\n", saa7114_read(client, 0x88), saa7114_read(client, 0x8f)); for (i = 0x94; i < 0x96; i++) { v4l_dbg(1, debug, client, "reg[0x%02x] = 0x%02x (0x%02x)\n", i, saa7114_read(client, i), decoder->reg[REG_ADDR(i)]); } //i = saa7114_write_block(client, init, sizeof(init)); return 0;}static int saa7114_remove(struct i2c_client *client){ kfree(i2c_get_clientdata(client)); return 0;}/* ----------------------------------------------------------------------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)static const struct i2c_device_id saa7114_id[] = { { "saa7114_old", 0 }, /* "saa7114" maps to the saa7115 driver */ { }};MODULE_DEVICE_TABLE(i2c, saa7114_id);#endifstatic struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "saa7114", .driverid = I2C_DRIVERID_SAA7114, .command = saa7114_command, .probe = saa7114_probe, .remove = saa7114_remove,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) .id_table = saa7114_id,#endif};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?