static int saa7114_write_block (struct i2c_client *client, const u8 *data, unsigned int len) { int ret = -1; u8 reg; /* the saa7114 has an autoincrement function, use it if * the adapter understands raw I2C */ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { /* do raw I2C, not smbus compatible */ /*struct saa7114 *decoder = i2c_get_clientdata(client);*/ struct i2c_msg msg; u8 block_data[32]; msg.addr = client->addr; msg.flags = client->flags; while (len >= 2) { msg.buf = (char *) block_data; msg.len = 0; block_data[msg.len++] = reg = data[0]; do { block_data[msg.len++] = /*decoder->reg[reg++] =*/ data[1]; len -= 2; data += 2; } while (len >= 2 && data[0] == reg && msg.len < 32); if ((ret = i2c_transfer(client->adapter, &msg, 1)) < 0) break; } } else { /* do some slow I2C emulation kind of thing */ while (len >= 2) { reg = *data++; if ((ret = saa7114_write(client, reg, *data++)) < 0) break; len -= 2; } } return ret; }
static int saa7114_write_block (struct i2c_client *client, const u8 *data, unsigned int len) { int ret = -1; u8 reg; /* the saa7114 has an autoincrement function, use it if * the adapter understands raw I2C */ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { /* do raw I2C, not smbus compatible */ u8 block_data[32]; int block_len; while (len >= 2) { block_len = 0; block_data[block_len++] = reg = data[0]; do { block_data[block_len++] = data[1]; reg++; len -= 2; data += 2; } while (len >= 2 && data[0] == reg && block_len < 32); if ((ret = i2c_master_send(client, block_data, block_len)) < 0) break; } } else { /* do some slow I2C emulation kind of thing */ while (len >= 2) { reg = *data++; if ((ret = saa7114_write(client, reg, *data++)) < 0) break; len -= 2; } } return ret; }
static int saa7114_command (struct i2c_client *client, unsigned int cmd, void *arg) { struct saa7114 *decoder = i2c_get_clientdata(client); switch (cmd) { case 0: //dprintk(1, KERN_INFO "%s: writing init\n", I2C_NAME(client)); //saa7114_write_block(client, init, sizeof(init)); break; case DECODER_DUMP: { int i; dprintk(1, KERN_INFO "%s: decoder dump\n", I2C_NAME(client)); for (i = 0; i < 32; i += 16) { int j; printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i); for (j = 0; j < 16; ++j) { printk(" %02x", saa7114_read(client, i + j)); } printk("\n"); } } break; case DECODER_GET_CAPABILITIES: { struct video_decoder_capability *cap = arg; dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n", I2C_NAME(client)); cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC | VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR; cap->inputs = 8; cap->outputs = 1; } break; case DECODER_GET_STATUS: { int *iarg = arg; int status; int res; status = saa7114_read(client, 0x1f); dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client), status); res = 0; if ((status & (1 << 6)) == 0) { res |= DECODER_STATUS_GOOD; } switch (decoder->norm) { case VIDEO_MODE_NTSC: res |= DECODER_STATUS_NTSC; break; case VIDEO_MODE_PAL: res |= DECODER_STATUS_PAL; break; case VIDEO_MODE_SECAM: res |= DECODER_STATUS_SECAM; break; default: case VIDEO_MODE_AUTO: if ((status & (1 << 5)) != 0) { res |= DECODER_STATUS_NTSC; } else { res |= DECODER_STATUS_PAL; } break; } if ((status & (1 << 0)) != 0) { res |= DECODER_STATUS_COLOR; } *iarg = res; } break; case DECODER_SET_NORM: { int *iarg = arg; short int hoff = 0, voff = 0, w = 0, h = 0; dprintk(1, KERN_DEBUG "%s: decoder set norm ", I2C_NAME(client)); switch (*iarg) { case VIDEO_MODE_NTSC: dprintk(1, "NTSC\n"); decoder->reg[REG_ADDR(0x06)] = SAA_7114_NTSC_HSYNC_START; decoder->reg[REG_ADDR(0x07)] = SAA_7114_NTSC_HSYNC_STOP; decoder->reg[REG_ADDR(0x08)] = decoder->playback ? 0x7c : 0xb8; // PLL free when playback, PLL close when capture decoder->reg[REG_ADDR(0x0e)] = 0x85; decoder->reg[REG_ADDR(0x0f)] = 0x24; hoff = SAA_7114_NTSC_HOFFSET; voff = SAA_7114_NTSC_VOFFSET; w = SAA_7114_NTSC_WIDTH; h = SAA_7114_NTSC_HEIGHT; break; case VIDEO_MODE_PAL: dprintk(1, "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: dprintk(1, " 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; dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n", I2C_NAME(client), *iarg); if (*iarg < 0 || *iarg > 7) { return -EINVAL; } if (decoder->input != *iarg) { dprintk(1, KERN_DEBUG "%s: now setting %s input\n", I2C_NAME(client), *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; dprintk(1, KERN_DEBUG "%s: decoder set output\n", I2C_NAME(client)); /* not much choice of outputs */ if (*iarg != 0) { return -EINVAL; } } break; case DECODER_ENABLE_OUTPUT: { int *iarg = arg; int enable = (*iarg != 0); dprintk(1, KERN_DEBUG "%s: decoder %s output\n", I2C_NAME(client), 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; dprintk(1, KERN_DEBUG "%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n", I2C_NAME(client), 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); }