Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     bt866 - BT866 Digital Video Encoder (Rockwell Part)
0004 
0005     Copyright (C) 1999 Mike Bernson <mike@mlb.org>
0006     Copyright (C) 1998 Dave Perks <dperks@ibm.net>
0007 
0008     Modifications for LML33/DC10plus unified driver
0009     Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
0010 
0011     This code was modify/ported from the saa7111 driver written
0012     by Dave Perks.
0013 
0014     This code was adapted for the bt866 by Christer Weinigel and ported
0015     to 2.6 by Martin Samuelsson.
0016 
0017 */
0018 
0019 #include <linux/module.h>
0020 #include <linux/types.h>
0021 #include <linux/slab.h>
0022 #include <linux/ioctl.h>
0023 #include <linux/uaccess.h>
0024 #include <linux/i2c.h>
0025 #include <linux/videodev2.h>
0026 #include <media/v4l2-device.h>
0027 
0028 MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
0029 MODULE_AUTHOR("Mike Bernson & Dave Perks");
0030 MODULE_LICENSE("GPL");
0031 
0032 static int debug;
0033 module_param(debug, int, 0);
0034 MODULE_PARM_DESC(debug, "Debug level (0-1)");
0035 
0036 
0037 /* ----------------------------------------------------------------------- */
0038 
0039 struct bt866 {
0040     struct v4l2_subdev sd;
0041     u8 reg[256];
0042 };
0043 
0044 static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
0045 {
0046     return container_of(sd, struct bt866, sd);
0047 }
0048 
0049 static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
0050 {
0051     struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
0052     u8 buffer[2];
0053     int err;
0054 
0055     buffer[0] = subaddr;
0056     buffer[1] = data;
0057 
0058     encoder->reg[subaddr] = data;
0059 
0060     v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
0061 
0062     for (err = 0; err < 3;) {
0063         if (i2c_master_send(client, buffer, 2) == 2)
0064             break;
0065         err++;
0066         v4l_warn(client, "error #%d writing to 0x%02x\n",
0067                 err, subaddr);
0068         schedule_timeout_interruptible(msecs_to_jiffies(100));
0069     }
0070     if (err == 3) {
0071         v4l_warn(client, "giving up\n");
0072         return -1;
0073     }
0074 
0075     return 0;
0076 }
0077 
0078 static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
0079 {
0080     v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
0081 
0082     /* Only PAL supported by this driver at the moment! */
0083     if (!(std & V4L2_STD_NTSC))
0084         return -EINVAL;
0085     return 0;
0086 }
0087 
0088 static int bt866_s_routing(struct v4l2_subdev *sd,
0089                u32 input, u32 output, u32 config)
0090 {
0091     static const __u8 init[] = {
0092         0xc8, 0xcc, /* CRSCALE */
0093         0xca, 0x91, /* CBSCALE */
0094         0xcc, 0x24, /* YC16 | OSDNUM */
0095         0xda, 0x00, /*  */
0096         0xdc, 0x24, /* SETMODE | PAL */
0097         0xde, 0x02, /* EACTIVE */
0098 
0099         /* overlay colors */
0100         0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
0101         0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
0102         0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
0103         0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
0104         0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
0105         0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
0106         0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
0107         0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
0108 
0109         0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
0110         0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
0111         0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
0112         0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
0113         0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
0114         0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
0115         0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
0116         0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
0117     };
0118     struct bt866 *encoder = to_bt866(sd);
0119     u8 val;
0120     int i;
0121 
0122     for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
0123         bt866_write(encoder, init[i], init[i+1]);
0124 
0125     val = encoder->reg[0xdc];
0126 
0127     if (input == 0)
0128         val |= 0x40; /* CBSWAP */
0129     else
0130         val &= ~0x40; /* !CBSWAP */
0131 
0132     bt866_write(encoder, 0xdc, val);
0133 
0134     val = encoder->reg[0xcc];
0135     if (input == 2)
0136         val |= 0x01; /* OSDBAR */
0137     else
0138         val &= ~0x01; /* !OSDBAR */
0139     bt866_write(encoder, 0xcc, val);
0140 
0141     v4l2_dbg(1, debug, sd, "set input %d\n", input);
0142 
0143     switch (input) {
0144     case 0:
0145     case 1:
0146     case 2:
0147         break;
0148     default:
0149         return -EINVAL;
0150     }
0151     return 0;
0152 }
0153 
0154 #if 0
0155 /* Code to setup square pixels, might be of some use in the future,
0156    but is currently unused. */
0157     val = encoder->reg[0xdc];
0158     if (*iarg)
0159         val |= 1; /* SQUARE */
0160     else
0161         val &= ~1; /* !SQUARE */
0162     bt866_write(client, 0xdc, val);
0163 #endif
0164 
0165 /* ----------------------------------------------------------------------- */
0166 
0167 static const struct v4l2_subdev_video_ops bt866_video_ops = {
0168     .s_std_output = bt866_s_std_output,
0169     .s_routing = bt866_s_routing,
0170 };
0171 
0172 static const struct v4l2_subdev_ops bt866_ops = {
0173     .video = &bt866_video_ops,
0174 };
0175 
0176 static int bt866_probe(struct i2c_client *client,
0177             const struct i2c_device_id *id)
0178 {
0179     struct bt866 *encoder;
0180     struct v4l2_subdev *sd;
0181 
0182     v4l_info(client, "chip found @ 0x%x (%s)\n",
0183             client->addr << 1, client->adapter->name);
0184 
0185     encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
0186     if (encoder == NULL)
0187         return -ENOMEM;
0188     sd = &encoder->sd;
0189     v4l2_i2c_subdev_init(sd, client, &bt866_ops);
0190     return 0;
0191 }
0192 
0193 static int bt866_remove(struct i2c_client *client)
0194 {
0195     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0196 
0197     v4l2_device_unregister_subdev(sd);
0198     return 0;
0199 }
0200 
0201 static const struct i2c_device_id bt866_id[] = {
0202     { "bt866", 0 },
0203     { }
0204 };
0205 MODULE_DEVICE_TABLE(i2c, bt866_id);
0206 
0207 static struct i2c_driver bt866_driver = {
0208     .driver = {
0209         .name   = "bt866",
0210     },
0211     .probe      = bt866_probe,
0212     .remove     = bt866_remove,
0213     .id_table   = bt866_id,
0214 };
0215 
0216 module_i2c_driver(bt866_driver);