#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <machine/clock.h>
#include <dev/video/cxm/cxm.h>
#include <bus/iicbus/iiconf.h>
#include <bus/iicbus/iicbus.h>
#include "iicbb_if.h"
static const struct cxm_saa7115_command
saa7115_init = {
19,
{
{ 0x01, 1, { 0x08 } },
{ 0x03, 18, { 0x20, 0x90, 0x90, 0xeb, 0xe0, 0xb0, 0x40, 0x80,
0x44, 0x40, 0x00, 0x03, 0x2a, 0x06, 0x00, 0x9d,
0x80, 0x01 } },
{ 0x17, 7, { 0x99, 0x40, 0x80, 0x77, 0x42, 0xa9, 0x01 } },
{ 0x40, 20, { 0x40, 0x00, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd } },
{ 0x56, 4, { 0x00, 0x00, 0x00, 0x47 } },
{ 0x5c, 3, { 0x00, 0x1f, 0x35 } },
{ 0x80, 2, { 0x00, 0x01 } },
{ 0x83, 5, { 0x00, 0x20, 0x21, 0xc5, 0x01 } },
{ 0xc0, 4, { 0x00, 0x08, 0x00, 0x80 } },
{ 0x90, 4, { 0x80, 0x48, 0x00, 0x84 } },
{ 0xa0, 3, { 0x01, 0x00, 0x00 } },
{ 0xa4, 3, { 0x80, 0x40, 0x40 } },
{ 0xa8, 3, { 0x00, 0x02, 0x00 } },
{ 0xac, 3, { 0x00, 0x01, 0x00 } },
{ 0xb0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
{ 0xb8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
{ 0x38, 3, { 0x03, 0x10, 0x00 } },
{ 0xf1, 4, { 0x05, 0xd0, 0x35, 0x00 } },
{ 0xf6, 10, { 0x61, 0x0e, 0x60, 0x0e, 0x60, 0x0e, 0x00,
0x00, 0x00, 0x88 } }
}
};
static const struct cxm_saa7115_command
saa7115_mute = {
1,
{
{ 0x87, 1, { 0x00 } },
}
};
static const struct cxm_saa7115_command
saa7115_unmute = {
1,
{
{ 0x87, 1, { 0x01 } },
}
};
static const struct cxm_saa7115_command
saa7115_select_fm = {
1,
{
{ 0x88, 1, { 0x33 } }
}
};
static const struct cxm_saa7115_command
saa7115_select_line_in_composite = {
3,
{
{ 0x02, 1, { 0xc0 } },
{ 0x09, 1, { 0x40 } },
{ 0x88, 1, { 0x70 } }
}
};
static const struct cxm_saa7115_command
saa7115_select_line_in_svideo = {
3,
{
{ 0x02, 1, { 0xc8 } },
{ 0x09, 1, { 0x80 } },
{ 0x88, 1, { 0xf0 } }
}
};
static const struct cxm_saa7115_command
saa7115_select_tuner = {
3,
{
{ 0x02, 1, { 0xc4 } },
{ 0x09, 1, { 0x40 } },
{ 0x88, 1, { 0xb0 } }
}
};
static const struct cxm_saa7115_command
saa7115_audio_clock_44100_ntsc = {
2,
{
{ 0x30, 3, { 0xbc, 0xdf, 0x02 } },
{ 0x34, 3, { 0xf2, 0x00, 0x2d } }
}
};
static const struct cxm_saa7115_command
saa7115_audio_clock_44100_pal = {
2,
{
{ 0x30, 3, { 0x00, 0x72, 0x03 } },
{ 0x34, 3, { 0xf2, 0x00, 0x2d } }
}
};
static const struct cxm_saa7115_command
saa7115_audio_clock_48000_ntsc = {
2,
{
{ 0x30, 3, { 0xcd, 0x20, 0x03 } },
{ 0x34, 3, { 0xce, 0xfb, 0x30 } }
}
};
static const struct cxm_saa7115_command
saa7115_audio_clock_48000_pal = {
2,
{
{ 0x30, 3, { 0x00, 0xc0, 0x03 } },
{ 0x34, 3, { 0xce, 0xfb, 0x30 } }
}
};
static const struct cxm_saa7115_command
saa7115_scaler_vcd_ntsc_double_lines = {
13,
{
{ 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00,
0x60, 0x01, 0xf0, 0x00 } },
{ 0xd0, 3, { 0x02, 0x02, 0xaa } },
{ 0xd4, 3, { 0x80, 0x40, 0x40 } },
{ 0xd8, 3, { 0x18, 0x04, 0x00 } },
{ 0xdc, 3, { 0x0c, 0x02, 0x00 } },
{ 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
{ 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
{ 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00,
0xa0, 0x05, 0x0c, 0x00 } },
{ 0x15, 2, { 0x02, 0x12 } },
{ 0x54, 2, { 0x4d, 0x00 } },
{ 0x5a, 2, { 0x06, 0x83 } },
{ 0xf0, 1, { 0xad } },
{ 0xf5, 1, { 0xad } }
}
};
static const struct cxm_saa7115_command
saa7115_scaler_vcd_pal_double_lines = {
13,
{
{ 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01,
0x60, 0x01, 0x20, 0x01 } },
{ 0xd0, 3, { 0x02, 0x02, 0xaa } },
{ 0xd4, 3, { 0x80, 0x40, 0x40 } },
{ 0xd8, 3, { 0x18, 0x04, 0x00 } },
{ 0xdc, 3, { 0x0c, 0x02, 0x00 } },
{ 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
{ 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
{ 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00,
0xa0, 0x05, 0x11, 0x00 } },
{ 0x15, 2, { 0x37, 0x17 } },
{ 0x54, 2, { 0xdd, 0x4d } },
{ 0x5a, 2, { 0x03, 0x03 } },
{ 0xf0, 1, { 0xb0 } },
{ 0xf5, 1, { 0xb0 } }
}
};
static const struct cxm_saa7115_command
saa7115_scaler_svcd_ntsc = {
13,
{
{ 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00,
0xe0, 0x01, 0xf0, 0x00 } },
{ 0xd0, 3, { 0x01, 0x00, 0x00 } },
{ 0xd4, 3, { 0x80, 0x40, 0x40 } },
{ 0xd8, 3, { 0x00, 0x06, 0x00 } },
{ 0xdc, 3, { 0x00, 0x03, 0x00 } },
{ 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
{ 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
{ 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00,
0xa0, 0x05, 0x0c, 0x00 } },
{ 0x15, 2, { 0x02, 0x12 } },
{ 0x54, 2, { 0x4d, 0x00 } },
{ 0x5a, 2, { 0x06, 0x83 } },
{ 0xf0, 1, { 0xad } },
{ 0xf5, 1, { 0xad } }
}
};
static const struct cxm_saa7115_command
saa7115_scaler_svcd_pal = {
13,
{
{ 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01,
0xe0, 0x01, 0x20, 0x01 } },
{ 0xd0, 3, { 0x01, 0x00, 0x00 } },
{ 0xd4, 3, { 0x80, 0x40, 0x40 } },
{ 0xd8, 3, { 0x00, 0x06, 0x00 } },
{ 0xdc, 3, { 0x00, 0x03, 0x00 } },
{ 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
{ 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
{ 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00,
0xa0, 0x05, 0x11, 0x00 } },
{ 0x15, 2, { 0x37, 0x17 } },
{ 0x54, 2, { 0xdd, 0x4d } },
{ 0x5a, 2, { 0x03, 0x03 } },
{ 0xf0, 1, { 0xb0 } },
{ 0xf5, 1, { 0xb0 } }
}
};
static const struct cxm_saa7115_command
saa7115_scaler_dvd_ntsc = {
13,
{
{ 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00,
0xd0, 0x02, 0xf0, 0x00 } },
{ 0xd0, 3, { 0x01, 0x00, 0x00 } },
{ 0xd4, 3, { 0x80, 0x40, 0x40 } },
{ 0xd8, 3, { 0x00, 0x04, 0x00 } },
{ 0xdc, 3, { 0x00, 0x02, 0x00 } },
{ 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
{ 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
{ 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00,
0xa0, 0x05, 0x0c, 0x00 } },
{ 0x15, 2, { 0x02, 0x12 } },
{ 0x54, 2, { 0x4d, 0x00 } },
{ 0x5a, 2, { 0x06, 0x83 } },
{ 0xf0, 1, { 0xad } },
{ 0xf5, 1, { 0xad } }
}
};
static const struct cxm_saa7115_command
saa7115_scaler_dvd_pal = {
13,
{
{ 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01,
0xd0, 0x02, 0x20, 0x01 } },
{ 0xd0, 3, { 0x01, 0x00, 0x00 } },
{ 0xd4, 3, { 0x80, 0x40, 0x40 } },
{ 0xd8, 3, { 0x00, 0x04, 0x00 } },
{ 0xdc, 3, { 0x00, 0x02, 0x00 } },
{ 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
{ 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
{ 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00,
0xa0, 0x05, 0x11, 0x00 } },
{ 0x15, 2, { 0x37, 0x17 } },
{ 0x54, 2, { 0xdd, 0x4d } },
{ 0x5a, 2, { 0x03, 0x03 } },
{ 0xf0, 1, { 0xb0 } },
{ 0xf5, 1, { 0xb0 } }
}
};
static const struct cxm_saa7115_audio_clock
saa7115_audio_clock[] = {
{ 44100, 30, &saa7115_audio_clock_44100_ntsc },
{ 44100, 25, &saa7115_audio_clock_44100_pal },
{ 48000, 30, &saa7115_audio_clock_48000_ntsc },
{ 48000, 25, &saa7115_audio_clock_48000_pal }
};
static const struct cxm_saa7115_scaling
saa7115_scalings[] = {
{ 352, 480, 30, &saa7115_scaler_vcd_ntsc_double_lines },
{ 352, 576, 25, &saa7115_scaler_vcd_pal_double_lines },
{ 480, 480, 30, &saa7115_scaler_svcd_ntsc },
{ 480, 576, 25, &saa7115_scaler_svcd_pal },
{ 720, 480, 30, &saa7115_scaler_dvd_ntsc },
{ 720, 576, 25, &saa7115_scaler_dvd_pal }
};
static int
cxm_saa7115_reset(device_t iicbus, int i2c_addr)
{
unsigned char msg[2];
int sent;
msg[0] = 0x88;
msg[1] = 0x0b;
if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
return -1;
if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
|| sent != sizeof(msg))
goto fail;
iicbus_stop(iicbus);
msg[0] = 0x88;
msg[1] = 0x2b;
if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
return -1;
if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
|| sent != sizeof(msg))
goto fail;
iicbus_stop(iicbus);
return 0;
fail:
iicbus_stop(iicbus);
return -1;
}
static int
cxm_saa7115_read(device_t iicbus, int i2c_addr,
unsigned char addr, char *buf, int len)
{
unsigned char msg[1];
int received;
int sent;
msg[0] = addr;
if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
return -1;
if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
|| sent != sizeof(msg))
goto fail;
if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0)
goto fail;
if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0)
goto fail;
iicbus_stop(iicbus);
return received;
fail:
iicbus_stop(iicbus);
return -1;
}
static int
cxm_saa7115_write(device_t iicbus, int i2c_addr,
unsigned char addr, const char *buf, int len)
{
unsigned char msg[1];
int sent;
msg[0] = addr;
if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
return -1;
if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
|| sent != sizeof(msg))
goto fail;
if (iicbus_write(iicbus, buf, len, &sent, CXM_I2C_TIMEOUT) != 0)
goto fail;
iicbus_stop(iicbus);
return sent;
fail:
iicbus_stop(iicbus);
return -1;
}
int
cxm_saa7115_init(struct cxm_softc *sc)
{
char name[5];
unsigned char id[1];
unsigned char rev;
unsigned int i;
unsigned int nsettings;
const struct cxm_saa7115_setting *settings;
if (cxm_saa7115_reset (sc->iicbus, CXM_I2C_SAA7115) < 0)
return -1;
name[4] = '\0';
for (i = 0; i < 4; i++) {
id[0] = 2 + i;
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x00,
id, sizeof(id)) != sizeof(id))
return -1;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x00,
id, sizeof(id)) != sizeof(id))
return -1;
name[i] = '0' + (id[0] & 0x0f);
rev = id[0] >> 4;
}
nsettings = 0;
settings = NULL;
if (strcmp(name, "7115") == 0) {
nsettings = saa7115_init.nsettings;
settings = saa7115_init.settings;
} else {
device_printf(sc->dev, "unknown video decoder SAA%s\n", name);
return -1;
}
for (i = 0; i < nsettings; i++)
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
settings[i].addr,
settings[i].values, settings[i].nvalues)
!= settings[i].nvalues)
return -1;
if (cxm_saa7115_select_source(sc, cxm_tuner_source) < 0)
return -1;
device_printf(sc->dev, "SAA%s rev %u video decoder\n",
name, (unsigned int)rev);
return 0;
}
int
cxm_saa7115_mute(struct cxm_softc *sc)
{
unsigned int i;
unsigned int nsettings;
const struct cxm_saa7115_setting *settings;
nsettings = saa7115_mute.nsettings;
settings = saa7115_mute.settings;
for (i = 0; i < nsettings; i++)
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
settings[i].addr,
settings[i].values, settings[i].nvalues)
!= settings[i].nvalues)
return -1;
return 0;
}
int
cxm_saa7115_unmute(struct cxm_softc *sc)
{
unsigned int i;
unsigned int nsettings;
const struct cxm_saa7115_setting *settings;
nsettings = saa7115_unmute.nsettings;
settings = saa7115_unmute.settings;
for (i = 0; i < nsettings; i++)
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
settings[i].addr,
settings[i].values, settings[i].nvalues)
!= settings[i].nvalues)
return -1;
return 0;
}
int
cxm_saa7115_select_source(struct cxm_softc *sc, enum cxm_source source)
{
unsigned int i;
unsigned int nsettings;
const struct cxm_saa7115_setting *settings;
switch (source) {
case cxm_fm_source:
nsettings = saa7115_select_fm.nsettings;
settings = saa7115_select_fm.settings;
break;
case cxm_line_in_source_composite:
nsettings = saa7115_select_line_in_composite.nsettings;
settings = saa7115_select_line_in_composite.settings;
break;
case cxm_line_in_source_svideo:
nsettings = saa7115_select_line_in_svideo.nsettings;
settings = saa7115_select_line_in_svideo.settings;
break;
case cxm_tuner_source:
nsettings = saa7115_select_tuner.nsettings;
settings = saa7115_select_tuner.settings;
break;
default:
return -1;
}
for (i = 0; i < nsettings; i++)
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
settings[i].addr,
settings[i].values, settings[i].nvalues)
!= settings[i].nvalues)
return -1;
return 0;
}
int
cxm_saa7115_configure(struct cxm_softc *sc,
unsigned int width, unsigned int height,
unsigned int fps, unsigned int audio_sample_rate)
{
unsigned char power[1];
unsigned char task[1];
unsigned int i;
unsigned int nsettings;
const struct cxm_saa7115_setting *settings;
for (i = 0; NUM_ELEMENTS(saa7115_scalings); i++)
if (saa7115_scalings[i].width == width
&& saa7115_scalings[i].height == height
&& saa7115_scalings[i].fps == fps)
break;
if (i >= NUM_ELEMENTS(saa7115_scalings))
return -1;
nsettings = saa7115_scalings[i].scaling->nsettings;
settings = saa7115_scalings[i].scaling->settings;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x88,
power, sizeof(power)) != sizeof(power))
return -1;
power[0] &= ~0x20;
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x88,
power, sizeof(power)) != sizeof(power))
return -1;
for (i = 0; i < nsettings; i++)
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
settings[i].addr,
settings[i].values, settings[i].nvalues)
!= settings[i].nvalues)
return -1;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x80,
task, sizeof(task)) != sizeof(task))
return -1;
task[0] |= 0x30;
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x80,
task, sizeof(task)) != sizeof(task))
return -1;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x88,
power, sizeof(power)) != sizeof(power))
return -1;
power[0] |= 0x20;
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x88,
power, sizeof(power)) != sizeof(power))
return -1;
for (i = 0; NUM_ELEMENTS(saa7115_audio_clock); i++)
if (saa7115_audio_clock[i].sample_rate == audio_sample_rate
&& saa7115_audio_clock[i].fps == fps)
break;
if (i >= NUM_ELEMENTS(saa7115_audio_clock))
return -1;
nsettings = saa7115_audio_clock[i].clock->nsettings;
settings = saa7115_audio_clock[i].clock->settings;
for (i = 0; i < nsettings; i++)
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
settings[i].addr,
settings[i].values, settings[i].nvalues)
!= settings[i].nvalues)
return -1;
return 0;
}
enum cxm_source_format
cxm_saa7115_detected_format(struct cxm_softc *sc)
{
unsigned char status[2];
enum cxm_source_format source_format;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1e,
status, sizeof(status)) != sizeof(status))
return cxm_unknown_source_format;
if (!(status[1] & 0x01)) {
device_printf(sc->dev, "video decoder isn't locked\n");
return cxm_unknown_source_format;
}
source_format = cxm_unknown_source_format;
if (!(status[1] & 0x20)) {
switch (status[0] & 0x03) {
case 0:
source_format = cxm_bw_50hz_source_format;
break;
case 1:
source_format = cxm_ntsc_50hz_source_format;
break;
case 2:
source_format = cxm_pal_50hz_source_format;
break;
case 3:
source_format = cxm_secam_50hz_source_format;
break;
default:
break;
}
} else {
switch (status[0] & 0x03) {
case 0:
source_format = cxm_bw_60hz_source_format;
break;
case 1:
source_format = cxm_ntsc_60hz_source_format;
break;
case 2:
source_format = cxm_pal_60hz_source_format;
break;
default:
break;
}
}
return source_format;
}
int
cxm_saa7115_detected_fps(struct cxm_softc *sc)
{
unsigned char status[1];
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1f,
status, sizeof(status)) != sizeof(status))
return -1;
if (!(status[0] & 0x01)) {
device_printf(sc->dev, "video decoder isn't locked\n");
return -1;
}
return (status[0] & 0x20) ? 30 : 25;
}
int
cxm_saa7115_get_brightness(struct cxm_softc *sc)
{
unsigned char brightness;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0a,
&brightness, sizeof(brightness))
!= sizeof(brightness))
return -1;
return brightness;
}
int
cxm_saa7115_set_brightness(struct cxm_softc *sc, unsigned char brightness)
{
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0a,
&brightness, sizeof(brightness))
!= sizeof(brightness))
return -1;
return 0;
}
int
cxm_saa7115_get_chroma_saturation(struct cxm_softc *sc)
{
unsigned char chroma_saturation;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0c,
&chroma_saturation, sizeof(chroma_saturation))
!= sizeof(chroma_saturation))
return -1;
return chroma_saturation;
}
int
cxm_saa7115_set_chroma_saturation(struct cxm_softc *sc,
unsigned char chroma_saturation)
{
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0c,
&chroma_saturation, sizeof(chroma_saturation))
!= sizeof(chroma_saturation))
return -1;
return 0;
}
int
cxm_saa7115_get_contrast(struct cxm_softc *sc)
{
unsigned char contrast;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0b,
&contrast, sizeof(contrast)) != sizeof(contrast))
return -1;
return contrast;
}
int
cxm_saa7115_set_contrast(struct cxm_softc *sc, unsigned char contrast)
{
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0b,
&contrast, sizeof(contrast)) != sizeof(contrast))
return -1;
return 0;
}
int
cxm_saa7115_get_hue(struct cxm_softc *sc)
{
unsigned char hue;
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0d,
&hue, sizeof(hue))
!= sizeof(hue))
return -1;
return hue;
}
int
cxm_saa7115_set_hue(struct cxm_softc *sc, unsigned char hue)
{
if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0d,
&hue, sizeof(hue))
!= sizeof(hue))
return -1;
return 0;
}
int
cxm_saa7115_is_locked(struct cxm_softc *sc)
{
unsigned char status[1];
if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1f,
status, sizeof(status)) != sizeof(status))
return -1;
return (status[0] & 0x01) ? 1 : 0;
}
int
cxm_saa7115_wait_for_lock(struct cxm_softc *sc)
{
unsigned int i;
for (i = 0; i < 10; i++) {
tsleep(&sc->iicbus, 0, "video", hz / 20);
switch (cxm_saa7115_is_locked(sc)) {
case 1:
return 1;
case 0:
break;
default:
return -1;
}
}
device_printf(sc->dev, "video decoder failed to lock\n");
return 0;
}