summaryrefslogtreecommitdiff
path: root/drivers/media/radio/CG2900/cg2900_fm_api.c
diff options
context:
space:
mode:
authorHemant Gupta <hemant.gupta@stericsson.com>2011-05-30 20:13:57 +0530
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:06:01 +0200
commit1111f67691c150cae3e88f12fc9c50ab76b3aaff (patch)
treee8a72334da1be440363321eac7afe9949037f6f5 /drivers/media/radio/CG2900/cg2900_fm_api.c
parentea3500f7b5e6f419ddc5552e2ff7c7d6909ab725 (diff)
CG2900 FM Radio: Handling Mono-Stereo Interrupt.
The linux FM driver for CG2900 now supports mono-stereo transition interrupt from the CG2900. It indicates stereo to mono transition or vice versa. Support for RDS Interrupt, Scan Completion Interrupt, CG2900 Reset Interrupt, etc is also added in this patch. ST-Ericsson ID: 324264 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I280a2a00a6f58e105d11f3a9f14ea662719c485e Signed-off-by: Hemant Gupta <hemant.gupta@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30511 Reviewed-by: Johan PALMAEUS <johan.xj.palmaeus@stericsson.com> Reviewed-by: Virupax SADASHIVPETIMATH <virupax.sadashivpetimath@stericsson.com> Tested-by: Virupax SADASHIVPETIMATH <virupax.sadashivpetimath@stericsson.com>
Diffstat (limited to 'drivers/media/radio/CG2900/cg2900_fm_api.c')
-rw-r--r--drivers/media/radio/CG2900/cg2900_fm_api.c324
1 files changed, 189 insertions, 135 deletions
diff --git a/drivers/media/radio/CG2900/cg2900_fm_api.c b/drivers/media/radio/CG2900/cg2900_fm_api.c
index b6be4e462e3..b7f5f9867d6 100644
--- a/drivers/media/radio/CG2900/cg2900_fm_api.c
+++ b/drivers/media/radio/CG2900/cg2900_fm_api.c
@@ -597,91 +597,108 @@ static void cg2900_fm_driver_callback(
bool event_successful
)
{
+ struct sk_buff *skb;
+
FM_INFO_REPORT("cg2900_fm_driver_callback: "
"event = %02x, event_successful = %x",
event, event_successful);
- if (event_successful) {
- switch (event) {
- case FMD_EVENT_GEN_POWERUP:
- FM_DEBUG_REPORT("FMD_EVENT_GEN_POWERUP");
- break;
- case FMD_EVENT_ANTENNA_STATUS_CHANGED:
- FM_DEBUG_REPORT("FMD_EVENT_ANTENNA_STATUS_CHANGED");
- break;
- case FMD_EVENT_FREQUENCY_CHANGED:
- FM_DEBUG_REPORT("FMD_EVENT_FREQUENCY_CHANGED ");
- break;
-
- case FMD_EVENT_SEEK_STOPPED:
- FM_DEBUG_REPORT("FMD_EVENT_SEEK_STOPPED");
- fm_event = CG2900_EVENT_SCAN_CANCELLED;
- wake_up_poll_queue();
- break;
-
- case FMD_EVENT_SEEK_COMPLETED:
- FM_DEBUG_REPORT("FMD_EVENT_SEEK_COMPLETED");
- fm_event = CG2900_EVENT_SEARCH_CHANNEL_FOUND;
- wake_up_poll_queue();
- break;
-
- case FMD_EVENT_SCAN_BAND_COMPLETED:
- FM_DEBUG_REPORT("FMD_EVENT_SCAN_BAND_COMPLETED");
- fm_event = CG2900_EVENT_SCAN_CHANNELS_FOUND;
- wake_up_poll_queue();
- break;
-
- case FMD_EVENT_BLOCK_SCAN_COMPLETED:
- FM_DEBUG_REPORT("FMD_EVENT_BLOCK_SCAN_COMPLETED");
- fm_event = CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND;
- wake_up_poll_queue();
- break;
-
- case FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE:
- FM_DEBUG_REPORT("FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE");
- break;
-
- case FMD_EVENT_RDSGROUP_RCVD:
- FM_DEBUG_REPORT("FMD_EVENT_RDSGROUP_RCVD");
- fmd_set_rds_sem();
- break;
-
- default:
- FM_INFO_REPORT("cg2900_fm_driver_callback: "
- "Unknown event = %x", event);
- break;
+ switch (event) {
+ case FMD_EVENT_GEN_POWERUP:
+ FM_DEBUG_REPORT("FMD_EVENT_GEN_POWERUP");
+ break;
+ case FMD_EVENT_ANTENNA_STATUS_CHANGED:
+ FM_DEBUG_REPORT("FMD_EVENT_ANTENNA_STATUS_CHANGED");
+ break;
+ case FMD_EVENT_FREQUENCY_CHANGED:
+ FM_DEBUG_REPORT("FMD_EVENT_FREQUENCY_CHANGED ");
+ break;
+ case FMD_EVENT_SEEK_STOPPED:
+ FM_DEBUG_REPORT("FMD_EVENT_SEEK_STOPPED");
+ skb = alloc_skb(SKB_FM_INTERRUPT_DATA,
+ GFP_KERNEL);
+ if (!skb) {
+ FM_ERR_REPORT("cg2900_fm_driver_callback: "
+ "Unable to Allocate Memory");
+ return;
}
- } else {
- switch (event) {
- /*
- * Seek stop, band scan, seek, block scan could
- * fail for some reason so wake up poll queue
- */
- case FMD_EVENT_SEEK_STOPPED:
- FM_ERR_REPORT("FMD_EVENT_SEEK_STOPPED");
- fm_event = CG2900_EVENT_SCAN_CANCELLED;
- wake_up_poll_queue();
- break;
- case FMD_EVENT_SEEK_COMPLETED:
- FM_ERR_REPORT("FMD_EVENT_SEEK_COMPLETED");
- fm_event = CG2900_EVENT_SEARCH_CHANNEL_FOUND;
- wake_up_poll_queue();
- break;
- case FMD_EVENT_SCAN_BAND_COMPLETED:
- FM_ERR_REPORT("FMD_EVENT_SCAN_BAND_COMPLETED");
- fm_event = CG2900_EVENT_SCAN_CHANNELS_FOUND;
- wake_up_poll_queue();
- break;
- case FMD_EVENT_BLOCK_SCAN_COMPLETED:
- FM_ERR_REPORT("FMD_EVENT_BLOCK_SCAN_COMPLETED");
- fm_event = CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND;
- wake_up_poll_queue();
- break;
- default:
+ skb->data[0] = CG2900_EVENT_SCAN_CANCELLED;
+ skb->data[1] = event_successful;
+ skb_queue_tail(&fm_interrupt_queue, skb);
+ wake_up_poll_queue();
+ break;
+ case FMD_EVENT_SEEK_COMPLETED:
+ FM_DEBUG_REPORT("FMD_EVENT_SEEK_COMPLETED");
+ skb = alloc_skb(SKB_FM_INTERRUPT_DATA,
+ GFP_KERNEL);
+ if (!skb) {
FM_ERR_REPORT("cg2900_fm_driver_callback: "
- "event = %x failed!!!!", event);
- break;
+ "Unable to Allocate Memory");
+ return;
+ }
+ skb->data[0] = CG2900_EVENT_SEARCH_CHANNEL_FOUND;
+ skb->data[1] = event_successful;
+ skb_queue_tail(&fm_interrupt_queue, skb);
+ wake_up_poll_queue();
+ break;
+ case FMD_EVENT_SCAN_BAND_COMPLETED:
+ FM_DEBUG_REPORT("FMD_EVENT_SCAN_BAND_COMPLETED");
+ skb = alloc_skb(SKB_FM_INTERRUPT_DATA,
+ GFP_KERNEL);
+ if (!skb) {
+ FM_ERR_REPORT("cg2900_fm_driver_callback: "
+ "Unable to Allocate Memory");
+ return;
}
+ skb->data[0] = CG2900_EVENT_SCAN_CHANNELS_FOUND;
+ skb->data[1] = event_successful;
+ skb_queue_tail(&fm_interrupt_queue, skb);
+ wake_up_poll_queue();
+ break;
+ case FMD_EVENT_BLOCK_SCAN_COMPLETED:
+ FM_DEBUG_REPORT("FMD_EVENT_BLOCK_SCAN_COMPLETED");
+ skb = alloc_skb(SKB_FM_INTERRUPT_DATA,
+ GFP_KERNEL);
+ if (!skb) {
+ FM_ERR_REPORT("cg2900_fm_driver_callback: "
+ "Unable to Allocate Memory");
+ return;
+ }
+ skb->data[0] = CG2900_EVENT_BLOCK_SCAN_CHANNELS_FOUND;
+ skb->data[1] = event_successful;
+ skb_queue_tail(&fm_interrupt_queue, skb);
+ wake_up_poll_queue();
+ break;
+ case FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE:
+ FM_DEBUG_REPORT("FMD_EVENT_AF_UPDATE_SWITCH_COMPLETE");
+ break;
+ case FMD_EVENT_RDSGROUP_RCVD:
+ FM_DEBUG_REPORT("FMD_EVENT_RDSGROUP_RCVD");
+ /*
+ * Release the rds semaphore, poll queue
+ * will be woken-up in rds callback
+ */
+ fmd_set_rds_sem();
+ break;
+ case FMD_EVENT_MONO_STEREO_TRANSITION_COMPLETE:
+ FM_ERR_REPORT(
+ "FMD_EVENT_MONO_STEREO_TRANSITION_COMPLETE");
+ skb = alloc_skb(SKB_FM_INTERRUPT_DATA,
+ GFP_KERNEL);
+ if (!skb) {
+ FM_ERR_REPORT("cg2900_fm_driver_callback: "
+ "Unable to Allocate Memory");
+ return;
+ }
+ skb->data[0] = CG2900_EVENT_MONO_STEREO_TRANSITION;
+ skb->data[1] = event_successful;
+ skb_queue_tail(&fm_interrupt_queue, skb);
+ wake_up_poll_queue();
+ break;
+ default:
+ FM_INFO_REPORT("cg2900_fm_driver_callback: "
+ "Unknown event = %x", event);
+ break;
}
}
@@ -696,6 +713,8 @@ static void cg2900_fm_rds_callback(void)
u8 index = 0;
u16 rds_local_buf_count;
int result;
+ struct sk_buff *skb;
+
FM_INFO_REPORT("cg2900_fm_rds_callback");
/*
@@ -751,7 +770,21 @@ static void cg2900_fm_rds_callback(void)
fm_rds_info.rds_head++;
if (fm_rds_info.rds_head == MAX_RDS_BUFFER)
fm_rds_info.rds_head = 0;
- wake_up_read_queue();
+
+ /* Queue the RDS event */
+ skb = alloc_skb(SKB_FM_INTERRUPT_DATA,
+ GFP_KERNEL);
+ if (!skb) {
+ FM_ERR_REPORT("cg2900_fm_rds_callback: "
+ "Unable to Allocate Memory");
+ goto error;
+ }
+ skb->data[0] = CG2900_EVENT_RDS_EVENT;
+ skb->data[1] = true;
+ skb_queue_tail(&fm_interrupt_queue, skb);
+
+ /* Wake up the poll queue */
+ wake_up_poll_queue();
error:
mutex_unlock(&rds_mutex);
}
@@ -879,10 +912,11 @@ int cg2900_fm_switch_on(
fm_state = CG2900_FM_STATE_SWITCHED_ON;
fm_mode = CG2900_FM_IDLE_MODE;
- memset(&fm_rds_info, 0, sizeof(struct cg2900_fm_rds_info));
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
error:
FM_DEBUG_REPORT("cg2900_fm_switch_on: returning %d",
@@ -931,10 +965,12 @@ int cg2900_fm_switch_off(void)
fm_state = CG2900_FM_STATE_INITIALIZED;
fm_mode = CG2900_FM_IDLE_MODE;
memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
+ sizeof(struct cg2900_fm_rds_info));
memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
}
error:
@@ -955,6 +991,13 @@ int cg2900_fm_standby(void)
result = -EINVAL;
goto error;
}
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
result = fmd_goto_standby();
if (0 != result) {
FM_ERR_REPORT("cg2900_fm_standby: "
@@ -1118,6 +1161,9 @@ int cg2900_fm_set_rx_default_settings(
goto error;
}
+ /* Remove all Interrupt from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
+
FM_DEBUG_REPORT("cg2900_fm_set_rx_default_settings: "
"Sending Set rds");
@@ -1194,13 +1240,15 @@ int cg2900_fm_set_tx_default_settings(
fm_rds_status = false;
fmd_stop_rds_thread();
memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
+ sizeof(struct cg2900_fm_rds_info));
memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
/* Give 50 ms delay to exit the RDS thread */
schedule_timeout_interruptible(msecs_to_jiffies(50));
}
+ /* Remove all Interrupt from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
/* Switch To Tx mode */
FM_DEBUG_REPORT("cg2900_fm_set_tx_default_settings: "
@@ -1396,6 +1444,14 @@ int cg2900_fm_search_up_freq(void)
/* Stop RDS if it is active */
result = cg2900_fm_rds_off();
fm_prev_rds_status = true;
+ } else {
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
}
result = fmd_rx_seek(CG2900_DIR_UP);
if (0 != result) {
@@ -1404,11 +1460,6 @@ int cg2900_fm_search_up_freq(void)
result = -EINVAL;
goto error;
}
- memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
- memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
result = 0;
error:
@@ -1433,6 +1484,14 @@ int cg2900_fm_search_down_freq(void)
/* Stop RDS if it is active */
result = cg2900_fm_rds_off();
fm_prev_rds_status = true;
+ } else {
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
}
result = fmd_rx_seek(CG2900_DIR_DOWN);
if (0 != result) {
@@ -1441,11 +1500,6 @@ int cg2900_fm_search_down_freq(void)
result = -EINVAL;
goto error;
}
- memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
- memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
result = 0;
error:
@@ -1470,6 +1524,14 @@ int cg2900_fm_start_band_scan(void)
/* Stop RDS if it is active */
result = cg2900_fm_rds_off();
fm_prev_rds_status = true;
+ } else {
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
}
result = fmd_rx_scan_band(DEFAULT_CHANNELS_TO_SCAN);
if (0 != result) {
@@ -1478,11 +1540,6 @@ int cg2900_fm_start_band_scan(void)
result = -EINVAL;
goto error;
}
- memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
- memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
result = 0;
error:
@@ -1648,6 +1705,14 @@ int cg2900_fm_start_block_scan(
/* Stop RDS if it is active */
result = cg2900_fm_rds_off();
fm_prev_rds_status = true;
+ } else {
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
}
result = fmd_get_antenna(
&antenna);
@@ -1661,11 +1726,6 @@ int cg2900_fm_start_block_scan(
result = -EINVAL;
goto error;
}
- memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
- memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
result = 0;
error:
@@ -1990,8 +2050,8 @@ int cg2900_fm_tx_get_pilot_tone_status(
result = fmd_tx_get_stereo_mode(enable);
if (0 != result) {
FM_ERR_REPORT("cg2900_fm_tx_get_pilot_tone_status: "
- "fmd_tx_get_stereo_mode failed %d",
- (unsigned int)result);
+ "fmd_tx_get_stereo_mode failed %d",
+ result);
result = -EINVAL;
goto error;
}
@@ -2334,6 +2394,13 @@ int cg2900_fm_rds_off(void)
result = -EINVAL;
goto error;
}
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
result = fmd_rx_set_rds(FMD_SWITCH_OFF_RDS);
if (0 != result) {
FM_ERR_REPORT("cg2900_fm_rds_off: fmd_rx_set_rds failed, "
@@ -2343,11 +2410,6 @@ int cg2900_fm_rds_off(void)
}
/* Stop the RDS Thread */
fm_rds_status = false;
- memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
- memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
FM_DEBUG_REPORT("cg2900_fm_rds_off: "
"Stopping RDS Thread");
fmd_stop_rds_thread();
@@ -2399,10 +2461,10 @@ int cg2900_fm_rds_on(void)
/* Start the RDS Thread to read the RDS Buffers */
fm_rds_status = true;
memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
+ sizeof(struct cg2900_fm_rds_info));
memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
fmd_start_rds_thread(cg2900_fm_rds_callback);
error:
@@ -2584,6 +2646,13 @@ int cg2900_fm_set_frequency(
result = -EINVAL;
goto error;
}
+ memset(&fm_rds_info, 0,
+ sizeof(struct cg2900_fm_rds_info));
+ memset(fm_rds_buf, 0,
+ sizeof(struct cg2900_fm_rds_buf) *
+ MAX_RDS_BUFFER * MAX_RDS_GROUPS);
+ /* Remove all Interrupts from the queue */
+ skb_queue_purge(&fm_interrupt_queue);
if (CG2900_FM_RX_MODE == fm_mode) {
FM_DEBUG_REPORT("cg2900_fm_set_frequency: "
"fmd_rx_set_frequency");
@@ -2616,11 +2685,6 @@ int cg2900_fm_set_frequency(
result = -EINVAL;
goto error;
}
- memset(&fm_rds_info, 0,
- sizeof(struct cg2900_fm_rds_info));
- memset(fm_rds_buf, 0,
- sizeof(struct cg2900_fm_rds_buf) *
- MAX_RDS_BUFFER * MAX_RDS_GROUPS);
result = 0;
}
@@ -2820,16 +2884,7 @@ int cg2900_fm_get_mode(
FM_DEBUG_REPORT("cg2900_fm_get_mode: "
"fmd_rx_get_stereo_mode");
result = fmd_rx_get_stereo_mode(cur_mode);
- switch (*cur_mode) {
- case FMD_STEREOMODE_OFF:
- case FMD_STEREOMODE_BLENDING:
- *cur_mode = CG2900_MODE_STEREO;
- break;
- case FMD_STEREOMODE_MONO:
- default:
- *cur_mode = CG2900_MODE_MONO;
- break;
- }
+ FM_DEBUG_REPORT("cg2900_fm_get_mode: cur_mode = %x", *cur_mode);
} else if (CG2900_FM_TX_MODE == fm_mode) {
FM_DEBUG_REPORT("cg2900_fm_get_mode: "
"fmd_tx_get_stereo_mode");
@@ -3024,8 +3079,7 @@ int cg2900_fm_set_test_tone_generator(
if (0 != result) {
FM_ERR_REPORT("cg2900_fm_set_test_tone_generator: "
"fmd_set_test_tone_generator_status failed"
- ", Error Code %d",
- result);
+ ", Error Code %d", result);
result = -EINVAL;
goto error;
}