static inline void i2c_set_status(struct saa7134_dev *dev, enum i2c_status status) { d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name, str_i2c_status[status]); saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status); }
static int tda7432_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) { struct tda7432 *t; struct i2c_client *client; d2printk("tda7432: In tda7432_attach\n"); t = kmalloc(sizeof *t,GFP_KERNEL); if (!t) return -ENOMEM; memset(t,0,sizeof *t); client = &t->c; memcpy(client,&client_template,sizeof(struct i2c_client)); client->adapter = adap; client->addr = addr; client->data = t; do_tda7432_init(client); MOD_INC_USE_COUNT; strcpy(client->name,"TDA7432"); printk(KERN_INFO "tda7432: init\n"); i2c_attach_client(client); return 0; }
static int tda7432_set(struct i2c_client *client) { struct tda7432 *t = client->data; unsigned char buf[16]; d2printk("tda7432: In tda7432_set\n"); dprintk(KERN_INFO "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud); buf[0] = TDA7432_IN; buf[1] = t->input; buf[2] = t->volume; buf[3] = t->bass; buf[4] = t->treble; buf[5] = t->lf; buf[6] = t->lr; buf[7] = t->rf; buf[8] = t->rr; buf[9] = t->loud; if (10 != i2c_master_send(client,buf,10)) { printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n"); return -1; } return 0; }
static inline int i2c_send_byte(struct saa7134_dev *dev, enum i2c_attr attr, unsigned char data) { enum i2c_status status; __u32 dword; /* have to write both attr + data in one 32bit word */ dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2); dword &= 0x0f; dword |= (attr << 6); dword |= ((__u32)data << 8); dword |= 0x00 << 16; /* 100 kHz */ // dword |= 0x40 << 16; /* 400 kHz */ dword |= 0xf0 << 24; saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); if (!i2c_is_busy_wait(dev)) return -EIO; status = i2c_get_status(dev); if (i2c_is_error(status)) return -EIO; return 0; }
static int i2c_reset(struct saa7134_dev *dev) { enum i2c_status status; int count; d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name); status = i2c_get_status(dev); if (!i2c_is_error(status)) return TRUE; i2c_set_status(dev,status); for (count = 0; count < I2C_WAIT_RETRY; count++) { status = i2c_get_status(dev); if (!i2c_is_error(status)) break; udelay(I2C_WAIT_DELAY); } if (I2C_WAIT_RETRY == count) return FALSE; if (!i2c_is_idle(status)) return FALSE; i2c_set_attr(dev,NOP); return TRUE; }
static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev) { enum i2c_status status; status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f; d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name, str_i2c_status[status]); return status; }
static int tda7432_read(struct i2c_client *client) { unsigned char buffer; d2printk("tda7432: In tda7432_read\n"); if (1 != i2c_master_recv(client,&buffer,1)) { printk(KERN_WARNING "tda7432: I/O error, trying (read)\n"); return -1; } dprintk("tda7432: Read 0x%02x\n", buffer); return buffer; }
static int tda7432_write(struct i2c_client *client, int subaddr, int val) { unsigned char buffer[2]; d2printk("tda7432: In tda7432_write\n"); dprintk("tda7432: Writing %d 0x%x\n", subaddr, val); buffer[0] = subaddr; buffer[1] = val; if (2 != i2c_master_send(client,buffer,2)) { printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n", subaddr, val); return -1; } return 0; }
static inline int i2c_recv_byte(struct saa7134_dev *dev) { enum i2c_status status; unsigned char data; i2c_set_attr(dev,CONTINUE); if (!i2c_is_busy_wait(dev)) return -EIO; status = i2c_get_status(dev); if (i2c_is_error(status)) return -EIO; data = saa_readb(SAA7134_I2C_DATA); d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data); return data; }
static void do_tda7432_init(struct i2c_client *client) { struct tda7432 *t = client->data; d2printk("tda7432: In tda7432_init\n"); t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ TDA7432_BASS_SYM | /* Symmetric bass cut */ TDA7432_BASS_NORM; /* Normal bass range */ t->volume = 0x3b ; /* -27dB Volume */ if (loudness) /* Turn loudness on? */ t->volume |= TDA7432_LD_ON; t->muted = VIDEO_AUDIO_MUTE; t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ t->loud = loudness; /* insmod parameter */ tda7432_set(client); }
static int tda7432_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tda7432 *t = client->data; d2printk("tda7432: In tda7432_command\n"); switch (cmd) { /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ /* Query card - scale from TDA7432 settings to V4L settings */ case VIDIOCGAUDIO: { struct video_audio *va = arg; dprintk("tda7432: VIDIOCGAUDIO\n"); va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE | VIDEO_AUDIO_MUTABLE; if (t->muted) va->flags |= VIDEO_AUDIO_MUTE; va->mode |= VIDEO_SOUND_STEREO; /* Master volume control * V4L volume is min 0, max 65535 * TDA7432 Volume: * Min (-79dB) is 0x6f * Max (+20dB) is 0x07 (630) * Max (0dB) is 0x20 (829) * (Mask out bit 7 of vol - it's for the loudness setting) */ if (!maxvol){ /* max +20db */ va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; } else { /* max 0db */ va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829; } /* Balance depends on L,R attenuation * V4L balance is 0 to 65535, middle is 32768 * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f * to scale up to V4L numbers, mult by 1057 * attenuation exists for lf, lr, rf, rr * we use only lf and rf (front channels) */ if ( (t->lf) < (t->rf) ) /* right is attenuated, balance shifted left */ va->balance = (32768 - 1057*(t->rf)); else /* left is attenuated, balance shifted right */ va->balance = (32768 + 1057*(t->lf)); /* Bass/treble 4 bits each */ va->bass=t->bass; if(va->bass >= 0x8) va->bass = ~(va->bass - 0x8) & 0xf; va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass); va->treble=t->treble; if(va->treble >= 0x8) va->treble = ~(va->treble - 0x8) & 0xf; va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble); break; /* VIDIOCGAUDIO case */ } /* Set card - scale from V4L settings to TDA7432 settings */ case VIDIOCSAUDIO: { struct video_audio *va = arg; dprintk("tda7432: VIDEOCSAUDIO\n"); if(va->flags & VIDEO_AUDIO_VOLUME){ if(!maxvol){ /* max +20db */ t->volume = 0x6f - ((va->volume)/630); } else { /* max 0db */ t->volume = 0x6f - ((va->volume)/829); } if (loudness) /* Turn on the loudness bit */ t->volume |= TDA7432_LD_ON; tda7432_write(client,TDA7432_VL, t->volume); } if(va->flags & VIDEO_AUDIO_BASS) { t->bass = va->bass >> 12; if(t->bass>= 0x8) t->bass = (~t->bass & 0xf) + 0x8 ; } if(va->flags & VIDEO_AUDIO_TREBLE) { t->treble= va->treble >> 12; if(t->treble>= 0x8) t->treble = (~t->treble & 0xf) + 0x8 ; } if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS)) tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); if(va->flags & VIDEO_AUDIO_BALANCE) { if (va->balance < 32768) { /* shifted to left, attenuate right */ t->rr = (32768 - va->balance)/1057; t->rf = t->rr; t->lr = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; } else if(va->balance > 32769) { /* shifted to right, attenuate left */ t->lf = (va->balance - 32768)/1057; t->lr = t->lf; t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; } else { /* centered */ t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; t->lr = TDA7432_ATTEN_0DB; } } t->muted=(va->flags & VIDEO_AUDIO_MUTE); if (t->muted) { /* Mute & update balance*/ tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); } else { tda7432_write(client,TDA7432_LF, t->lf); tda7432_write(client,TDA7432_LR, t->lr); tda7432_write(client,TDA7432_RF, t->rf); tda7432_write(client,TDA7432_RR, t->rr); } break; } /* end of VIDEOCSAUDIO case */
static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct saa7134_dev *dev = i2c_adap->algo_data; enum i2c_status status; unsigned char data; int addr,rc,i,byte; status = i2c_get_status(dev); if (!i2c_is_idle(status)) if (!i2c_reset(dev)) return -EIO; d2printk("start xfer\n"); d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); for (i = 0; i < num; i++) { if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { /* send address */ d2printk("send address\n"); addr = msgs[i].addr << 1; if (msgs[i].flags & I2C_M_RD) addr |= 1; if (i > 0 && msgs[i].flags & I2C_M_RD) { /* workaround for a saa7134 i2c bug * needed to talk to the mt352 demux * thanks to pinnacle for the hint */ int quirk = 0xfd; d1printk(" [%02x quirk]",quirk); i2c_send_byte(dev,START,quirk); i2c_recv_byte(dev); } d1printk(" < %02x", addr); rc = i2c_send_byte(dev,START,addr); if (rc < 0) goto err; } if (msgs[i].flags & I2C_M_RD) { /* read bytes */ d2printk("read bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { d1printk(" ="); rc = i2c_recv_byte(dev); if (rc < 0) goto err; d1printk("%02x", rc); msgs[i].buf[byte] = rc; } } else { /* write bytes */ d2printk("write bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { data = msgs[i].buf[byte]; d1printk(" %02x", data); rc = i2c_send_byte(dev,CONTINUE,data); if (rc < 0) goto err; } } } d2printk("xfer done\n"); d1printk(" >"); i2c_set_attr(dev,STOP); rc = -EIO; if (!i2c_is_busy_wait(dev)) goto err; status = i2c_get_status(dev); if (i2c_is_error(status)) goto err; /* ensure that the bus is idle for at least one bit slot */ msleep(1); d1printk("\n"); return num; err: if (1 == i2c_debug) { status = i2c_get_status(dev); printk(" ERROR: %s\n",str_i2c_status[status]); } return rc; }
static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr) { d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name, str_i2c_attr[attr]); saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6); }
static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct saa7134_dev *dev = i2c_adap->algo_data; enum i2c_status status; unsigned char data; int addr,rc,i,byte; status = i2c_get_status(dev); if (!i2c_is_idle(status)) if (!i2c_reset(dev)) return -EIO; d2printk("start xfer\n"); d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); for (i = 0; i < num; i++) { if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { d2printk("send address\n"); addr = msgs[i].addr << 1; if (msgs[i].flags & I2C_M_RD) addr |= 1; if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40 && msgs[i].addr != 0x19) { int quirk = 0xfe; d1printk(" [%02x quirk]",quirk); i2c_send_byte(dev,START,quirk); i2c_recv_byte(dev); } d1printk(" < %02x", addr); rc = i2c_send_byte(dev,START,addr); if (rc < 0) goto err; } if (msgs[i].flags & I2C_M_RD) { d2printk("read bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { d1printk(" ="); rc = i2c_recv_byte(dev); if (rc < 0) goto err; d1printk("%02x", rc); msgs[i].buf[byte] = rc; } if (0x19 == msgs[i].addr) { d1printk(" ?"); rc = i2c_recv_byte(dev); if (rc < 0) goto err; d1printk("%02x", rc); } } else { d2printk("write bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { data = msgs[i].buf[byte]; d1printk(" %02x", data); rc = i2c_send_byte(dev,CONTINUE,data); if (rc < 0) goto err; } } } d2printk("xfer done\n"); d1printk(" >"); i2c_set_attr(dev,STOP); rc = -EIO; if (!i2c_is_busy_wait(dev)) goto err; status = i2c_get_status(dev); if (i2c_is_error(status)) goto err; msleep(1); d1printk("\n"); return num; err: if (1 == i2c_debug) { status = i2c_get_status(dev); printk(" ERROR: %s\n",str_i2c_status[status]); } return rc; }