bt832.c 6.24 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8
/* Driver for Bt832 CMOS Camera Video Processor
    i2c-addresses: 0x88 or 0x8a

  The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
  via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
  It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
  connected to bt848/bt878 GPIO pins on this purpose.
  (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
9

Linus Torvalds's avatar
Linus Torvalds committed
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
  Supported Cards:
  -  Pixelview Rev.4E: 0x8a
		GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !

  (c) Gunther Mayer, 2002

  STATUS:
  - detect chip and hexdump
  - reset chip and leave low power mode
  - detect camera present

  TODO:
  - make it work (find correct setup for Bt832 and Bt878)
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>

34
#include <media/audiochip.h>
Linus Torvalds's avatar
Linus Torvalds committed
35 36 37 38 39 40
#include "bttv.h"
#include "bt832.h"

MODULE_LICENSE("GPL");

/* Addresses to scan */
41 42
static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
				       I2C_CLIENT_END };
Linus Torvalds's avatar
Linus Torvalds committed
43 44 45 46 47 48 49 50 51 52 53 54 55
I2C_CLIENT_INSMOD;

/* ---------------------------------------------------------------------- */

#define dprintk     if (debug) printk

static int bt832_detach(struct i2c_client *client);


static struct i2c_driver driver;
static struct i2c_client client_template;

struct bt832 {
56
	struct i2c_client client;
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59 60 61 62
};

int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
{
	int i,rc;
	buf[0]=0x80; // start at register 0 with auto-increment
63 64
	if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
		printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
Linus Torvalds's avatar
Linus Torvalds committed
65

66 67 68 69
	for(i=0;i<65;i++)
		buf[i]=0;
	if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
		printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
Linus Torvalds's avatar
Linus Torvalds committed
70

71 72
	// Note: On READ the first byte is the current index
	//  (e.g. 0x80, what we just wrote)
Linus Torvalds's avatar
Linus Torvalds committed
73

74 75 76 77
	if(1) {
		int i;
		printk("BT832 hexdump:\n");
		for(i=1;i<65;i++) {
Linus Torvalds's avatar
Linus Torvalds committed
78 79
			if(i!=1) {
			  if(((i-1)%8)==0) printk(" ");
80
			  if(((i-1)%16)==0) printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
81
			}
82 83 84 85
			printk(" %02x",buf[i]);
		}
		printk("\n");
	}
Linus Torvalds's avatar
Linus Torvalds committed
86 87 88 89 90 91 92 93 94 95 96
	return 0;
}

// Return: 1 (is a bt832), 0 (No bt832 here)
int bt832_init(struct i2c_client *i2c_client_s)
{
	unsigned char *buf;
	int rc;

	buf=kmalloc(65,GFP_KERNEL);
	bt832_hexdump(i2c_client_s,buf);
97

Linus Torvalds's avatar
Linus Torvalds committed
98 99 100 101 102 103
	if(buf[0x40] != 0x31) {
		printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
		kfree(buf);
		return 0;
	}

104 105 106 107 108
	printk("Write 0 tp VPSTATUS\n");
	buf[0]=BT832_VP_STATUS; // Reg.52
	buf[1]= 0x00;
	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
		printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
Linus Torvalds's avatar
Linus Torvalds committed
109

110
	bt832_hexdump(i2c_client_s,buf);
Linus Torvalds's avatar
Linus Torvalds committed
111 112 113 114 115 116 117


	// Leave low power mode:
	printk("Bt832: leave low power mode.\n");
	buf[0]=BT832_CAM_SETUP0; //0x39 57
	buf[1]=0x08;
	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
118
		printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
Linus Torvalds's avatar
Linus Torvalds committed
119

120
	bt832_hexdump(i2c_client_s,buf);
Linus Torvalds's avatar
Linus Torvalds committed
121 122

	printk("Write 0 tp VPSTATUS\n");
123 124 125 126
	buf[0]=BT832_VP_STATUS; // Reg.52
	buf[1]= 0x00;
	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
		printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
Linus Torvalds's avatar
Linus Torvalds committed
127

128
	bt832_hexdump(i2c_client_s,buf);
Linus Torvalds's avatar
Linus Torvalds committed
129 130 131 132 133 134 135


	// Enable Output
	printk("Enable Output\n");
	buf[0]=BT832_VP_CONTROL1; // Reg.40
	buf[1]= 0x27 & (~0x01); // Default | !skip
	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
136
		printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
137

138
	bt832_hexdump(i2c_client_s,buf);
Linus Torvalds's avatar
Linus Torvalds committed
139 140 141 142 143 144


	// for testing (even works when no camera attached)
	printk("bt832: *** Generate NTSC M Bars *****\n");
	buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
	buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
145 146
	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
		printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
Linus Torvalds's avatar
Linus Torvalds committed
147 148 149 150

	printk("Bt832: Camera Present: %s\n",
		(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");

151
	bt832_hexdump(i2c_client_s,buf);
Linus Torvalds's avatar
Linus Torvalds committed
152 153 154 155 156 157
	kfree(buf);
	return 1;
}



158
static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
Linus Torvalds's avatar
Linus Torvalds committed
159 160 161 162 163
{
	struct bt832 *t;

	printk("bt832_attach\n");

164 165
	client_template.adapter = adap;
	client_template.addr    = addr;
Linus Torvalds's avatar
Linus Torvalds committed
166

167
	printk("bt832: chip found @ 0x%x\n", addr<<1);
Linus Torvalds's avatar
Linus Torvalds committed
168

169 170
	if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
171 172
	memset(t,0,sizeof(*t));
	t->client = client_template;
173 174
	i2c_set_clientdata(&t->client, t);
	i2c_attach_client(&t->client);
Linus Torvalds's avatar
Linus Torvalds committed
175 176 177 178 179

	if(! bt832_init(&t->client)) {
		bt832_detach(&t->client);
		return -1;
	}
180

Linus Torvalds's avatar
Linus Torvalds committed
181 182 183 184 185
	return 0;
}

static int bt832_probe(struct i2c_adapter *adap)
{
186
#ifdef I2C_CLASS_TV_ANALOG
Linus Torvalds's avatar
Linus Torvalds committed
187 188
	if (adap->class & I2C_CLASS_TV_ANALOG)
		return i2c_probe(adap, &addr_data, bt832_attach);
189
#else
190
	if (adap->id == I2C_HW_B_BT848)
191 192
		return i2c_probe(adap, &addr_data, bt832_attach);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
193 194 195 196 197
	return 0;
}

static int bt832_detach(struct i2c_client *client)
{
198
	struct bt832 *t = i2c_get_clientdata(client);
Linus Torvalds's avatar
Linus Torvalds committed
199 200 201 202 203 204 205 206 207 208

	printk("bt832: detach.\n");
	i2c_detach_client(client);
	kfree(t);
	return 0;
}

static int
bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
209
	struct bt832 *t = i2c_get_clientdata(client);
Linus Torvalds's avatar
Linus Torvalds committed
210 211 212

	printk("bt832: command %x\n",cmd);

213
	switch (cmd) {
Linus Torvalds's avatar
Linus Torvalds committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
		case BT832_HEXDUMP: {
			unsigned char *buf;
			buf=kmalloc(65,GFP_KERNEL);
			bt832_hexdump(&t->client,buf);
			kfree(buf);
		}
		break;
		case BT832_REATTACH:
			printk("bt832: re-attach\n");
			i2c_del_driver(&driver);
			i2c_add_driver(&driver);
		break;
	}
	return 0;
}

/* ----------------------------------------------------------------------- */

static struct i2c_driver driver = {
	.owner          = THIS_MODULE,
234 235 236 237 238
	.name           = "i2c bt832 driver",
	.id             = -1, /* FIXME */
	.attach_adapter = bt832_probe,
	.detach_client  = bt832_detach,
	.command        = bt832_command,
Linus Torvalds's avatar
Linus Torvalds committed
239 240 241
};
static struct i2c_client client_template =
{
242
	.name       = "bt832",
243
	.driver     = &driver,
Linus Torvalds's avatar
Linus Torvalds committed
244 245 246
};


247
static int __init bt832_init_module(void)
Linus Torvalds's avatar
Linus Torvalds committed
248
{
249
	return i2c_add_driver(&driver);
Linus Torvalds's avatar
Linus Torvalds committed
250 251
}

252
static void __exit bt832_cleanup_module(void)
Linus Torvalds's avatar
Linus Torvalds committed
253 254 255 256 257 258 259
{
	i2c_del_driver(&driver);
}

module_init(bt832_init_module);
module_exit(bt832_cleanup_module);

260 261 262 263 264 265 266
/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-basic-offset: 8
 * End:
 */