/* * saa7191 - Philips SAA7191 video decoder driver * * Copyright (C) 2003 Ladislav Michl * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "saa7191.h" #define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO) struct saa7191 { struct i2c_client *client; unsigned char reg[25]; unsigned char norm; unsigned char input; unsigned char bright; unsigned char contrast; unsigned char hue; unsigned char sat; }; static struct i2c_driver i2c_driver_saa7191; static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) { static const unsigned char initseq[] = { 0, 0x50, /* SAA7191_REG_IDEL */ 0x30, /* SAA7191_REG_HSYB */ 0x00, /* SAA7191_REG_HSYS */ 0xe8, /* SAA7191_REG_HCLB */ 0xb6, /* SAA7191_REG_HCLS */ 0xf4, /* SAA7191_REG_HPHI */ 0x01, /* SAA7191_REG_LUMA */ 0x00, /* SAA7191_REG_HUEC */ 0xf8, /* SAA7191_REG_CKTQ */ 0xf8, /* SAA7191_REG_CKTS */ 0x90, /* SAA7191_REG_PLSE */ 0x90, /* SAA7191_REG_SESE */ 0x00, /* SAA7191_REG_GAIN */ 0x8c, /* SAA7191_REG_STDC */ 0x78, /* SAA7191_REG_IOCK */ 0x99, /* SAA7191_REG_CTL3 */ 0x00, /* SAA7191_REG_CTL4 */ 0x2c, /* SAA7191_REG_CHCV */ 0x00, /* unused */ 0x00, /* unused */ 0x34, /* SAA7191_REG_HS6B */ 0x0a, /* SAA7191_REG_HS6S */ 0xf4, /* SAA7191_REG_HC6B */ 0xce, /* SAA7191_REG_HC6S */ 0xf4, /* SAA7191_REG_HP6I */ }; int err = 0; struct saa7191 *decoder; struct i2c_client *client; client = kmalloc(sizeof(*client), GFP_KERNEL); if (!client) return -ENOMEM; decoder = kmalloc(sizeof(*decoder), GFP_KERNEL); if (!decoder) { err = -ENOMEM; goto out_free_client; } client->data = decoder; client->adapter = adap; client->addr = addr; client->driver = &i2c_driver_saa7191; strcpy(client->name, "saa7191 client"); decoder->client = client; err = i2c_attach_client(client); if (err) goto out_free_decoder; decoder->norm = VIDEO_DECODER_PAL | VIDEO_MODE_NTSC | VIDEO_DECODER_AUTO; decoder->input = 0; /* Registers are 8bit wide and we are storing shifted values */ decoder->bright = 128; decoder->contrast = 128; decoder->hue = 128; decoder->sat = 128; memcpy(decoder->reg, initseq, sizeof(initseq)); err = i2c_master_send(client, initseq, sizeof(initseq)); if (err) printk(KERN_INFO "saa7191 initialization failed (%d)\n", err); MOD_INC_USE_COUNT; return 0; out_free_decoder: kfree(decoder); out_free_client: kfree(client); return err; } static int saa7191_probe(struct i2c_adapter *adap) { /* Always connected to VINO */ if (adap->id == VINO_ADAPTER) return saa7191_attach(adap, SAA7191_ADDR, 0); /* Feel free to add probe here :-) */ return -ENODEV; } static int saa7191_detach(struct i2c_client *client) { struct saa7191 *decoder = client->data; i2c_detach_client(client); kfree(decoder); kfree(client); MOD_DEC_USE_COUNT; return 0; } static unsigned char saa7191_read(struct i2c_client *client, unsigned char command) { return ((struct saa7191 *)client->data)->reg[command]; } static int saa7191_write(struct i2c_client *client, unsigned char command, unsigned char value) { ((struct saa7191 *)client->data)->reg[command] = value; return i2c_smbus_write_byte_data(client, command, value); } static int vino_set_input(struct i2c_client *client, int val) { unsigned char luma = saa7191_read(client, SAA7191_REG_LUMA); unsigned char iock = saa7191_read(client, SAA7191_REG_IOCK); switch (val) { case 0: /* Set Composite input */ iock &= ~0x03; /* Chrominance trap active */ luma |= ~SAA7191_LUMA_BYPS; break; case 1: /* Set S-Video input */ iock |= 2; /* Chrominance trap bypassed */ luma |= SAA7191_LUMA_BYPS; break; default: return -EINVAL; } saa7191_write(client, SAA7191_REG_LUMA, luma); saa7191_write(client, SAA7191_REG_IOCK, iock); return 0; } static int saa7191_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct saa7191 *decoder = client->data; switch (cmd) { case DECODER_GET_CAPABILITIES: { struct video_decoder_capability *cap = arg; cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC | VIDEO_DECODER_AUTO; cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1; cap->outputs = 1; break; } case DECODER_GET_STATUS: { int *iarg = arg; int status; int res = 0; status = i2c_smbus_read_byte_data(client, SAA7191_REG_STATUS); if ((status & SAA7191_STATUS_HLCK) == 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_AUTO: default: if (status & SAA7191_STATUS_FIDT) res |= DECODER_STATUS_NTSC; else res |= DECODER_STATUS_PAL; if (status & SAA7191_STATUS_CODE) res |= DECODER_STATUS_COLOR; break; } *iarg = res; break; } case DECODER_SET_NORM: { int *iarg = arg; switch (*iarg) { case VIDEO_MODE_NTSC: break; case VIDEO_MODE_PAL: break; default: return -EINVAL; } decoder->norm = *iarg; break; } case DECODER_SET_INPUT: { int *iarg = arg; switch (client->adapter->id) { case VINO_ADAPTER: return vino_set_input(client, *iarg); default: if (*iarg != 0) return -EINVAL; } break; } case DECODER_SET_OUTPUT: { int *iarg = arg; /* not much choice of outputs */ if (*iarg != 0) return -EINVAL; break; } case DECODER_ENABLE_OUTPUT: { /* Always enabled */ break; } case DECODER_SET_PICTURE: { struct video_picture *pic = arg; unsigned val; #if 0 /* TODO */ val = pic->brightness >> 8; if (decoder->bright != val) { decoder->bright = val; i2c_smbus_write_byte_data(client, XXX, val); } val = pic->contrast >> 8; if (decoder->contrast != val) { decoder->contrast = val; i2c_smbus_write_byte_data(client, XXX, val); } val = pic->colour >> 8; if (decoder->sat != val) { decoder->sat = val; i2c_smbus_write_byte_data(client, XXX, val); } #endif val = (pic->hue >> 8) - 0x80; if (decoder->hue != val) { decoder->hue = val; i2c_smbus_write_byte_data(client, SAA7191_REG_HUEC, val); } break; } default: return -EINVAL; } return 0; } static struct i2c_driver i2c_driver_saa7191 = { .name = "saa7191", .id = I2C_DRIVERID_SAA7191, .flags = I2C_DF_NOTIFY, .attach_adapter = saa7191_probe, .detach_client = saa7191_detach, .command = saa7191_command }; static int saa7191_init(void) { return i2c_add_driver(&i2c_driver_saa7191); } static void saa7191_exit(void) { i2c_del_driver(&i2c_driver_saa7191); } module_init(saa7191_init); module_exit(saa7191_exit); MODULE_DESCRIPTION("Philips SAA7191 video decoder driver"); MODULE_AUTHOR("Ladislav Michl "); MODULE_LICENSE("GPL");