static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr, u8 reg, u8 *value) { int rc; /* Set serial device address */ rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); if (rc < 0) return rc; /* Set i2c device register sub-address */ rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg); if (rc < 0) return rc; /* Start read now */ rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); if (rc < 0) return rc; rc = stk1160_i2c_busy_wait(dev, 0x01); if (rc < 0) return rc; stk1160_read_reg(dev, STK1160_SBUSR_RD, value); if (rc < 0) return rc; return 0; }
/* * stk1160_i2c_register() * register i2c bus */ int stk1160_i2c_register(struct stk1160 *dev) { int rc; dev->i2c_adap = adap_template; dev->i2c_adap.dev.parent = dev->dev; strcpy(dev->i2c_adap.name, "stk1160"); dev->i2c_adap.algo_data = dev; i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); rc = i2c_add_adapter(&dev->i2c_adap); if (rc < 0) { stk1160_err("cannot add i2c adapter (%d)\n", rc); return rc; } dev->i2c_client = client_template; dev->i2c_client.adapter = &dev->i2c_adap; /* Set i2c clock divider device address */ stk1160_write_reg(dev, STK1160_SICTL_CD, 0x0f); /* ??? */ stk1160_write_reg(dev, STK1160_ASIC + 3, 0x00); return 0; }
/* * stk1160_i2c_check_for_device() * check if there is a i2c_device at the supplied address */ static int stk1160_i2c_check_for_device(struct stk1160 *dev, unsigned char addr) { int rc; /* Set serial device address */ rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); if (rc < 0) return rc; /* Set device sub-address, we'll chip version reg */ rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00); if (rc < 0) return rc; /* Start read now */ rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); if (rc < 0) return rc; rc = stk1160_i2c_busy_wait(dev, 0x01); if (rc < 0) return -ENODEV; return 0; }
static void stk1160_set_std(struct stk1160 *dev) { int i; static struct regval std525[] = { /* 720x480 */ /* Frame start */ {STK116_CFSPO_STX_L, 0x0000}, {STK116_CFSPO_STX_H, 0x0000}, {STK116_CFSPO_STY_L, 0x0003}, {STK116_CFSPO_STY_H, 0x0000}, /* Frame end */ {STK116_CFEPO_ENX_L, 0x05a0}, {STK116_CFEPO_ENX_H, 0x0005}, {STK116_CFEPO_ENY_L, 0x00f3}, {STK116_CFEPO_ENY_H, 0x0000}, {0xffff, 0xffff} }; static struct regval std625[] = { /* 720x576 */ /* TODO: Each line of frame has some junk at the end */ /* Frame start */ {STK116_CFSPO, 0x0000}, {STK116_CFSPO+1, 0x0000}, {STK116_CFSPO+2, 0x0001}, {STK116_CFSPO+3, 0x0000}, /* Frame end */ {STK116_CFEPO, 0x05a0}, {STK116_CFEPO+1, 0x0005}, {STK116_CFEPO+2, 0x0121}, {STK116_CFEPO+3, 0x0001}, {0xffff, 0xffff} }; if (dev->norm & V4L2_STD_525_60) { stk1160_dbg("registers to NTSC like standard\n"); for (i = 0; std525[i].reg != 0xffff; i++) stk1160_write_reg(dev, std525[i].reg, std525[i].val); } else { stk1160_dbg("registers to PAL like standard\n"); for (i = 0; std625[i].reg != 0xffff; i++) stk1160_write_reg(dev, std625[i].reg, std625[i].val); } }
static int vidioc_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { struct stk1160 *dev = video_drvdata(file); /* Match host */ return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val)); }
/* Must be called with v4l_lock hold */ static void stk1160_stop_hw(struct stk1160 *dev) { /* If the device is not physically present, there is nothing to do */ if (!dev->udev) return; /* set alternate 0 */ dev->alt = 0; stk1160_info("setting alternate %d\n", dev->alt); usb_set_interface(dev->udev, 0, 0); /* Stop stk1160 */ stk1160_write_reg(dev, STK1160_DCTRL, 0x00); stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00); /* Stop saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); }
static int vidioc_s_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct stk1160 *dev = video_drvdata(file); switch (reg->match.type) { case V4L2_CHIP_MATCH_AC97: return -EINVAL; case V4L2_CHIP_MATCH_I2C_DRIVER: v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); return 0; case V4L2_CHIP_MATCH_I2C_ADDR: /* TODO: is this correct? */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); return 0; default: if (!v4l2_chip_match_host(®->match)) return -EINVAL; } /* Match host */ return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val)); }
static int stk1160_start_streaming(struct stk1160 *dev) { bool new_pkt_size; int rc = 0; int i; /* Check device presence */ if (!dev->udev) return -ENODEV; if (mutex_lock_interruptible(&dev->v4l_lock)) return -ERESTARTSYS; /* * For some reason it is mandatory to set alternate *first* * and only *then* initialize isoc urbs. * Someone please explain me why ;) */ new_pkt_size = stk1160_set_alternate(dev); /* * We (re)allocate isoc urbs if: * there is no allocated isoc urbs, OR * a new dev->max_pkt_size is detected */ if (!dev->isoc_ctl.num_bufs || new_pkt_size) { rc = stk1160_alloc_isoc(dev); if (rc < 0) goto out_stop_hw; } /* submit urbs and enables IRQ */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_KERNEL); if (rc) { stk1160_err("cannot submit urb[%d] (%d)\n", i, rc); goto out_uninit; } } /* Start saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); /* Start stk1160 */ stk1160_write_reg(dev, STK1160_DCTRL, 0xb3); stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00); stk1160_dbg("streaming started\n"); mutex_unlock(&dev->v4l_lock); return 0; out_uninit: stk1160_uninit_isoc(dev); out_stop_hw: usb_set_interface(dev->udev, 0, 0); stk1160_clear_queue(dev); mutex_unlock(&dev->v4l_lock); return rc; }