// SPDX-License-Identifier: GPL-2.0-or-later
/*
bt866 - BT866 Digital Video Encoder (Rockwell Part)
Copyright (C) 1999 Mike Bernson <mike@mlb.org>
Copyright (C) 1998 Dave Perks <dperks@ibm.net>
Modifications for LML33/DC10plus unified driver
Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
This code was modify/ported from the saa7111 driver written
by Dave Perks.
This code was adapted for the bt866 by Christer Weinigel and ported
to 2.6 by Martin Samuelsson.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
MODULE_DESCRIPTION("Brooktree-866 video encoder driver" );
MODULE_AUTHOR("Mike Bernson & Dave Perks" );
MODULE_LICENSE("GPL" );
static int debug;
module_param(debug, int , 0 );
MODULE_PARM_DESC(debug, "Debug level (0-1)" );
/* ----------------------------------------------------------------------- */
struct bt866 {
struct v4l2_subdev sd;
u8 reg[256 ];
};
static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
{
return container_of(sd, struct bt866, sd);
}
static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
{
struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
u8 buffer[2 ];
int err;
buffer[0 ] = subaddr;
buffer[1 ] = data;
encoder->reg[subaddr] = data;
v4l_dbg(1 , debug, client, "write 0x%02x = 0x%02x\n" , subaddr, data);
for (err = 0 ; err < 3 ;) {
if (i2c_master_send(client, buffer, 2 ) == 2 )
break ;
err++;
v4l_warn(client, "error #%d writing to 0x%02x\n" ,
err, subaddr);
schedule_timeout_interruptible(msecs_to_jiffies(100 ));
}
if (err == 3 ) {
v4l_warn(client, "giving up\n" );
return -1 ;
}
return 0 ;
}
static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
{
v4l2_dbg(1 , debug, sd, "set norm %llx\n" , (unsigned long long )std);
/* Only PAL supported by this driver at the moment! */
if (!(std & V4L2_STD_NTSC))
return -EINVAL;
return 0 ;
}
static int bt866_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
static const __u8 init[] = {
0 xc8, 0 xcc, /* CRSCALE */
0 xca, 0 x91, /* CBSCALE */
0 xcc, 0 x24, /* YC16 | OSDNUM */
0 xda, 0 x00, /* */
0 xdc, 0 x24, /* SETMODE | PAL */
0 xde, 0 x02, /* EACTIVE */
/* overlay colors */
0 x70, 0 xEB, 0 x90, 0 x80, 0 xB0, 0 x80, /* white */
0 x72, 0 xA2, 0 x92, 0 x8E, 0 xB2, 0 x2C, /* yellow */
0 x74, 0 x83, 0 x94, 0 x2C, 0 xB4, 0 x9C, /* cyan */
0 x76, 0 x70, 0 x96, 0 x3A, 0 xB6, 0 x48, /* green */
0 x78, 0 x54, 0 x98, 0 xC6, 0 xB8, 0 xB8, /* magenta */
0 x7A, 0 x41, 0 x9A, 0 xD4, 0 xBA, 0 x64, /* red */
0 x7C, 0 x23, 0 x9C, 0 x72, 0 xBC, 0 xD4, /* blue */
0 x7E, 0 x10, 0 x9E, 0 x80, 0 xBE, 0 x80, /* black */
0 x60, 0 xEB, 0 x80, 0 x80, 0 xc0, 0 x80, /* white */
0 x62, 0 xA2, 0 x82, 0 x8E, 0 xc2, 0 x2C, /* yellow */
0 x64, 0 x83, 0 x84, 0 x2C, 0 xc4, 0 x9C, /* cyan */
0 x66, 0 x70, 0 x86, 0 x3A, 0 xc6, 0 x48, /* green */
0 x68, 0 x54, 0 x88, 0 xC6, 0 xc8, 0 xB8, /* magenta */
0 x6A, 0 x41, 0 x8A, 0 xD4, 0 xcA, 0 x64, /* red */
0 x6C, 0 x23, 0 x8C, 0 x72, 0 xcC, 0 xD4, /* blue */
0 x6E, 0 x10, 0 x8E, 0 x80, 0 xcE, 0 x80, /* black */
};
struct bt866 *encoder = to_bt866(sd);
u8 val;
int i;
for (i = 0 ; i < ARRAY_SIZE(init) / 2 ; i += 2 )
bt866_write(encoder, init[i], init[i+1 ]);
val = encoder->reg[0 xdc];
if (input == 0 )
val |= 0 x40; /* CBSWAP */
else
val &= ~0 x40; /* !CBSWAP */
bt866_write(encoder, 0 xdc, val);
val = encoder->reg[0 xcc];
if (input == 2 )
val |= 0 x01; /* OSDBAR */
else
val &= ~0 x01; /* !OSDBAR */
bt866_write(encoder, 0 xcc, val);
v4l2_dbg(1 , debug, sd, "set input %d\n" , input);
switch (input) {
case 0 :
case 1 :
case 2 :
break ;
default :
return -EINVAL;
}
return 0 ;
}
#if 0
/* Code to setup square pixels, might be of some use in the future,
but is currently unused. */
val = encoder->reg[0 xdc];
if (*iarg)
val |= 1 ; /* SQUARE */
else
val &= ~1 ; /* !SQUARE */
bt866_write(client, 0 xdc, val);
#endif
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_video_ops bt866_video_ops = {
.s_std_output = bt866_s_std_output,
.s_routing = bt866_s_routing,
};
static const struct v4l2_subdev_ops bt866_ops = {
.video = &bt866_video_ops,
};
static int bt866_probe(struct i2c_client *client)
{
struct bt866 *encoder;
struct v4l2_subdev *sd;
v4l_info(client, "chip found @ 0x%x (%s)\n" ,
client->addr << 1 , client->adapter->name);
encoder = devm_kzalloc(&client->dev, sizeof (*encoder), GFP_KERNEL);
if (encoder == NULL)
return -ENOMEM;
sd = &encoder->sd;
v4l2_i2c_subdev_init(sd, client, &bt866_ops);
return 0 ;
}
static void bt866_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
}
static const struct i2c_device_id bt866_id[] = {
{ "bt866" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bt866_id);
static struct i2c_driver bt866_driver = {
.driver = {
.name = "bt866" ,
},
.probe = bt866_probe,
.remove = bt866_remove,
.id_table = bt866_id,
};
module_i2c_driver(bt866_driver);
Messung V0.5 in Prozent C=92 H=94 G=92
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-05)
¤
*© Formatika GbR, Deutschland