7,7 → 7,7 |
|
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) |
& Marcus Metzler (mocm@thp.uni-koeln.de) |
(c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> |
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org> |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
25,29 → 25,47 |
|
*/ |
|
/* SHARK version by Giacomo Guidi <giacomo@gandalf.sssup.it> */ |
#include <linuxcomp.h> |
|
#define __NO_VERSION__ 1 |
#include <linux/module.h> |
#include <linux/init.h> |
#include <linux/delay.h> |
|
#include <linux/pci.h> |
#include <string.h> |
#include <asm/io.h> |
|
#include "drivers/bttv.h" |
#include "drivers/tuner.h" |
#include "drivers/bttvp.h" |
|
#define printk cprintf |
|
static struct i2c_algo_bit_data bttv_i2c_algo_template; |
static struct i2c_adapter bttv_i2c_adap_template; |
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template; |
static struct i2c_adapter bttv_i2c_adap_sw_template; |
static struct i2c_adapter bttv_i2c_adap_hw_template; |
static struct i2c_client bttv_i2c_client_template; |
|
#ifndef I2C_PEC |
static void bttv_inc_use(struct i2c_adapter *adap); |
static void bttv_dec_use(struct i2c_adapter *adap); |
#endif |
static int attach_inform(struct i2c_client *client); |
|
EXPORT_SYMBOL(bttv_get_cardinfo); |
EXPORT_SYMBOL(bttv_get_pcidev); |
EXPORT_SYMBOL(bttv_get_id); |
EXPORT_SYMBOL(bttv_gpio_enable); |
EXPORT_SYMBOL(bttv_read_gpio); |
EXPORT_SYMBOL(bttv_write_gpio); |
EXPORT_SYMBOL(bttv_get_gpio_queue); |
EXPORT_SYMBOL(bttv_i2c_call); |
|
static int i2c_debug = 0; |
static int i2c_hw = 0; |
MODULE_PARM(i2c_debug,"i"); |
MODULE_PARM(i2c_hw,"i"); |
|
/* ----------------------------------------------------------------------- */ |
/* Exported functions - for other modules which want to access the */ |
/* gpio ports (IR for example) */ |
/* see bttv.h for comments */ |
|
int bttv_get_cardinfo(unsigned int card, int *type, int *cardid) |
int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid) |
{ |
if (card >= bttv_num) { |
return -1; |
57,6 → 75,23 |
return 0; |
} |
|
struct pci_dev* bttv_get_pcidev(unsigned int card) |
{ |
if (card >= bttv_num) |
return NULL; |
return bttvs[card].dev; |
} |
|
int bttv_get_id(unsigned int card) |
{ |
printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); |
if (card >= bttv_num) { |
return -1; |
} |
return bttvs[card].type; |
} |
|
|
int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) |
{ |
struct bttv *btv; |
88,7 → 123,7 |
|
/* prior setting BT848_GPIO_REG_INP is (probably) not needed |
because we set direct input on init */ |
*data = gpioread(); |
*data = btread(BT848_GPIO_DATA); |
return 0; |
} |
|
104,39 → 139,53 |
|
/* prior setting BT848_GPIO_REG_INP is (probably) not needed |
because direct input is set on init */ |
gpioaor(data & mask, ~mask); |
btaor(data & mask, ~mask, BT848_GPIO_DATA); |
if (bttv_gpio) |
bttv_gpio_tracking(btv,"extern write"); |
return 0; |
} |
|
wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) |
{ |
struct bttv *btv; |
|
if (card >= bttv_num) { |
return NULL; |
} |
|
btv = &bttvs[card]; |
if (bttvs[card].shutdown) { |
return NULL; |
} |
return &btv->gpioq; |
} |
|
|
/* ----------------------------------------------------------------------- */ |
/* I2C functions */ |
/* I2C functions - bitbanging adapter (software i2c) */ |
|
void bttv_bit_setscl(void *data, int state) |
{ |
struct bttv *btv = (struct bttv*)data; |
unsigned long tmp; |
|
|
if (state) |
btv->i2c_state |= 0x02; |
else |
btv->i2c_state &= ~0x02; |
btwrite(btv->i2c_state, BT848_I2C); |
tmp = btread(BT848_I2C); |
btread(BT848_I2C); |
} |
|
void bttv_bit_setsda(void *data, int state) |
{ |
struct bttv *btv = (struct bttv*)data; |
unsigned long tmp; |
|
|
if (state) |
btv->i2c_state |= 0x01; |
else |
btv->i2c_state &= ~0x01; |
btwrite(btv->i2c_state, BT848_I2C); |
tmp = btread(BT848_I2C); |
btread(BT848_I2C); |
} |
|
static int bttv_bit_getscl(void *data) |
157,88 → 206,256 |
return state; |
} |
|
static void bttv_inc_use(struct i2c_adapter *adap) |
static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { |
.setsda = bttv_bit_setsda, |
.setscl = bttv_bit_setscl, |
.getsda = bttv_bit_getsda, |
.getscl = bttv_bit_getscl, |
.udelay = 16, |
.mdelay = 10, |
.timeout = 200, |
}; |
|
static struct i2c_adapter bttv_i2c_adap_sw_template = { |
#ifdef I2C_PEC |
.owner = THIS_MODULE, |
#else |
.inc_use = bttv_inc_use, |
.dec_use = bttv_dec_use, |
#endif |
#ifdef I2C_ADAP_CLASS_TV_ANALOG |
.class = I2C_ADAP_CLASS_TV_ANALOG, |
#endif |
I2C_DEVNAME("bt848"), |
.id = I2C_HW_B_BT848, |
.client_register = attach_inform, |
}; |
|
/* ----------------------------------------------------------------------- */ |
/* I2C functions - hardware i2c */ |
|
static int algo_control(struct i2c_adapter *adapter, |
unsigned int cmd, unsigned long arg) |
{ |
MOD_INC_USE_COUNT; |
return 0; |
} |
|
static void bttv_dec_use(struct i2c_adapter *adap) |
static u32 functionality(struct i2c_adapter *adap) |
{ |
MOD_DEC_USE_COUNT; |
return I2C_FUNC_SMBUS_EMUL; |
} |
|
static int attach_inform(struct i2c_client *client) |
static int |
bttv_i2c_wait_done(struct bttv *btv) |
{ |
struct bttv *btv = (struct bttv*)client->adapter->data; |
int i; |
u32 stat; |
unsigned long timeout; |
|
for (i = 0; i < I2C_CLIENTS_MAX; i++) { |
if (btv->i2c_clients[i] == NULL) { |
btv->i2c_clients[i] = client; |
timeout = jiffies + HZ/100 + 1; /* 10ms */ |
for (;;) { |
stat = btread(BT848_INT_STAT); |
if (stat & BT848_INT_I2CDONE) |
break; |
if (time_after(jiffies,timeout)) |
return -EIO; |
udelay(10); |
} |
btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); |
return ((stat & BT848_INT_RACK) ? 1 : 0); |
} |
|
#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\ |
BT848_I2C_SCL | BT848_I2C_SDA) |
|
static int |
bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) |
{ |
u32 xmit; |
int retval,cnt; |
|
/* start, address + first byte */ |
xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW; |
if (msg->len > 1 || !last) |
xmit |= BT878_I2C_NOSTOP; |
btwrite(xmit, BT848_I2C); |
retval = bttv_i2c_wait_done(btv); |
if (retval < 0) |
goto err; |
if (retval == 0) |
goto eio; |
if (i2c_debug) { |
printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]); |
if (!(xmit & BT878_I2C_NOSTOP)) |
printk(" >\n"); |
} |
|
for (cnt = 1; cnt < msg->len; cnt++ ) { |
/* following bytes */ |
xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART; |
if (cnt < msg->len-1 || !last) |
xmit |= BT878_I2C_NOSTOP; |
btwrite(xmit, BT848_I2C); |
retval = bttv_i2c_wait_done(btv); |
if (retval < 0) |
goto err; |
if (retval == 0) |
goto eio; |
if (i2c_debug) { |
printk(" %02x", msg->buf[cnt]); |
if (!(xmit & BT878_I2C_NOSTOP)) |
printk(" >\n"); |
} |
} |
if (btv->tuner_type != -1) |
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); |
if (bttv_verbose) |
cprintf("bttv%d: i2c attach [client=%s,%s]\n",btv->nr, |
client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); |
return 0; |
return msg->len; |
|
eio: |
retval = -EIO; |
err: |
if (i2c_debug) |
printk(" ERR: %d\n",retval); |
return retval; |
} |
|
static int detach_inform(struct i2c_client *client) |
static int |
bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) |
{ |
struct bttv *btv = (struct bttv*)client->adapter->data; |
int i; |
u32 xmit; |
u32 cnt; |
int retval; |
|
for (i = 0; i < I2C_CLIENTS_MAX; i++) { |
if (btv->i2c_clients[i] == client) { |
btv->i2c_clients[i] = NULL; |
break; |
for(cnt = 0; cnt < msg->len; cnt++) { |
xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; |
if (cnt < msg->len-1) |
xmit |= BT848_I2C_W3B; |
if (cnt < msg->len-1 || !last) |
xmit |= BT878_I2C_NOSTOP; |
if (cnt) |
xmit |= BT878_I2C_NOSTART; |
btwrite(xmit, BT848_I2C); |
retval = bttv_i2c_wait_done(btv); |
if (retval < 0) |
goto err; |
if (retval == 0) |
goto eio; |
msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; |
if (i2c_debug) { |
if (!(xmit & BT878_I2C_NOSTART)) |
printk(" <R %02x", (msg->addr << 1) +1); |
printk(" =%02x", msg->buf[cnt]); |
if (!(xmit & BT878_I2C_NOSTOP)) |
printk(" >\n"); |
} |
} |
if (bttv_verbose) |
cprintf("bttv%d: i2c detach [client=%s,%s]\n",btv->nr, |
client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); |
return 0; |
return msg->len; |
|
eio: |
retval = -EIO; |
err: |
if (i2c_debug) |
printk(" ERR: %d\n",retval); |
return retval; |
} |
|
void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) |
int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) |
{ |
struct bttv *btv = i2c_get_adapdata(i2c_adap); |
int retval = 0; |
int i; |
|
for (i = 0; i < I2C_CLIENTS_MAX; i++) { |
if (NULL == btv->i2c_clients[i]) |
continue; |
if (NULL == btv->i2c_clients[i]->driver->command) |
continue; |
btv->i2c_clients[i]->driver->command( |
btv->i2c_clients[i],cmd,arg); |
|
if (i2c_debug) |
printk("bt-i2c:"); |
btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); |
for (i = 0 ; i < num; i++) { |
if (msgs[i].flags & I2C_M_RD) { |
/* read */ |
retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num); |
if (retval < 0) |
goto err; |
} else { |
/* write */ |
retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num); |
if (retval < 0) |
goto err; |
} |
} |
return num; |
|
err: |
return retval; |
} |
|
static struct i2c_algo_bit_data bttv_i2c_algo_template = { |
setsda: bttv_bit_setsda, |
setscl: bttv_bit_setscl, |
getsda: bttv_bit_getsda, |
getscl: bttv_bit_getscl, |
udelay: 16, |
mdelay: 10, |
timeout: 200, |
static struct i2c_algorithm bttv_algo = { |
.name = "bt878", |
.id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, |
.master_xfer = bttv_i2c_xfer, |
.algo_control = algo_control, |
.functionality = functionality, |
}; |
|
static struct i2c_adapter bttv_i2c_adap_template = { |
name: "bt848", |
id: I2C_HW_B_BT848, |
inc_use: bttv_inc_use, |
dec_use: bttv_dec_use, |
client_register: attach_inform, |
client_unregister: detach_inform, |
static struct i2c_adapter bttv_i2c_adap_hw_template = { |
#ifdef I2C_PEC |
.owner = THIS_MODULE, |
#else |
.inc_use = bttv_inc_use, |
.dec_use = bttv_dec_use, |
#endif |
#ifdef I2C_ADAP_CLASS_TV_ANALOG |
.class = I2C_ADAP_CLASS_TV_ANALOG, |
#endif |
I2C_DEVNAME("bt878"), |
.id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, |
.algo = &bttv_algo, |
.client_register = attach_inform, |
}; |
|
/* ----------------------------------------------------------------------- */ |
/* I2C functions - common stuff */ |
|
#ifndef I2C_PEC |
static void bttv_inc_use(struct i2c_adapter *adap) |
{ |
MOD_INC_USE_COUNT; |
} |
|
static void bttv_dec_use(struct i2c_adapter *adap) |
{ |
MOD_DEC_USE_COUNT; |
} |
#endif |
|
static int attach_inform(struct i2c_client *client) |
{ |
struct bttv *btv = i2c_get_adapdata(client->adapter); |
|
if (btv->tuner_type != UNSET) |
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); |
if (btv->pinnacle_id != UNSET) |
bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, |
&btv->pinnacle_id); |
|
if (bttv_debug) |
printk("bttv%d: i2c attach [client=%s]\n", |
btv->nr, i2c_clientname(client)); |
return 0; |
} |
|
void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) |
{ |
if (0 != btv->i2c_rc) |
return; |
i2c_clients_command(&btv->i2c_adap, cmd, arg); |
} |
|
void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) |
{ |
if (card >= bttv_num) |
return; |
bttv_call_i2c_clients(&bttvs[card], cmd, arg); |
} |
|
static struct i2c_client bttv_i2c_client_template = { |
name: "bttv internal use only", |
id: -1, |
I2C_DEVNAME("bttv internal"), |
.id = -1, |
}; |
|
|
250,7 → 467,7 |
if (0 != btv->i2c_rc) |
return -1; |
if (bttv_verbose && NULL != probe_for) |
printk("[info ] bttv%d: i2c: checking for %s @ 0x%02x... ", |
printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", |
btv->nr,probe_for,addr); |
btv->i2c_client.addr = addr >> 1; |
if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { |
258,7 → 475,7 |
if (bttv_verbose) |
printk("not found\n"); |
} else |
printk("bttv%d: i2c read 0x%x: error\n", |
printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", |
btv->nr,addr); |
return -1; |
} |
285,86 → 502,76 |
} |
|
/* read EEPROM content */ |
void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) |
void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) |
{ |
int i; |
|
if (bttv_I2CWrite(btv, addr, 0, -1, 0)<0) { |
printk("bttv: readee error\n"); |
printk(KERN_WARNING "bttv: readee error\n"); |
return; |
} |
btv->i2c_client.addr = addr >> 1; |
for (i=0; i<256; i+=16) { |
if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { |
printk("bttv: readee error\n"); |
printk(KERN_WARNING "bttv: readee error\n"); |
break; |
} |
} |
} |
|
/* TODO: get an assigned bus id */ |
#define I2C_HW_B_BT848_OSPREY 0x0FF |
|
/* init + register i2c algo-bit adapter */ |
int init_bttv_i2c(struct bttv *btv) |
int __devinit init_bttv_i2c(struct bttv *btv) |
{ |
memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, |
sizeof(struct i2c_adapter)); |
|
if ((btv->type == BTTV_OSPREY2000) || |
(btv->type == BTTV_OSPREY5x0)) { |
/* these boards have the bt860 which conflicts with the tda7432 |
* which will attempt to load when this type of bus is registered. |
* change the bus name to prevent this (and any other conflicts) |
* from occuring */ |
btv->i2c_adap.id = I2C_HW_B_BT848_OSPREY; |
} |
|
memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, |
sizeof(struct i2c_algo_bit_data)); |
int use_hw = (btv->id == 878) && i2c_hw; |
|
memcpy(&btv->i2c_client, &bttv_i2c_client_template, |
sizeof(struct i2c_client)); |
sizeof(bttv_i2c_client_template)); |
|
sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), |
" #%d", btv->nr); |
btv->i2c_algo.data = btv; |
btv->i2c_adap.data = btv; |
btv->i2c_adap.algo_data = &btv->i2c_algo; |
if (use_hw) { |
/* bt878 */ |
memcpy(&btv->i2c_adap, &bttv_i2c_adap_hw_template, |
sizeof(bttv_i2c_adap_hw_template)); |
} else { |
/* bt848 */ |
memcpy(&btv->i2c_adap, &bttv_i2c_adap_sw_template, |
sizeof(bttv_i2c_adap_sw_template)); |
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, |
sizeof(bttv_i2c_algo_bit_template)); |
btv->i2c_algo.data = btv; |
btv->i2c_adap.algo_data = &btv->i2c_algo; |
} |
|
btv->i2c_adap.dev.parent = &btv->dev->dev; |
snprintf(btv->i2c_adap.name, sizeof(btv->i2c_adap.name), |
"bt%d #%d [%s]", btv->id, btv->nr, use_hw ? "hw" : "sw"); |
|
i2c_set_adapdata(&btv->i2c_adap, btv); |
btv->i2c_client.adapter = &btv->i2c_adap; |
|
bttv_bit_setscl(btv,1); |
bttv_bit_setsda(btv,1); |
|
printk("[info ] bttv: adding i2c bus to system\n"); |
btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap); |
printk("[info ] bttv: i2c bus added to system\n"); |
if (use_hw) { |
btv->i2c_rc = i2c_add_adapter(&btv->i2c_adap); |
} else { |
bttv_bit_setscl(btv,1); |
bttv_bit_setsda(btv,1); |
btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap); |
} |
return btv->i2c_rc; |
} |
|
/* find a bttv struct by matching some data from the pci bus (for audio) */ |
struct bttv *bttv_find_matching_card( struct pci_dev *dev ) |
int __devexit fini_bttv_i2c(struct bttv *btv) |
{ |
int i; |
|
if (dev == NULL) return NULL; |
for (i = 0;i < bttv_num;i++) { |
if (bttvs[i].dev == NULL) { |
continue; //hmm...can this ever happen? |
} |
if ((dev->bus->number == bttvs[i].dev->bus->number) && |
(PCI_SLOT(dev->devfn) == PCI_SLOT(bttvs[i].dev->devfn))) { |
//match! return this one. |
return &(bttvs[i]); |
} |
int use_hw = (btv->id == 878) && i2c_hw; |
|
if (0 != btv->i2c_rc) |
return 0; |
|
if (use_hw) { |
return i2c_del_adapter(&btv->i2c_adap); |
} else { |
return i2c_bit_del_bus(&btv->i2c_adap); |
} |
return NULL; |
} |
|
struct gpio_adapter *bttv_get_gpio( struct bttv *btv ) |
{ |
return &(btv->gpio_adap); |
} |
|
/* |
* Local variables: |
* c-basic-offset: 8 |