diff -r 19981e560c9f linux/drivers/media/video/cx88/cx88-alsa.c --- a/linux/drivers/media/video/cx88/cx88-alsa.c Thu Aug 24 14:08:31 2006 -0700 +++ b/linux/drivers/media/video/cx88/cx88-alsa.c Thu Aug 24 15:04:06 2006 -0700 @@ -174,7 +174,7 @@ static int _cx88_start_audio_dma(snd_cx8 dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02)); /* enable irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02); + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | MO_INT_AUDINT); /* Enables corresponding bits at AUD_INT_STAT */ @@ -207,7 +207,7 @@ static int _cx88_stop_audio_dma(snd_cx88 cx_clear(MO_AUD_DMACNTRL, 0x11); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x02); + cx_clear(MO_PCI_INTMSK, MO_INT_AUDINT); cx_clear(MO_AUD_INTMSK, (1<<16)| (1<<12)| @@ -295,7 +295,7 @@ static irqreturn_t cx8801_irq(int irq, v int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02); + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | MO_INT_AUDINT); if (0 == status) goto out; dprintk( 3, "cx8801_irq\n" ); @@ -304,8 +304,9 @@ static irqreturn_t cx8801_irq(int irq, v handled = 1; cx_write(MO_PCI_INTSTAT, status); - if (status & 0x02) - { + if (status & core->pci_irqmask) + cx88_core_irq(core, status); + if (status & MO_INT_AUDINT) { dprintk( 2, " ALSA IRQ handling\n" ); cx8801_aud_irq(chip); } @@ -822,6 +823,8 @@ static int __devinit snd_cx88_create(str chip->irq = pci->irq; synchronize_irq(chip->irq); + /* I2C Initialization */ + cx88_devs_init(core, pci); snd_card_set_dev(card, &pci->dev); *rchip = chip; diff -r 19981e560c9f linux/drivers/media/video/cx88/cx88-core.c --- a/linux/drivers/media/video/cx88/cx88-core.c Thu Aug 24 14:08:31 2006 -0700 +++ b/linux/drivers/media/video/cx88/cx88-core.c Thu Aug 24 15:04:06 2006 -0700 @@ -548,6 +548,11 @@ int cx88_core_irq(struct cx88_core *core cx88_ir_irq(core); handled++; } + if (status & (MO_INT_I2CDONE | MO_INT_I2CRACK)) { + core->int_status = status & (MO_INT_I2CRACK | MO_INT_I2CDONE); + wake_up(&core->i2c_wq); + handled++; + } if (!handled) cx88_print_irqbits(core->name, "irq pci", cx88_pci_irqs, status, @@ -1110,6 +1115,7 @@ struct cx88_core* cx88_core_get(struct p core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); core->pci_irqmask = 0x00fc00; + core->pci_irqmask = 0x00fc00 | MO_INT_I2CDONE | MO_INT_I2CRACK; mutex_init(&core->lock); core->nr = cx88_devcount++; @@ -1168,12 +1174,7 @@ struct cx88_core* cx88_core_get(struct p core->tda9887_conf = cx88_boards[core->board].tda9887_conf; /* init hardware */ - cx88_reset(core); - cx88_i2c_init(core,pci); - cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); - cx88_card_setup(core); - cx88_ir_init(core,pci); - + /* moved alongwith i2c init */ mutex_unlock(&devlist); return core; @@ -1203,6 +1204,21 @@ void cx88_core_put(struct cx88_core *cor kfree(core); } +void cx88_devs_init(struct cx88_core *core, struct pci_dev *pci) +{ + /* init */ + if (!core->initialized) { + init_waitqueue_head(&core->i2c_wq); + cx88_reset(core); + cx88_i2c_init(core, pci); + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); + cx88_card_setup(core); + cx88_ir_init(core, pci); + core->initialized = 1; + } +} +EXPORT_SYMBOL(cx88_devs_init); + /* ------------------------------------------------------------------ */ EXPORT_SYMBOL(cx88_print_irqbits); diff -r 19981e560c9f linux/drivers/media/video/cx88/cx88-i2c.c --- a/linux/drivers/media/video/cx88/cx88-i2c.c Thu Aug 24 14:08:31 2006 -0700 +++ b/linux/drivers/media/video/cx88/cx88-i2c.c Thu Aug 24 15:04:06 2006 -0700 @@ -6,6 +6,7 @@ & Marcus Metzler (mocm@thp.uni-koeln.de) (c) 2002 Yurij Sysoev (c) 1999-2003 Gerd Knorr + (C) 2006 Manu Abraham 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 @@ -46,6 +47,139 @@ MODULE_PARM_DESC(i2c_scan,"scan i2c bus #define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) + +/* ---------------------------------------------------------------------------- */ +/* CX88 I2C Routines */ + +#define CX88_HW_I2C (MO_I2C_MODE | \ + MO_I2C_SYNC | \ + MO_I2C_SCL | \ + MO_I2C_SDA) + +static int cx88_ack_wait(struct cx88_core *core) +{ + int ret = 0; + + if (wait_event_interruptible_timeout(core->i2c_wq, + core->int_status, + msecs_to_jiffies(50)) == -ERESTARTSYS) { + + dprintk(1, "I/O Error\n"); + ret = -EREMOTEIO; + } + if (core->int_status & MO_INT_I2CRACK) { + dprintk(1, "I2CRACK\n"); + core->int_status &= ~MO_INT_I2CRACK; + } else { + dprintk(1, "ACK fail\n"); + return -EREMOTEIO; + } + if (core->int_status & MO_INT_I2CDONE) { + dprintk(1, "I2CDONE\n"); + ret = 1; + } + core->int_status &= ~MO_INT_I2CDONE; + + return ret; +} + +/* Hardware I2C Enable */ +static void cx88_i2c_enable(struct cx88_core *core) +{ + cx_set(MO_PCI_INTMSK, MO_INT_I2CDONE | MO_INT_I2CRACK); +} + +static int cx88_i2c_write(struct cx88_core *core, const struct i2c_msg *msg, int last) +{ + u32 txd; + int i; + + if (0 == msg->len) + return -EINVAL; + + txd = (msg->addr << 25) | (msg->buf[0] << 16) + | CX88_HW_I2C; + + if (msg->len > 1 || !last) + txd |= MO_I2C_NOSTOP; + cx_write(MO_I2C, txd); + msleep_interruptible(1); + if (cx88_ack_wait(core) < 0) + return -EREMOTEIO; + + for (i = 1; i < msg->len; i++) { + txd = (msg->buf[i] << 24) | CX88_HW_I2C + | MO_I2C_NOS1B; + + if (i < msg->len - 1 || !last) + txd |= MO_I2C_NOSTOP; + cx_write(MO_I2C, txd); + if (cx88_ack_wait(core) < 0) + return -EREMOTEIO; + } + return msg->len; +} + +static int cx88_i2c_read(struct cx88_core *core, const struct i2c_msg *msg, int last) +{ + u32 txd, i; + + for (i = 0; i < msg->len; i++) { + txd = (msg->addr << 25) | (1 << 24) + | CX88_HW_I2C; + + if (i < msg->len - 1) + txd |= MO_I2C_W3BRA; + if (i < msg->len - 1 || !last) + txd |= MO_I2C_NOSTOP; + if (i) + txd |= MO_I2C_NOS1B; + + cx_write(MO_I2C, txd); + msleep_interruptible(1); + if (cx88_ack_wait(core) < 0) + return -EREMOTEIO; + + msg->buf[i] = ((u32) cx_read(MO_I2C) >> 8) & 0xff; + } + return msg->len; +} + +static int cx88_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + struct cx88_core *core = i2c_get_adapdata(adapter); + int ret = 0; + int i; + + for (i = 0 ; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) + ret = cx88_i2c_read(core, &msgs[i], i + 1 == num); + else + ret = cx88_i2c_write(core, &msgs[i], i + 1 == num); + if (ret < 0) + return ret; + } + return num; +} + +static u32 cx88_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +#define I2C_HW_B_CX88 0x1c + +static struct i2c_algorithm cx88_i2c_algo = { + .master_xfer = cx88_i2c_xfer, + .functionality = cx88_i2c_func, +}; + +static struct i2c_adapter cx88_i2c_adapter = { + .owner = THIS_MODULE, + .name = "CX88 I2C", + .id = I2C_HW_B_CX88, + .algo = &cx88_i2c_algo, +}; /* ----------------------------------------------------------------------- */ @@ -92,7 +226,6 @@ static int cx8800_bit_getsda(void *data) } /* ----------------------------------------------------------------------- */ - static int attach_inform(struct i2c_client *client) { struct tuner_setup tun_setup; @@ -159,6 +292,7 @@ void cx88_call_i2c_clients(struct cx88_c #endif i2c_clients_command(&core->i2c_adap, cmd, arg); } +EXPORT_SYMBOL(cx88_call_i2c_clients); static struct i2c_algo_bit_data cx8800_i2c_algo_template = { .setsda = cx8800_bit_setsda, @@ -212,16 +346,43 @@ static void do_i2c_scan(char *name, stru /* init + register i2c algo-bit adapter */ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) { - memcpy(&core->i2c_adap, &cx8800_i2c_adap_template, - sizeof(core->i2c_adap)); - memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, - sizeof(core->i2c_algo)); - memcpy(&core->i2c_client, &cx8800_i2c_client_template, - sizeof(core->i2c_client)); - + core->i2c_hw = 1; // Temporary testing + if (core->i2c_hw) { + dprintk(1, "I2C intializing\n"); + core->int_status = 0; + memcpy(&core->i2c_adap, &cx88_i2c_adapter, + sizeof (struct i2c_adapter)); + + memcpy(&core->i2c_client, &cx8800_i2c_client_template, + sizeof (core->i2c_client)); + + i2c_set_adapdata(&core->i2c_adap, core); + core->i2c_algo.data = core; + core->i2c_client.adapter = &core->i2c_adap; + core->i2c_rc = i2c_add_adapter(&core->i2c_adap); + cx88_i2c_enable(core); + } else { + dprintk(1, "Bitbanging initializing\n"); + memcpy(&core->i2c_adap, &cx8800_i2c_adap_template, + sizeof(core->i2c_adap)); + + memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, + sizeof(core->i2c_algo)); + memcpy(&core->i2c_client, &cx8800_i2c_client_template, + sizeof(core->i2c_client)); + + i2c_set_adapdata(&core->i2c_adap,core); + core->i2c_adap.algo_data = &core->i2c_algo; + core->i2c_client.adapter = &core->i2c_adap; + + cx8800_bit_setscl(core,1); + cx8800_bit_setsda(core,1); + core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap); + + } #ifdef I2C_CLASS_TV_ANALOG if (core->tuner_type != TUNER_ABSENT) - core->i2c_adap.class |= I2C_CLASS_TV_ANALOG; + core->i2c_adap.class |= I2C_CLASS_TV_ANALOG; #endif #ifdef I2C_CLASS_TV_DIGITAL if (cx88_boards[core->board].dvb) @@ -233,14 +394,7 @@ int cx88_i2c_init(struct cx88_core *core #endif strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name)); core->i2c_algo.data = core; - i2c_set_adapdata(&core->i2c_adap,core); - core->i2c_adap.algo_data = &core->i2c_algo; - core->i2c_client.adapter = &core->i2c_adap; - - cx8800_bit_setscl(core,1); - cx8800_bit_setsda(core,1); - - core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap); + if (0 == core->i2c_rc) { dprintk(1, "i2c register ok\n"); if (i2c_scan) @@ -249,13 +403,10 @@ int cx88_i2c_init(struct cx88_core *core printk("%s: i2c register FAILED\n", core->name); return core->i2c_rc; } - +EXPORT_SYMBOL(cx88_i2c_init); /* ----------------------------------------------------------------------- */ - -EXPORT_SYMBOL(cx88_call_i2c_clients); - /* - * Local variables: - * c-basic-offset: 8 - * End: - */ +* Local variables: +* c-basic-offset: 8 +* End: +*/ diff -r 19981e560c9f linux/drivers/media/video/cx88/cx88-mpeg.c --- a/linux/drivers/media/video/cx88/cx88-mpeg.c Thu Aug 24 14:08:31 2006 -0700 +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c Thu Aug 24 15:04:06 2006 -0700 @@ -127,7 +127,7 @@ static int cx8802_start_dma(struct cx880 /* enable irqs */ dprintk( 1, "setting the interrupt mask\n" ); - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | MO_INT_TSINT); cx_set(MO_TS_INTMSK, 0x1f0011); #if 0 cx_write(MO_TS_INTMSK, 0x0f0011); @@ -400,7 +400,8 @@ static irqreturn_t cx8802_irq(int irq, v int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04); + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | MO_INT_TSINT); + if (0 == status) goto out; dprintk( 1, "cx8802_irq\n" ); @@ -410,10 +411,10 @@ static irqreturn_t cx8802_irq(int irq, v cx_write(MO_PCI_INTSTAT, status); if (status & core->pci_irqmask) - cx88_core_irq(core,status); - if (status & 0x04) + cx88_core_irq(core, status); + if (status & MO_INT_TSINT) cx8802_mpeg_irq(dev); - }; + } if (MAX_IRQ_LOOP == loop) { dprintk( 0, "clearing mask\n" ); printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", @@ -475,8 +476,11 @@ int cx8802_init_common(struct cx8802_dev } cx_set(MO_PCI_INTMSK, core->pci_irqmask); + /* init */ + cx88_devs_init(core, dev->pci); /* everything worked */ pci_set_drvdata(dev->pci,dev); + return 0; } diff -r 19981e560c9f linux/drivers/media/video/cx88/cx88-reg.h --- a/linux/drivers/media/video/cx88/cx88-reg.h Thu Aug 24 14:08:31 2006 -0700 +++ b/linux/drivers/media/video/cx88/cx88-reg.h Thu Aug 24 15:04:06 2006 -0700 @@ -6,6 +6,7 @@ 2001 Michael Eskin 2002 Yurij Sysoev 2003 Gerd Knorr + Copyright (C) 2006 Manu Abraham 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 @@ -76,8 +77,20 @@ #define MO_PDMA_DCNTRL 0x20001C // Destination control #define MO_LD_SSID 0x200030 // Load subsystem ID #define MO_DEV_CNTRL2 0x200034 // Device control + #define MO_PCI_INTMSK 0x200040 // PCI interrupt mask #define MO_PCI_INTSTAT 0x200044 // PCI interrupt status +#define MO_INT_I2CRACK (1 << 17) +#define MO_INT_I2CDONE (1 << 16) +#define MO_INT_DSTDMAINT (1 << 7) +#define MO_INT_SRCDMAINT (1 << 6) +#define MO_INT_TM1INT (1 << 5) +#define MO_INT_HSTINT (1 << 4) +#define MO_INT_VIPINT (1 << 3) +#define MO_INT_TSINT (1 << 2) +#define MO_INT_AUDINT (1 << 1) +#define MO_INT_VIDINT (1 << 0) + #define MO_PCI_INTMSTAT 0x200048 // PCI interrupt masked status #define MO_VID_INTMSK 0x200050 // Video interrupt mask #define MO_VID_INTSTAT 0x200054 // Video interrupt status @@ -514,12 +527,22 @@ /* i2c bus registers */ #define MO_I2C 0x368000 // I2C data/control -#define MO_I2C_DIV (0xf<<4) +#define MO_I2C_DB0 (0xff<<24) +#define MO_I2C_DB1 (0xff<<16) +#define MO_I2C_DB2 (0xff<<8) +#define MO_I2C_MODE (1<<7) +#define MO_I2C_RATE (1<<6) +#define MO_I2C_NOSTOP (1<<5) +#define MO_I2C_NOS1B (1<<4) #define MO_I2C_SYNC (1<<3) -#define MO_I2C_W3B (1<<2) +#define MO_I2C_W3BRA (1<<2) #define MO_I2C_SCL (1<<1) #define MO_I2C_SDA (1<<0) +enum cx88_i2crate { + CX88_I2CRATE_LOW, + CX88_I2CRATE_HIGH, +}; /* ---------------------------------------------------------------------- */ /* general purpose host registers */ @@ -576,7 +599,7 @@ #define RISC_CNT_INC 0x00010000 #define RISC_CNT_RSVR 0x00020000 #define RISC_CNT_RESET 0x00030000 -#define RISC_JMP_SRP 0x01 +#define RISC_JMP_SRP 0x01 /* ---------------------------------------------------------------------- */ diff -r 19981e560c9f linux/drivers/media/video/cx88/cx88-video.c --- a/linux/drivers/media/video/cx88/cx88-video.c Thu Aug 24 14:08:31 2006 -0700 +++ b/linux/drivers/media/video/cx88/cx88-video.c Thu Aug 24 15:04:06 2006 -0700 @@ -2039,17 +2039,18 @@ static irqreturn_t cx8800_irq(int irq, v int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01); + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | MO_INT_VIDINT); + if (0 == status) goto out; cx_write(MO_PCI_INTSTAT, status); handled = 1; if (status & core->pci_irqmask) - cx88_core_irq(core,status); - if (status & 0x01) + cx88_core_irq(core, status); + if (status & MO_INT_VIDINT) cx8800_vid_irq(dev); - }; + } if (10 == loop) { printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", core->name); @@ -2219,6 +2220,8 @@ static int __devinit cx8800_initdev(stru } cx_set(MO_PCI_INTMSK, core->pci_irqmask); + /* I2C Initialization */ + cx88_devs_init(core, pci_dev); /* load and configure helper modules */ if (TUNER_ABSENT != core->tuner_type) request_module("tuner"); @@ -2310,6 +2313,7 @@ static void __devexit cx8800_finidev(str pci_disable_device(pci_dev); /* unregister stuff */ + i2c_del_adapter(&core->i2c_adap); free_irq(pci_dev->irq, dev); cx8800_unregister_video(dev); diff -r 19981e560c9f linux/drivers/media/video/cx88/cx88.h --- a/linux/drivers/media/video/cx88/cx88.h Thu Aug 24 14:08:31 2006 -0700 +++ b/linux/drivers/media/video/cx88/cx88.h Thu Aug 24 15:04:06 2006 -0700 @@ -239,6 +239,8 @@ struct cx88_board { struct cx88_input radio; unsigned int blackbird:1; unsigned int dvb:1; + unsigned int hw_i2c; + enum cx88_i2crate i2c_rate; }; struct cx88_subid { @@ -319,7 +321,7 @@ struct cx88_core { #ifdef HAVE_VIDEO_BUF_DVB struct dvb_pll_desc *pll_desc; unsigned int pll_addr; - int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); #endif /* state info */ @@ -345,6 +347,12 @@ struct cx88_core { /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ struct cx8802_dev *dvbdev; + + u32 int_status; + wait_queue_head_t i2c_wq; + enum cx88_i2crate tx_rate; + u32 i2c_hw; + int initialized; }; struct cx8800_dev; @@ -638,6 +646,7 @@ extern int cx88_do_ioctl(struct inode *i void *arg, v4l2_kioctl driver_ioctl); extern const u32 cx88_user_ctrls[]; extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl); +extern void cx88_devs_init(struct cx88_core *core, struct pci_dev *pci); /* * Local variables: