static int solo_disp_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { struct solo_filehandle *fh = priv; struct solo6010_dev *solo_dev = fh->solo_dev; switch (ctrl->id) { case V4L2_CID_MOTION_TRACE: if (ctrl->value) { solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, SOLO_VI_MOTION_Y_ADD | SOLO_VI_MOTION_Y_VALUE(0x20) | SOLO_VI_MOTION_CB_VALUE(0x10) | SOLO_VI_MOTION_CR_VALUE(0x10)); solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, SOLO_VI_MOTION_CR_ADD | SOLO_VI_MOTION_Y_VALUE(0x10) | SOLO_VI_MOTION_CB_VALUE(0x80) | SOLO_VI_MOTION_CR_VALUE(0x10)); } else { solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); } return 0; } return -EINVAL; }
int solo_p2m_init(struct solo6010_dev *solo_dev) { struct solo_p2m_dev *p2m_dev; int i; for (i = 0; i < SOLO_NR_P2M; i++) { p2m_dev = &solo_dev->p2m_dev[i]; sema_init(&p2m_dev->sem, 1); init_completion(&p2m_dev->completion); solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(i), __pa(p2m_dev->desc)); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), SOLO_P2M_CSC_16BIT_565 | SOLO_P2M_DMA_INTERVAL(0) | SOLO_P2M_PCI_MASTER_MODE); solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i)); } run_p2m_test(solo_dev); return 0; }
static int solo_s_ctrl(struct v4l2_ctrl *ctrl) { struct solo_dev *solo_dev = container_of(ctrl->handler, struct solo_dev, disp_hdl); switch (ctrl->id) { case V4L2_CID_MOTION_TRACE: if (ctrl->val) { solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, SOLO_VI_MOTION_Y_ADD | SOLO_VI_MOTION_Y_VALUE(0x20) | SOLO_VI_MOTION_CB_VALUE(0x10) | SOLO_VI_MOTION_CR_VALUE(0x10)); solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, SOLO_VI_MOTION_CR_ADD | SOLO_VI_MOTION_Y_VALUE(0x10) | SOLO_VI_MOTION_CB_VALUE(0x80) | SOLO_VI_MOTION_CR_VALUE(0x10)); } else { solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); } return 0; default: break; } return -EINVAL; }
static void solo_gpio_mode(struct solo_dev *solo_dev, unsigned int port_mask, unsigned int mode) { int port; unsigned int ret; ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0); /* To set gpio */ for (port = 0; port < 16; port++) { if (!((1 << port) & port_mask)) continue; ret &= (~(3 << (port << 1))); ret |= ((mode & 3) << (port << 1)); } solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret); /* To set extended gpio - sensor */ ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); for (port = 0; port < 16; port++) { if (!((1 << (port + 16)) & port_mask)) continue; if (!mode) ret &= ~(1 << port); else ret |= 1 << port; } solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret); }
static void solo_set_time(struct solo6010_dev *solo_dev) { struct timeval tv; do_gettimeofday(&tv); solo_reg_write(solo_dev, SOLO_TIMER_SEC, tv.tv_sec); solo_reg_write(solo_dev, SOLO_TIMER_USEC, tv.tv_usec); }
static void solo_set_time(struct solo6010_dev *solo_dev) { struct timespec ts; ktime_get_ts(&ts); solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec); solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC); }
static void set_qp(struct solo_enc_dev *solo_enc, int qp) { u8 ch = solo_enc->ch; struct solo6010_dev *solo_dev = solo_enc->solo_dev; solo_enc->qp = qp; solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp); /* Extended encoding only */ solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp); }
/* Mutex must be held for p2m_id before calling this!! */ int solo_p2m_dma_desc(struct solo6010_dev *solo_dev, struct solo_p2m_desc *desc, dma_addr_t desc_dma, int desc_cnt) { struct solo_p2m_dev *p2m_dev; unsigned int timeout = 0; unsigned int config = 0; int ret = 0; int p2m_id; /* Get next ID */ p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; if (p2m_id < 0) p2m_id = 0 - p2m_id; p2m_dev = &solo_dev->p2m_dev[p2m_id]; if (mutex_lock_interruptible(&p2m_dev->mutex)) return -EINTR; INIT_COMPLETION(p2m_dev->completion); p2m_dev->error = 0; if (desc_cnt > 1) { /* We only need to do this when we have more than one * descriptor. */ config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id)); solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma); solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt); solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config | SOLO_P2M_DESC_MODE); } else { solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id), desc[1].dma_addr); solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id), desc[1].ext_addr); solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id), desc[1].cfg); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), desc[1].ctrl); } timeout = wait_for_completion_timeout(&p2m_dev->completion, msecs_to_jiffies(solo_dev->p2m_msecs)); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0); if (desc_cnt > 1) solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config); if (WARN_ON_ONCE(p2m_dev->error)) ret = -EIO; else if (timeout == 0) ret = -EAGAIN; mutex_unlock(&p2m_dev->mutex); return ret; }
static void solo_i2c_stop(struct solo_dev *solo_dev) { solo_irq_off(solo_dev, SOLO_IRQ_IIC); solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); solo_dev->i2c_state = IIC_STATE_STOP; wake_up(&solo_dev->i2c_wait); }
static int solo_i2c_handle_write(struct solo_dev *solo_dev) { retry_write: if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) { solo_reg_write(solo_dev, SOLO_IIC_TXD, solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]); solo_dev->i2c_msg_ptr++; solo_i2c_flush(solo_dev, 1); return 0; } solo_dev->i2c_msg_ptr = 0; solo_dev->i2c_msg++; solo_dev->i2c_msg_num--; if (solo_dev->i2c_msg_num == 0) { solo_i2c_stop(solo_dev); return 0; } if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) { solo_i2c_start(solo_dev); } else { if (solo_dev->i2c_msg->flags & I2C_M_RD) solo_i2c_stop(solo_dev); else goto retry_write; } return 0; }
static void solo_win_setup(struct solo6010_dev *solo_dev, u8 ch, int sx, int sy, int ex, int ey, int scale) { if (ch >= solo_dev->nr_chans) return; /* Here, we just keep window/channel the same */ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch), SOLO_VI_WIN_CHANNEL(ch) | SOLO_VI_WIN_SX(sx) | SOLO_VI_WIN_EX(ex) | SOLO_VI_WIN_SCALE(scale)); solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch), SOLO_VI_WIN_SY(sy) | SOLO_VI_WIN_EY(ey)); }
/* XXX We should check the return value of the sub-device ISR's */ static irqreturn_t solo_isr(int irq, void *data) { struct solo_dev *solo_dev = data; u32 status; int i; status = solo_reg_read(solo_dev, SOLO_IRQ_STAT); if (!status) return IRQ_NONE; if (status & ~solo_dev->irq_mask) { solo_reg_write(solo_dev, SOLO_IRQ_STAT, status & ~solo_dev->irq_mask); status &= solo_dev->irq_mask; } if (status & SOLO_IRQ_PCI_ERR) { u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR); solo_p2m_error_isr(solo_dev, err); solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR); } for (i = 0; i < SOLO_NR_P2M; i++) if (status & SOLO_IRQ_P2M(i)) solo_p2m_isr(solo_dev, i); if (status & SOLO_IRQ_IIC) solo_i2c_isr(solo_dev); if (status & SOLO_IRQ_VIDEO_IN) solo_video_in_isr(solo_dev); /* Call this first so enc gets detected flag set */ if (status & SOLO_IRQ_MOTION) solo_motion_isr(solo_dev); if (status & SOLO_IRQ_ENCODER) solo_enc_v4l2_isr(solo_dev); if (status & SOLO_IRQ_G723) solo_g723_isr(solo_dev); return IRQ_HANDLED; }
static irqreturn_t solo6010_isr(int irq, void *data) { struct solo6010_dev *solo_dev = data; u32 status; int i; status = solo_reg_read(solo_dev, SOLO_IRQ_STAT); if (!status) return IRQ_NONE; if (status & ~solo_dev->irq_mask) { solo_reg_write(solo_dev, SOLO_IRQ_STAT, status & ~solo_dev->irq_mask); status &= solo_dev->irq_mask; } if (status & SOLO_IRQ_PCI_ERR) solo_p2m_error_isr(solo_dev); for (i = 0; i < SOLO_NR_P2M; i++) if (status & SOLO_IRQ_P2M(i)) solo_p2m_isr(solo_dev, i); if (status & SOLO_IRQ_IIC) solo_i2c_isr(solo_dev); if (status & SOLO_IRQ_VIDEO_IN) { solo_video_in_isr(solo_dev); solo_timer_sync(solo_dev); } if (status & SOLO_IRQ_ENCODER) solo_enc_v4l2_isr(solo_dev); if (status & SOLO_IRQ_G723) solo_g723_isr(solo_dev); /* Clear all interrupts handled */ solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); return IRQ_HANDLED; }
static void solo_i2c_start(struct solo_dev *solo_dev) { u32 addr = solo_dev->i2c_msg->addr << 1; if (solo_dev->i2c_msg->flags & I2C_M_RD) addr |= 1; solo_dev->i2c_state = IIC_STATE_START; solo_reg_write(solo_dev, SOLO_IIC_TXD, addr); solo_i2c_flush(solo_dev, 1); }
static int solo_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct solo_dev *solo_dev = adap->algo_data; unsigned long timeout; int ret; int i; DEFINE_WAIT(wait); for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { if (&solo_dev->i2c_adap[i] == adap) break; } if (i == SOLO_I2C_ADAPTERS) return num; /* XXX Right return value for failure? */ mutex_lock(&solo_dev->i2c_mutex); solo_dev->i2c_id = i; solo_dev->i2c_msg = msgs; solo_dev->i2c_msg_num = num; solo_dev->i2c_msg_ptr = 0; solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); solo_irq_on(solo_dev, SOLO_IRQ_IIC); solo_i2c_start(solo_dev); timeout = HZ / 2; for (;;) { prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE); if (solo_dev->i2c_state == IIC_STATE_STOP) break; timeout = schedule_timeout(timeout); if (!timeout) break; if (signal_pending(current)) break; } finish_wait(&solo_dev->i2c_wait, &wait); ret = num - solo_dev->i2c_msg_num; solo_dev->i2c_state = IIC_STATE_IDLE; solo_dev->i2c_id = -1; mutex_unlock(&solo_dev->i2c_mutex); return ret; }
int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr, dma_addr_t dma_addr, u32 ext_addr, u32 size) { struct solo_p2m_dev *p2m_dev; unsigned int timeout = 0; WARN_ON(!size); WARN_ON(id >= SOLO_NR_P2M); if (!size || id >= SOLO_NR_P2M) return -EINVAL; p2m_dev = &solo_dev->p2m_dev[id]; down(&p2m_dev->sem); start_dma: INIT_COMPLETION(p2m_dev->completion); p2m_dev->error = 0; solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), dma_addr); solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), ext_addr); solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), SOLO_P2M_COPY_SIZE(size >> 2)); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON); timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); /* XXX Really looks to me like we will get stuck here if a * real PCI P2M error occurs */ if (p2m_dev->error) goto start_dma; up(&p2m_dev->sem); return (timeout == 0) ? -EAGAIN : 0; }
static int erase_off(struct solo6010_dev *solo_dev) { if (!solo_dev->erasing) return 0; /* First time around, assert erase off */ if (!solo_dev->frame_blank) solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0); /* Keep the erasing flag on for 8 frames minimum */ if (solo_dev->frame_blank++ >= 8) solo_dev->erasing = 0; return 1; }
void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status) { struct solo_p2m_dev *p2m_dev; int i; if (!(status & SOLO_PCI_ERR_P2M)) return; for (i = 0; i < SOLO_NR_P2M; i++) { p2m_dev = &solo_dev->p2m_dev[i]; p2m_dev->error = 1; solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); complete(&p2m_dev->completion); } }
int solo_i2c_init(struct solo6010_dev *solo_dev) { int i; int ret; solo_reg_write(solo_dev, SOLO_IIC_CFG, SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE); solo_dev->i2c_id = -1; solo_dev->i2c_state = IIC_STATE_IDLE; init_waitqueue_head(&solo_dev->i2c_wait); init_MUTEX(&solo_dev->i2c_sem); for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", SOLO6010_NAME, i); adap->algo = &solo_i2c_algo; adap->algo_data = solo_dev; adap->retries = 1; adap->dev.parent = &solo_dev->pdev->dev; if ((ret = i2c_add_adapter(adap))) { adap->algo_data = NULL; break; } } if (ret) { for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { if (!solo_dev->i2c_adap[i].algo_data) break; i2c_del_adapter(&solo_dev->i2c_adap[i]); solo_dev->i2c_adap[i].algo_data = NULL; } return ret; } dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n", SOLO_I2C_ADAPTERS); return 0; }
int solo_i2c_isr(struct solo6010_dev *solo_dev) { u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); int ret = -EINVAL; solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC); if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) || solo_dev->i2c_id < 0) { solo_i2c_stop(solo_dev); return -ENXIO; } switch (solo_dev->i2c_state) { case IIC_STATE_START: if (solo_dev->i2c_msg->flags & I2C_M_RD) { solo_dev->i2c_state = IIC_STATE_READ; ret = solo_i2c_handle_read(solo_dev); break; } solo_dev->i2c_state = IIC_STATE_WRITE; case IIC_STATE_WRITE: ret = solo_i2c_handle_write(solo_dev); break; case IIC_STATE_READ: solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] = solo_reg_read(solo_dev, SOLO_IIC_RXD); solo_dev->i2c_msg_ptr++; ret = solo_i2c_handle_read(solo_dev); break; default: solo_i2c_stop(solo_dev); } return ret; }
static void solo_timer_sync(struct solo6010_dev *solo_dev) { u32 sec, usec; struct timespec ts; long diff; if (solo_dev->type != SOLO_DEV_6110) return; if (++solo_dev->time_sync < 60) return; solo_dev->time_sync = 0; sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC); usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC); ktime_get_ts(&ts); diff = (long)ts.tv_sec - (long)sec; diff = (diff * 1000000) + ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec); if (diff > 1000 || diff < -1000) { solo_set_time(solo_dev); } else if (diff) { long usec_lsb = solo_dev->usec_lsb; usec_lsb -= diff / 4; if (usec_lsb < 0) usec_lsb = 0; else if (usec_lsb > 255) usec_lsb = 255; solo_dev->usec_lsb = usec_lsb; solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, solo_dev->usec_lsb); } }
static void solo_i2c_flush(struct solo_dev *solo_dev, int wr) { u32 ctrl; ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id); if (solo_dev->i2c_state == IIC_STATE_START) ctrl |= SOLO_IIC_START; if (wr) { ctrl |= SOLO_IIC_WRITE; } else { ctrl |= SOLO_IIC_READ; if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK)) ctrl |= SOLO_IIC_ACK_EN; } if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len) ctrl |= SOLO_IIC_STOP; solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl); }
static void solo_timer_sync(struct solo6010_dev *solo_dev) { u32 sec, usec; struct timeval tv; long diff; if (solo_dev->type != SOLO_DEV_6110) return; solo_dev->time_sync++; if (solo_dev->time_sync % 60) return; sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC); usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC); do_gettimeofday(&tv); diff = (long)tv.tv_sec - (long)sec; diff = (diff * 1000000) + ((long)tv.tv_usec - (long)usec); if (diff > 1000 || diff < -1000) { solo_set_time(solo_dev); } else if (diff) { long usec_lsb = solo_dev->usec_lsb; usec_lsb -= diff / 4; if (usec_lsb < 0) usec_lsb = 0; else if (usec_lsb > 255) usec_lsb = 255; solo_dev->usec_lsb = usec_lsb; solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, solo_dev->usec_lsb); } }
static int __devinit solo6010_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct solo6010_dev *solo_dev; int ret; u8 chip_id; solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); if (solo_dev == NULL) return -ENOMEM; if (id->driver_data == SOLO_DEV_6010) dev_info(&pdev->dev, "Probing Softlogic 6010\n"); else dev_info(&pdev->dev, "Probing Softlogic 6110\n"); solo_dev->type = id->driver_data; solo_dev->pdev = pdev; spin_lock_init(&solo_dev->reg_io_lock); pci_set_drvdata(pdev, solo_dev); solo_dev->p2m_jiffies = msecs_to_jiffies(100); /* Only for during init */ if ((ret = pci_enable_device(pdev))) goto fail_probe; pci_set_master(pdev); /* RETRY/TRDY Timeout disabled */ pci_write_config_byte(pdev, 0x40, 0x00); pci_write_config_byte(pdev, 0x41, 0x00); if ((ret = pci_request_regions(pdev, SOLO6010_NAME))) goto fail_probe; if ((solo_dev->reg_base = pci_ioremap_bar(pdev, 0)) == NULL) { ret = -ENOMEM; goto fail_probe; } chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & SOLO_CHIP_ID_MASK; switch (chip_id) { case 7: solo_dev->nr_chans = 16; solo_dev->nr_ext = 5; break; case 6: solo_dev->nr_chans = 8; solo_dev->nr_ext = 2; break; default: dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, " "defaulting to 4 channels\n", chip_id); case 5: solo_dev->nr_chans = 4; solo_dev->nr_ext = 1; } /* Disable all interrupts to start */ solo6010_irq_off(solo_dev, ~0); /* Initial global settings */ if (solo_dev->type == SOLO_DEV_6010) { solo_dev->clock_mhz = 108; solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT | SOLO_SYS_CFG_INPUTDIV(25) | SOLO_SYS_CFG_FEEDBACKDIV((solo_dev->clock_mhz * 2) - 2) | SOLO_SYS_CFG_OUTDIV(3)); } else { u32 divq, divf; solo_dev->clock_mhz = 135; if (solo_dev->clock_mhz < 125) { divq = 3; divf = (solo_dev->clock_mhz * 4) / 3 - 1; } else { divq = 2; divf = (solo_dev->clock_mhz * 2) / 3 - 1; } solo_reg_write(solo_dev, SOLO_PLL_CONFIG, (1 << 20) | /* PLL_RANGE */ (8 << 15) | /* PLL_DIVR */ (divq << 12 ) | (divf << 4 ) | (1 << 1) /* PLL_FSEN */ ); solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT); } solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, solo_dev->clock_mhz - 1); /* PLL locking time of 1ms */ mdelay(1); ret = request_irq(pdev->irq, solo6010_isr, IRQF_SHARED, SOLO6010_NAME, solo_dev); if (ret) goto fail_probe; /* Handle this from the start */ solo6010_irq_on(solo_dev, SOLO_IRQ_PCI_ERR); if ((ret = solo_i2c_init(solo_dev))) goto fail_probe; /* Setup the DMA engine */ solo_reg_write(solo_dev, SOLO_DMA_CTRL, SOLO_DMA_CTRL_REFRESH_CYCLE(1) | SOLO_DMA_CTRL_SDRAM_SIZE(2) | SOLO_DMA_CTRL_SDRAM_CLK_INVERT | SOLO_DMA_CTRL_READ_CLK_SELECT | SOLO_DMA_CTRL_LATENCY(1)); /* Undocumented crap */ if (solo_dev->type == SOLO_DEV_6010) { solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); } else { solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); solo_dev->usec_lsb = 0x3f; solo_set_time(solo_dev); } /* Disable watchdog */ solo_reg_write(solo_dev, SOLO_TIMER_WATCHDOG, 0xff); /* Initialize sub components */ if ((ret = solo_p2m_init(solo_dev))) goto fail_probe; if ((ret = solo_disp_init(solo_dev))) goto fail_probe; if ((ret = solo_gpio_init(solo_dev))) goto fail_probe; if ((ret = solo_tw28_init(solo_dev))) goto fail_probe; if ((ret = solo_v4l2_init(solo_dev))) goto fail_probe; if ((ret = solo_enc_init(solo_dev))) goto fail_probe; if ((ret = solo_enc_v4l2_init(solo_dev))) goto fail_probe; if ((ret = solo_g723_init(solo_dev))) goto fail_probe; if ((ret = solo_sysfs_init(solo_dev))) goto fail_probe; /* Now that init is over, set this lower */ solo_dev->p2m_jiffies = msecs_to_jiffies(50); return 0; fail_probe: free_solo_dev(solo_dev); return ret; }
void solo_video_in_isr(struct solo6010_dev *solo_dev) { solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN); wake_up_interruptible(&solo_dev->disp_thread_wait); }
static void erase_on(struct solo6010_dev *solo_dev) { solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); solo_dev->erasing = 1; solo_dev->frame_blank = 0; }
void solo_irq_on(struct solo_dev *solo_dev, u32 mask) { solo_dev->irq_mask |= mask; solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); }
void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask) { solo_dev->irq_mask &= ~mask; solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); }
void solo_p2m_isr(struct solo6010_dev *solo_dev, int id) { solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id)); complete(&solo_dev->p2m_dev[id].completion); }
static void solo_eeprom_reg_write(struct solo6010_dev *solo_dev, u32 data) { solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data); eeprom_delay(); }