// Modified by somesoo 20100730 for removing green block effect int8 tunerbb_drv_fc8050_multi_set_channel(int32 freq_num, uint8 subch_cnt, uint8 subch_id[ ], uint8 op_mode[ ]) { int8 res = BBM_OK; int32 freq = 0; uint8 dmb_cnt=0; int i; fc8050_service_type svcType = FC8050_SERVICE_MAX; unsigned short mask; // Added by somesoo 20100730 for removing green block effect fc8050_isr_control(0); for(i=0;i<subch_cnt;i++) { serviceType[i] = op_mode[i]; if(FC8050_ENSQUERY != op_mode[i]) tunerbb_drv_fc8050_stop(); else svcType = FC8050_ENSQUERY; } tunerbb_drv_fc8050_control_fic(0); /* Change freq_num(channel num) to frequency */ freq = tunerbb_drv_convert_chnum_to_freq(freq_num); if(freq == 0) { return FC8050_RESULT_ERROR; } res = BBM_TUNER_SET_FREQ(0, freq); if(res) { return FC8050_RESULT_ERROR; } if(svcType == FC8050_ENSQUERY) { if(BBM_SCAN_STATUS(0)) { return FC8050_RESULT_ERROR; } } BBM_WORD_READ(NULL, BBM_BUF_ENABLE, &mask); mask &= 0x100; for(i=0;i<subch_cnt;i++) { switch(serviceType[i]) { case FC8050_DAB: mask |= (1<<DAB_SVC_ID); BBM_AUDIO_SELECT(0, subch_id[i],DAB_SVC_ID); #ifdef STREAM_TS_UPLOAD fc8050_demux_select_channel(subch_id[i], DAB_SVC_ID); #else g_chinfo[subch_id[i]]=DAB_SVC_ID; #endif break; case FC8050_DMB: case FC8050_VISUAL: mask |= (1<<(DMB_SVC_ID+dmb_cnt)); //LGE_BROADCAST_I if(dmb_cnt<2) { BBM_VIDEO_SELECT(0, subch_id[i], DMB_SVC_ID+dmb_cnt, dmb_cnt); #ifdef STREAM_TS_UPLOAD fc8050_demux_select_video(subch_id[i], DMB_SVC_ID+dmb_cnt); #else g_chinfo[subch_id[i]]=dmb_cnt; #endif dmb_cnt++; } else res=BBM_NOK; break; case FC8050_DATA: mask |= (1<<DAT_SVC_ID); BBM_DATA_SELECT(0, subch_id[i], DAT_SVC_ID); #ifdef STREAM_TS_UPLOAD fc8050_demux_select_channel(subch_id[i], DAT_SVC_ID); #else g_chinfo[subch_id[i]]=DAT_SVC_ID; #endif break; case FC8050_ENSQUERY: tunerbb_drv_fc8050_control_fic(1); res = BBM_OK; break; default: res = BBM_NOK; break; } } BBM_WORD_WRITE(NULL, BBM_BUF_ENABLE, mask); tot_subch_cnt = subch_cnt; // Added by somesoo 20100730 for removing green block effect if(svcType != FC8050_ENSQUERY) fc8050_isr_control(1); if(res) return FC8050_RESULT_ERROR; else return FC8050_RESULT_SUCCESS; }
/*-------------------------------------------------------------------------- int8 tunerbb_drv_fc8050_get_bbinfo(tdmb_status_rsp_type* dmb_bb_info) (1) Getting the RF/BB Information (2) Return Value Sucess : 1 Fail : 0 or negative interger (If there is error code) (3) Argument tdmb_status_rsp_type* dmb_bb_info (IN/OUT) typedef struct tdmb_status_rsp_status { uint32 dab_ok; uint32 msc_ber; uint32 sync_lock; uint32 afc_ok; uint32 cir; uint32 fic_ber; uint32 tp_lock; uint32 sch_ber; uint32 tp_err_cnt; uint32 va_ber; byte srv_state_flag; }; These paramters are dependent on Information supplied by Device. ---------------------------------------------------------------------------- */ int8 tunerbb_drv_fc8050_get_ber(struct broadcast_tdmb_sig_info *dmb_bb_info) { uint8 sync_status; uint32 tp_err_cnt=0; fc8050_isr_control(0); tunerbb_drv_fc8050_check_overrun(serviceType[0]); dmb_bb_info->msc_ber=tunerbb_drv_fc8050_get_viterbi_ber(); sync_status=tunerbb_drv_fc8050_get_sync_status(); dmb_bb_info->sync_lock = ((sync_status & 0x10) ? 1 : 0); dmb_bb_info->cir = ((sync_status & 0x08) ? 1 : 0); dmb_bb_info->afc_ok = (((sync_status & 0x06)==0x06) ? 1 : 0); if(dmb_bb_info->cir && dmb_bb_info->sync_lock) { dmb_bb_info->sch_ber = 1; // dab_ok : channel impulse response dmb_bb_info->dab_ok = 1; } else { dmb_bb_info->sch_ber = 0; // dab_ok : channel impulse response dmb_bb_info->dab_ok = 0; } if(serviceType[0] == FC8050_DMB || serviceType[0] == FC8050_VISUAL) { tp_err_cnt=tunerbb_drv_fc8050_rserror_count(); if((dmb_bb_info->sync_lock == 0) || (tp_total_cnt == 0)) { dmb_bb_info->tp_err_cnt = 0; dmb_bb_info->tp_lock = 0; } else if(tp_err_cnt == 0) { dmb_bb_info->tp_err_cnt = 0; dmb_bb_info->tp_lock = 1; } else //if(bb_info.tp_err_cnt > 0) { dmb_bb_info->tp_err_cnt = (uint32)((tp_err_cnt *1000)/(3*tp_total_cnt)); dmb_bb_info->tp_lock = 0; } // initialize information tp_total_cnt = 0; } else { dmb_bb_info->tp_err_cnt =0; dmb_bb_info->tp_lock =0; } dmb_bb_info->fic_ber=0; dmb_bb_info->va_ber=tunerbb_drv_fc8050_get_rs_ber(); dmb_bb_info->srv_state_flag=0; fc8050_isr_control(1); return FC8050_RESULT_SUCCESS; }
/*-------------------------------------------------------------------------- int8 tunerbb_drv_fc8050_get_bbinfo(tdmb_status_rsp_type* dmb_bb_info) (1) Getting the RF/BB Information (2) Return Value Sucess : 1 Fail : 0 or negative interger (If there is error code) (3) Argument tdmb_status_rsp_type* dmb_bb_info (IN/OUT) typedef struct tdmb_status_rsp_status { uint32 dab_ok; uint32 msc_ber; uint32 sync_lock; uint32 afc_ok; uint32 cir; uint32 fic_ber; uint32 tp_lock; uint32 sch_ber; uint32 tp_err_cnt; uint32 va_ber; byte srv_state_flag; }; These paramters are dependent on Information supplied by Device. ---------------------------------------------------------------------------- */ int8 tunerbb_drv_fc8050_get_ber(struct broadcast_tdmb_sig_info *dmb_bb_info) { uint8 sync_status; uint32 tp_err_cnt=0; uint16 nframe = 0; fc8050_isr_control(0); tunerbb_drv_fc8050_check_overrun(serviceType[0]); dmb_bb_info->msc_ber = tunerbb_drv_fc8050_get_viterbi_ber(); sync_status = tunerbb_drv_fc8050_get_sync_status(); dmb_bb_info->sync_lock = ((sync_status & 0x10) ? 1 : 0); dmb_bb_info->cir = ((sync_status & 0x08) ? 1 : 0); dmb_bb_info->afc_ok = (((sync_status & 0x06)==0x06) ? 1 : 0); if(dmb_bb_info->cir && dmb_bb_info->sync_lock) { dmb_bb_info->sch_ber = 1; // dab_ok : channel impulse response dmb_bb_info->dab_ok = 1; } else { dmb_bb_info->sch_ber = 0; // dab_ok : channel impulse response dmb_bb_info->dab_ok = 0; } if(serviceType[0] == FC8050_DMB || serviceType[0] == FC8050_VISUAL) { tp_err_cnt = tunerbb_drv_fc8050_rserror_count(&nframe); //실시간 frame수 체크 if((dmb_bb_info->sync_lock == 0) || (tp_total_cnt == 0)) { dmb_bb_info->tp_err_cnt = 0; dmb_bb_info->tp_lock = 0; } else if(tp_err_cnt == 0) { dmb_bb_info->tp_err_cnt = 0; dmb_bb_info->tp_lock = 1; } else //if(bb_info.tp_err_cnt > 0) { dmb_bb_info->tp_err_cnt = (uint32)((tp_err_cnt *1000)/(3*tp_total_cnt)); dmb_bb_info->tp_lock = 0; } // initialize information tp_total_cnt = 0; } else { dmb_bb_info->tp_err_cnt = 0; dmb_bb_info->tp_lock = 0; } dmb_bb_info->fic_ber = 0; dmb_bb_info->va_ber = tunerbb_drv_fc8050_get_rs_ber(); if(dmb_bb_info->msc_ber < 6000) { dmb_bb_info->antenna_level = 4; } else if(dmb_bb_info->msc_ber >= 6000 && dmb_bb_info->msc_ber < 8000) { dmb_bb_info->antenna_level = 3; } else if(dmb_bb_info->msc_ber >= 8000 && dmb_bb_info->msc_ber < 9000) { dmb_bb_info->antenna_level = 2; } else if(dmb_bb_info->msc_ber >= 9000 && dmb_bb_info->msc_ber < 12000) { dmb_bb_info->antenna_level = 1; } else if(dmb_bb_info->msc_ber >= 12000) { dmb_bb_info->antenna_level = 0; } //antenna level이 0이면 약전계이므로 5분종료를 위해 dab_ok를 0으로 만듬. if(dmb_bb_info->antenna_level == 0) { dmb_bb_info->dab_ok = 0; } fc8050_isr_control(1); return FC8050_RESULT_SUCCESS; }
int tdmb_fc8050_spi_write_read(uint8* tx_data, int tx_length, uint8 *rx_data, int rx_length) { int rc; struct spi_transfer t = { .tx_buf = tx_data, .rx_buf = rx_data, .len = tx_length+rx_length, }; struct spi_message m; if (fc8050_ctrl_info.spi_ptr == NULL) { printk("tdmb_fc8050_spi_write_read error txdata=0x%x, length=%d\n", (unsigned int)tx_data, tx_length+rx_length); } mutex_lock(&fc8050_ctrl_info.mutex); spi_message_init(&m); spi_message_add_tail(&t, &m); rc = spi_sync(fc8050_ctrl_info.spi_ptr, &m); if ( rc < 0 ) { printk("tdmb_fc8050_spi_read_burst result(%d), actual_len=%d\n",rc, m.actual_length); } mutex_unlock(&fc8050_ctrl_info.mutex); return TRUE; } #ifdef FEATURE_DMB_USE_WORKQUEUE static irqreturn_t broadcast_tdmb_spi_isr(int irq, void *handle) { struct tdmb_fc8050_ctrl_blk* fc8050_info_p; unsigned long flag; fc8050_info_p = (struct tdmb_fc8050_ctrl_blk *)handle; if ( fc8050_info_p && fc8050_info_p->TdmbPowerOnState ) { if (fc8050_info_p->spi_irq_status) { printk("######### spi read function is so late skip #########\n"); return IRQ_HANDLED; } // printk("***** broadcast_tdmb_spi_isr coming *******\n"); spin_lock_irqsave(&fc8050_info_p->spin_lock, flag); queue_work(fc8050_info_p->spi_wq, &fc8050_info_p->spi_work); spin_unlock_irqrestore(&fc8050_info_p->spin_lock, flag); } else { printk("broadcast_tdmb_spi_isr is called, but device is off state\n"); } return IRQ_HANDLED; } static void broacast_tdmb_spi_work(struct work_struct *tdmb_work) { struct tdmb_fc8050_ctrl_blk *pTdmbWorkData; pTdmbWorkData = container_of(tdmb_work, struct tdmb_fc8050_ctrl_blk, spi_work); if ( pTdmbWorkData ) { fc8050_isr_control(0); pTdmbWorkData->spi_irq_status = TRUE; broadcast_drv_if_isr(); pTdmbWorkData->spi_irq_status = FALSE; fc8050_isr_control(1); } else { printk("~~~~~~~broadcast_tdmb_spi_work call but pTdmbworkData is NULL ~~~~~~~\n"); } } #else static irqreturn_t broadcast_tdmb_spi_event_handler(int irq, void *handle) { struct tdmb_fc8050_ctrl_blk* fc8050_info_p; fc8050_info_p = (struct tdmb_fc8050_ctrl_blk *)handle; if ( fc8050_info_p && fc8050_info_p->TdmbPowerOnState ) { if (fc8050_info_p->spi_irq_status) { printk("######### spi read function is so late skip #########\n"); return IRQ_HANDLED; } fc8050_isr_control(0); fc8050_info_p->spi_irq_status = TRUE; broadcast_drv_if_isr(); fc8050_info_p->spi_irq_status = FALSE; fc8050_isr_control(1); } else { printk("broadcast_tdmb_spi_isr is called, but device is off state\n"); } return IRQ_HANDLED; } #endif static int broadcast_tdmb_fc8050_probe(struct spi_device *spi) { int rc; #ifdef ANTENNA_SWITCHING struct pm_gpio GPIO11_CFG = { .direction = PM_GPIO_DIR_OUT, .pull = PM_GPIO_PULL_NO, .function = PM_GPIO_FUNC_NORMAL, .vin_sel = 2, .inv_int_pol = 0, }; struct pm_gpio GPIO12_CFG = { .direction = PM_GPIO_DIR_OUT, .pull = PM_GPIO_PULL_NO, .function = PM_GPIO_FUNC_NORMAL, .vin_sel = 2, .inv_int_pol = 0, }; #endif /* ANTENNA_SWITCHING */ fc8050_ctrl_info.TdmbPowerOnState = FALSE; fc8050_ctrl_info.spi_ptr = spi; fc8050_ctrl_info.spi_ptr->mode = SPI_MODE_0; fc8050_ctrl_info.spi_ptr->bits_per_word = 8; fc8050_ctrl_info.spi_ptr->max_speed_hz = ( 24000*1000 ); rc = spi_setup(spi); printk("broadcast_tdmb_fc8050_probe spi_setup=%d\n", rc); BBM_HOSTIF_SELECT(NULL, 1); #ifdef FEATURE_DMB_USE_WORKQUEUE INIT_WORK(&fc8050_ctrl_info.spi_work, broacast_tdmb_spi_work); fc8050_ctrl_info.spi_wq = create_singlethread_workqueue("tdmb_spi_wq"); if(fc8050_ctrl_info.spi_wq == NULL){ printk("Failed to setup tdmb spi workqueue \n"); return -ENOMEM; } #endif gpio_request(DMB_RESET_N, "DMB_RESET_N"); gpio_request(DMB_EN, "DMB_EN"); gpio_request(DMB_INT_N, "DMB_INT_N"); //gpio_direction_output(DMB_RESET_N, false); //gpio_direction_output(DMB_EN, false); //gpio_direction_output(DMB_INT_N, false); #ifdef ANTENNA_SWITCHING pm8xxx_gpio_config(DMB_ANT_SEL_P_EAR, &GPIO11_CFG); pm8xxx_gpio_config(DMB_ANT_SEL_N_INNER, &GPIO12_CFG); gpio_set_value_cansleep(DMB_ANT_SEL_P_EAR, 1); gpio_set_value_cansleep(DMB_ANT_SEL_N_INNER, 0); #endif /* ANTENNA_SWITCHING */ #ifdef FEATURE_DMB_USE_WORKQUEUE rc = request_irq(spi->irq, broadcast_tdmb_spi_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, spi->dev.driver->name, &fc8050_ctrl_info); #else rc = request_threaded_irq(spi->irq, NULL, broadcast_tdmb_spi_event_handler, IRQF_DISABLED | IRQF_TRIGGER_FALLING, spi->dev.driver->name, &fc8050_ctrl_info); #endif printk("broadcast_tdmb_fc8050_probe request_irq=%d\n", rc); tdmb_fc8050_interrupt_lock(); mutex_init(&fc8050_ctrl_info.mutex); wake_lock_init(&fc8050_ctrl_info.wake_lock, WAKE_LOCK_SUSPEND, dev_name(&spi->dev)); spin_lock_init(&fc8050_ctrl_info.spin_lock); #ifdef PM_QOS pm_qos_add_request(&fc8050_ctrl_info.pm_req_list, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); #endif /* PM_QOS */ printk("broadcast_fc8050_probe End\n"); return rc; } static int broadcast_tdmb_fc8050_remove(struct spi_device *spi) { printk("broadcast_tdmb_fc8050_remove \n"); #ifdef FEATURE_DMB_USE_WORKQUEUE if (fc8050_ctrl_info.spi_wq) { flush_workqueue(fc8050_ctrl_info.spi_wq); destroy_workqueue(fc8050_ctrl_info.spi_wq); } #endif free_irq(spi->irq, &fc8050_ctrl_info); mutex_destroy(&fc8050_ctrl_info.mutex); wake_lock_destroy(&fc8050_ctrl_info.wake_lock); #ifdef PM_QOS pm_qos_remove_request(&fc8050_ctrl_info.pm_req_list); #endif /* PM_QOS */ memset((unsigned char*)&fc8050_ctrl_info, 0x0, sizeof(struct tdmb_fc8050_ctrl_blk)); return 0; } static int broadcast_tdmb_fc8050_suspend(struct spi_device *spi, pm_message_t mesg) { printk("broadcast_tdmb_fc8050_suspend \n"); return 0; }
int tdmb_fc8050_spi_write_read(uint8* tx_data, int tx_length, uint8 *rx_data, int rx_length) { int rc; struct spi_transfer t = { .tx_buf = tx_data, .rx_buf = rx_data, .len = tx_length+rx_length, }; struct spi_message m; if (fc8050_ctrl_info.spi_ptr == NULL) { printk("tdmb_fc8050_spi_write_read error txdata=0x%x, length=%d\n", (unsigned int)tx_data, tx_length+rx_length); return FALSE; } mutex_lock(&fc8050_ctrl_info.mutex); spi_message_init(&m); spi_message_add_tail(&t, &m); rc = spi_sync(fc8050_ctrl_info.spi_ptr, &m); if ( rc < 0 ) { printk("tdmb_fc8050_spi_read_burst result(%d), actual_len=%d\n",rc, m.actual_length); } mutex_unlock(&fc8050_ctrl_info.mutex); return TRUE; } #ifdef FEATURE_DMB_USE_WORKQUEUE static irqreturn_t broadcast_tdmb_spi_isr(int irq, void *handle) { struct tdmb_fc8050_ctrl_blk* fc8050_info_p; unsigned long flag; fc8050_info_p = (struct tdmb_fc8050_ctrl_blk *)handle; if ( fc8050_info_p && fc8050_info_p->TdmbPowerOnState ) { if (fc8050_info_p->spi_irq_status) { printk("######### spi read function is so late skip #########\n"); return IRQ_HANDLED; } // printk("***** broadcast_tdmb_spi_isr coming *******\n"); spin_lock_irqsave(&fc8050_info_p->spin_lock, flag); queue_work(fc8050_info_p->spi_wq, &fc8050_info_p->spi_work); spin_unlock_irqrestore(&fc8050_info_p->spin_lock, flag); } else { printk("broadcast_tdmb_spi_isr is called, but device is off state\n"); } return IRQ_HANDLED; } static void broacast_tdmb_spi_work(struct work_struct *tdmb_work) { struct tdmb_fc8050_ctrl_blk *pTdmbWorkData; pTdmbWorkData = container_of(tdmb_work, struct tdmb_fc8050_ctrl_blk, spi_work); if ( pTdmbWorkData ) { fc8050_isr_control(0); pTdmbWorkData->spi_irq_status = TRUE; broadcast_drv_if_isr(); pTdmbWorkData->spi_irq_status = FALSE; fc8050_isr_control(1); } else { printk("~~~~~~~broadcast_tdmb_spi_work call but pTdmbworkData is NULL ~~~~~~~\n"); } } #else static irqreturn_t broadcast_tdmb_spi_event_handler(int irq, void *handle) { struct tdmb_fc8050_ctrl_blk* fc8050_info_p; fc8050_info_p = (struct tdmb_fc8050_ctrl_blk *)handle; if ( fc8050_info_p && fc8050_info_p->TdmbPowerOnState ) { if (fc8050_info_p->spi_irq_status) { printk("######### spi read function is so late skip ignore #########\n"); return IRQ_HANDLED; } fc8050_isr_control(0); fc8050_info_p->spi_irq_status = TRUE; broadcast_drv_if_isr(); fc8050_info_p->spi_irq_status = FALSE; fc8050_isr_control(1); } else { printk("broadcast_tdmb_spi_isr is called, but device is off state\n"); } return IRQ_HANDLED; } #endif static int tdmb_configure_gpios(void) { int rc = OK; int err_count = 0; rc = gpio_request(DMB_RESET_N, "DMB_RESET_N"); if (rc < 0) { err_count++; printk("%s:Failed GPIO DMB_RESET_N request!!!\n",__func__); } rc = gpio_request(DMB_EN, "DMB_EN"); if (rc < 0) { err_count++; printk("%s:Failed GPIO DMB_EN request!!!\n",__func__); } rc = gpio_request(DMB_INT_N, "DMB_INT_N"); if (rc < 0) { err_count++; printk("%s:Failed GPIO DMB_INT_N request!!!\n",__func__); } gpio_direction_output(DMB_RESET_N, 0); gpio_direction_output(DMB_EN, 0); gpio_direction_input(DMB_INT_N); if(err_count > 0) rc = -EINVAL; return rc; }