linux/drivers/media/i2c/bt866.c
<<
>>
Prefs
   1/*
   2    bt866 - BT866 Digital Video Encoder (Rockwell Part)
   3
   4    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
   5    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
   6
   7    Modifications for LML33/DC10plus unified driver
   8    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
   9
  10    This code was modify/ported from the saa7111 driver written
  11    by Dave Perks.
  12
  13    This code was adapted for the bt866 by Christer Weinigel and ported
  14    to 2.6 by Martin Samuelsson.
  15
  16    This program is free software; you can redistribute it and/or modify
  17    it under the terms of the GNU General Public License as published by
  18    the Free Software Foundation; either version 2 of the License, or
  19    (at your option) any later version.
  20
  21    This program is distributed in the hope that it will be useful,
  22    but WITHOUT ANY WARRANTY; without even the implied warranty of
  23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24    GNU General Public License for more details.
  25
  26    You should have received a copy of the GNU General Public License
  27    along with this program; if not, write to the Free Software
  28    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29*/
  30
  31#include <linux/module.h>
  32#include <linux/types.h>
  33#include <linux/slab.h>
  34#include <linux/ioctl.h>
  35#include <asm/uaccess.h>
  36#include <linux/i2c.h>
  37#include <linux/videodev2.h>
  38#include <media/v4l2-device.h>
  39#include <media/v4l2-chip-ident.h>
  40
  41MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
  42MODULE_AUTHOR("Mike Bernson & Dave Perks");
  43MODULE_LICENSE("GPL");
  44
  45static int debug;
  46module_param(debug, int, 0);
  47MODULE_PARM_DESC(debug, "Debug level (0-1)");
  48
  49
  50/* ----------------------------------------------------------------------- */
  51
  52struct bt866 {
  53        struct v4l2_subdev sd;
  54        u8 reg[256];
  55};
  56
  57static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
  58{
  59        return container_of(sd, struct bt866, sd);
  60}
  61
  62static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
  63{
  64        struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
  65        u8 buffer[2];
  66        int err;
  67
  68        buffer[0] = subaddr;
  69        buffer[1] = data;
  70
  71        encoder->reg[subaddr] = data;
  72
  73        v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
  74
  75        for (err = 0; err < 3;) {
  76                if (i2c_master_send(client, buffer, 2) == 2)
  77                        break;
  78                err++;
  79                v4l_warn(client, "error #%d writing to 0x%02x\n",
  80                                err, subaddr);
  81                schedule_timeout_interruptible(msecs_to_jiffies(100));
  82        }
  83        if (err == 3) {
  84                v4l_warn(client, "giving up\n");
  85                return -1;
  86        }
  87
  88        return 0;
  89}
  90
  91static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
  92{
  93        v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
  94
  95        /* Only PAL supported by this driver at the moment! */
  96        if (!(std & V4L2_STD_NTSC))
  97                return -EINVAL;
  98        return 0;
  99}
 100
 101static int bt866_s_routing(struct v4l2_subdev *sd,
 102                           u32 input, u32 output, u32 config)
 103{
 104        static const __u8 init[] = {
 105                0xc8, 0xcc, /* CRSCALE */
 106                0xca, 0x91, /* CBSCALE */
 107                0xcc, 0x24, /* YC16 | OSDNUM */
 108                0xda, 0x00, /*  */
 109                0xdc, 0x24, /* SETMODE | PAL */
 110                0xde, 0x02, /* EACTIVE */
 111
 112                /* overlay colors */
 113                0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
 114                0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
 115                0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
 116                0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
 117                0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
 118                0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
 119                0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
 120                0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
 121
 122                0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
 123                0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
 124                0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
 125                0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
 126                0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
 127                0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
 128                0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
 129                0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
 130        };
 131        struct bt866 *encoder = to_bt866(sd);
 132        u8 val;
 133        int i;
 134
 135        for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
 136                bt866_write(encoder, init[i], init[i+1]);
 137
 138        val = encoder->reg[0xdc];
 139
 140        if (input == 0)
 141                val |= 0x40; /* CBSWAP */
 142        else
 143                val &= ~0x40; /* !CBSWAP */
 144
 145        bt866_write(encoder, 0xdc, val);
 146
 147        val = encoder->reg[0xcc];
 148        if (input == 2)
 149                val |= 0x01; /* OSDBAR */
 150        else
 151                val &= ~0x01; /* !OSDBAR */
 152        bt866_write(encoder, 0xcc, val);
 153
 154        v4l2_dbg(1, debug, sd, "set input %d\n", input);
 155
 156        switch (input) {
 157        case 0:
 158        case 1:
 159        case 2:
 160                break;
 161        default:
 162                return -EINVAL;
 163        }
 164        return 0;
 165}
 166
 167#if 0
 168/* Code to setup square pixels, might be of some use in the future,
 169   but is currently unused. */
 170        val = encoder->reg[0xdc];
 171        if (*iarg)
 172                val |= 1; /* SQUARE */
 173        else
 174                val &= ~1; /* !SQUARE */
 175        bt866_write(client, 0xdc, val);
 176#endif
 177
 178static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 179{
 180        struct i2c_client *client = v4l2_get_subdevdata(sd);
 181
 182        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
 183}
 184
 185/* ----------------------------------------------------------------------- */
 186
 187static const struct v4l2_subdev_core_ops bt866_core_ops = {
 188        .g_chip_ident = bt866_g_chip_ident,
 189};
 190
 191static const struct v4l2_subdev_video_ops bt866_video_ops = {
 192        .s_std_output = bt866_s_std_output,
 193        .s_routing = bt866_s_routing,
 194};
 195
 196static const struct v4l2_subdev_ops bt866_ops = {
 197        .core = &bt866_core_ops,
 198        .video = &bt866_video_ops,
 199};
 200
 201static int bt866_probe(struct i2c_client *client,
 202                        const struct i2c_device_id *id)
 203{
 204        struct bt866 *encoder;
 205        struct v4l2_subdev *sd;
 206
 207        v4l_info(client, "chip found @ 0x%x (%s)\n",
 208                        client->addr << 1, client->adapter->name);
 209
 210        encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
 211        if (encoder == NULL)
 212                return -ENOMEM;
 213        sd = &encoder->sd;
 214        v4l2_i2c_subdev_init(sd, client, &bt866_ops);
 215        return 0;
 216}
 217
 218static int bt866_remove(struct i2c_client *client)
 219{
 220        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 221
 222        v4l2_device_unregister_subdev(sd);
 223        kfree(to_bt866(sd));
 224        return 0;
 225}
 226
 227static const struct i2c_device_id bt866_id[] = {
 228        { "bt866", 0 },
 229        { }
 230};
 231MODULE_DEVICE_TABLE(i2c, bt866_id);
 232
 233static struct i2c_driver bt866_driver = {
 234        .driver = {
 235                .owner  = THIS_MODULE,
 236                .name   = "bt866",
 237        },
 238        .probe          = bt866_probe,
 239        .remove         = bt866_remove,
 240        .id_table       = bt866_id,
 241};
 242
 243module_i2c_driver(bt866_driver);
 244