/** * hp3a_enable_histogram - Enables histogram harware. * * No return value. **/ void hp3a_enable_histogram(void) { struct hp3a_internal_buffer *ibuffer; if (unlikely(g_tc.hist_hw_configured == 0)) return; if (hp3a_dequeue(&g_tc.hist_stat_queue, &ibuffer) == 0) { if (g_tc.hist_hw_enable == 0) { /* Write histogram hardware registers. */ hp3a_write_ispregs(isp_hist_regs); omap_writel(IRQ0STATUS_HIST_DONE_IRQ, ISP_IRQ0STATUS); /* Enable histogram hardware. */ omap_writel(omap_readl(ISPHIST_PCR) | \ (ISPHIST_PCR_EN), ISPHIST_PCR); g_tc.hist_hw_enable = 1; g_tc.hist_done = 0; } ibuffer->type = HISTOGRAM; hp3a_enqueue(&g_tc.hist_hw_queue, &ibuffer); hp3a_enqueue(&g_tc.ready_stats_queue, &ibuffer); } else if (g_tc.hist_hw_enable == 1) { g_tc.hist_hw_enable = 0; omap_writel(omap_readl(ISPHIST_PCR) & \ ~(ISPHIST_PCR_EN), ISPHIST_PCR); } }
/** * hp3a_update_framework- execute tasks between frames. * * No return value. **/ void hp3a_update_stats_pipe_done(void) { struct hp3a_internal_buffer *ibuffer; hp3a_disable_raw(); if (g_tc.v4l2_streaming == 0) return; /* RAW stat buffer processing. */ if (g_tc.raw_hw_configured == 1) { if ((++g_tc.raw_cap_sched_count) == g_tc.raw_frequency) { if (omap_readl(ISPCCDC_PCR) & ISPCCDC_PCR_BUSY) { --g_tc.raw_cap_sched_count; return; } g_tc.raw_cap_sched_count = 0; ibuffer = NULL; if (hp3a_dequeue(&g_tc.raw_frame_queue, &ibuffer) == 0) { if (ibuffer->buffer_size >= g_tc.req_raw_buffer_size) { hp3a_enable_raw(ibuffer->isp_addr); ibuffer->type = BAYER; hp3a_enqueue(&g_tc.ready_stats_queue, &ibuffer); } } } } }
/** * hp3a_histogram_isr - ISR for the histogram done interrupt. * * No return value. **/ static void hp3a_histogram_isr(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2) { u32 *hist_buffer; u32 i; struct hp3a_internal_buffer *ibuffer = NULL; if (unlikely((HIST_DONE & status) != HIST_DONE)) { return; } omap_writel(omap_readl(ISPHIST_PCR) & ~(ISPHIST_PCR_EN), ISPHIST_PCR); if (unlikely(g_tc.v4l2_streaming == 0)) { return; } if (hp3a_dequeue(&g_tc.hist_hw_queue, &ibuffer) == 0) { /* If there is a buffer available then fill it. */ hist_buffer = (u32 *)phys_to_virt(page_to_phys(ibuffer->pages[0])); omap_writel((omap_readl(ISPHIST_CNT)) | \ ISPHIST_CNT_CLR_EN, ISPHIST_CNT); for (i = g_tc.hist_bin_size; i--;) { *hist_buffer = omap_readl(ISPHIST_DATA); ++hist_buffer; } omap_writel((omap_readl(ISPHIST_CNT)) & ~ISPHIST_CNT_CLR_EN, ISPHIST_CNT); } else { /* There are no buffers availavle so just clear internal histogram memory. */ for (i = g_tc.hist_bin_size; i--;) { omap_writel(0, ISPHIST_DATA); } } /* Set memory HW memory address and enable. */ omap_writel(0, ISPHIST_ADDR); if (g_tc.hist_hw_enable == 1) { /* Enable histogram. */ omap_writel(omap_readl(ISPHIST_PCR) | (ISPHIST_PCR_EN), ISPHIST_PCR); } g_tc.hist_done = 1; /* Release the tasks waiting for stats. */ wake_up(&g_tc.stats_done); }
/** * hp3a_task - Tasks body, executes once per frame. * @work: Pointer to the hp3a work structure. * * No return value. **/ static void hp3a_task(struct work_struct *work) { /* Place holder for deferred tasks. */ struct hp3a_sensor_param_internal sensor_param; struct hp3a_sensor_param_internal empty_param = { .exposure = 0, .gain = 0, .fps = 0}; struct cam_sensor_settings sensor_settings = { .flags = 0, .exposure = 0, .gain = 0, .regs = 0, .fps = 0, .reg_data = 0}; unsigned long irqflags = 0; /** * Setup exposure and gain for next frame. */ if (hp3a_dequeue(&g_tc.sensor_write_queue, &sensor_param) == 0) { sensor_settings.exposure = sensor_param.exposure; sensor_settings.gain = sensor_param.gain; sensor_settings.fps = sensor_param.fps; if (sensor_param.fps) sensor_settings.flags |= OMAP34XXCAM_SET_FPS; if (sensor_param.exposure) sensor_settings.flags |= OMAP34XXCAM_SET_EXPOSURE; if (sensor_param.gain) sensor_settings.flags |= OMAP34XXCAM_SET_GAIN; if (sensor_settings.flags == 0) return; /** * Write and read sensor settings. */ omap34xxcam_sensor_settings(sensor_param.v4l2_dev, &sensor_settings); spin_lock_irqsave(&g_tc.stats_lock, irqflags); /* Initialize memory. */ memset(&sensor_param, 0, sizeof(sensor_param)); if (g_tc.sensor_current.fps != sensor_settings.fps) { empty_param.frame_id = g_tc.frame_count + 1; empty_param.gain = 0; empty_param.exposure = -1; hp3a_enqueue( \ &g_tc.sensor_read_queue, &empty_param); sensor_param.frame_id = \ (g_tc.frame_count + 2); if (g_tc.sensor_current.exposure != \ sensor_settings.exposure) { sensor_param.exposure = \ sensor_settings.exposure; g_tc.sensor_current.exposure = \ sensor_settings.exposure; } if (g_tc.sensor_current.gain != sensor_settings.gain) { sensor_param.gain = sensor_settings.gain; g_tc.sensor_current.gain = \ sensor_settings.gain; } sensor_param.fps = sensor_settings.fps; /* Queue new value for stats collecton. */ hp3a_enqueue( \ &g_tc.sensor_read_queue, &sensor_param); g_tc.sensor_current.fps = sensor_settings.fps; } else { if (g_tc.sensor_current.gain != sensor_settings.gain) { if (g_tc.gain_sync > 1) { empty_param.frame_id = \ g_tc.frame_count + 1; empty_param.gain = -1; hp3a_enqueue( \ &g_tc.sensor_read_queue, &empty_param); } sensor_param.frame_id = \ (g_tc.frame_count + g_tc.gain_sync); sensor_param.gain = sensor_settings.gain; /* Queue new value for stats collecton. */ hp3a_enqueue( \ &g_tc.sensor_read_queue, &sensor_param); /* Save new programmed in gain value. */ g_tc.sensor_current.gain = sensor_settings.gain; } if (g_tc.sensor_current.exposure != \ sensor_settings.exposure) { if (g_tc.exposure_sync > 1) { empty_param.frame_id = \ g_tc.frame_count + 1; empty_param.gain = 0; empty_param.exposure = -1; hp3a_enqueue( \ &g_tc.sensor_read_queue, &empty_param); } sensor_param.frame_id = \ (g_tc.frame_count + g_tc.exposure_sync); sensor_param.exposure = \ sensor_settings.exposure; sensor_param.gain = 0; /* Queue new value for stats collecton. */ hp3a_enqueue( \ &g_tc.sensor_read_queue, &sensor_param); /* Save new programmed in exposure value. */ g_tc.sensor_current.exposure = \ sensor_settings.exposure; } } spin_unlock_irqrestore(&g_tc.stats_lock, irqflags); } }
/** * hp3a_update_framework- execute tasks between frames. * * No return value. **/ void hp3a_update_stats_readout_done(void) { int i; bool allow_exp_update = true; bool allow_gain_update = true; struct hp3a_internal_buffer *ibuffer; struct hp3a_sensor_param_internal sensor_param; if (unlikely(g_tc.v4l2_streaming == 0)) { hp3a_disable_histogram(); hp3a_disable_af(); return; } /* Reuse stats buffers. */ if (g_tc.histogram_buffer != NULL) { g_tc.hist_done = 0; hp3a_enqueue(&g_tc.hist_stat_queue, &g_tc.histogram_buffer); g_tc.histogram_buffer = NULL; } if (g_tc.af_buffer != NULL) { hp3a_enqueue(&g_tc.af_stat_queue, &g_tc.af_buffer); g_tc.af_buffer = NULL; } if (g_tc.raw_buffer != NULL) { hp3a_enqueue(&g_tc.raw_frame_queue, &g_tc.raw_buffer); g_tc.raw_buffer = NULL; } /* Process ready stats. */ for (i = MAX_STAT_BUFFERS_PER_FRAME; i--;) { ibuffer = NULL; if (hp3a_dequeue(&g_tc.ready_stats_queue, &ibuffer) == 0) { if (ibuffer->type == HISTOGRAM && g_tc.histogram_buffer == NULL) g_tc.histogram_buffer = ibuffer; else if (ibuffer->type == PAXEL && g_tc.af_buffer == NULL) g_tc.af_buffer = ibuffer; else if (ibuffer->type == BAYER && g_tc.raw_buffer == NULL) g_tc.raw_buffer = ibuffer; else { printk(KERN_ERR "hp3a: Error unknown " "buffer type(%d)\n", ibuffer->type); } } else { break; } } for (i = QUEUE_COUNT(g_tc.sensor_read_queue); i--;) { if (hp3a_dequeue(&g_tc.sensor_read_queue, &sensor_param) == 0) { if (sensor_param.frame_id == g_tc.frame_count) { if (sensor_param.exposure == (u32)-1) { g_tc.sensor_stats.exposure = 0; allow_exp_update = false; } else if (sensor_param.exposure && allow_exp_update) { g_tc.sensor_stats.exposure = sensor_param.exposure; } if (sensor_param.gain == (u16)-1) { g_tc.sensor_stats.gain = 0; allow_gain_update = false; } else if (sensor_param.gain && allow_gain_update) { g_tc.sensor_stats.gain = sensor_param.gain; } if (sensor_param.fps) { g_tc.sensor_stats.fps = \ sensor_param.fps; } } else if (sensor_param.frame_id > g_tc.frame_count) { hp3a_enqueue(&g_tc.sensor_read_queue, &sensor_param); } } else { break; } } /* Histogram buffer processing and HW configuration. */ hp3a_enable_histogram(); /* AF stat buffer processing and HW configuration. */ hp3a_enable_af(); /* Notify threads waiting for stats. */ complete(&g_tc.frame_done); }