summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorG, Manjunath Kondaiah <manjugk@ti.com>2010-12-20 18:47:12 +0530
committerG, Manjunath Kondaiah <manjugk@ti.com>2010-12-20 18:47:12 +0530
commit567e327436d96216f17e735504f10cd6c340d216 (patch)
tree38b1ec483ec0deae07aba6552c9ea75c759326c8
parentf08e66d15a03bc7f728b68e3b114fc131fcfe747 (diff)
parentb5de5469a80b9af394418b85ecd2b46502fcd51b (diff)
Merge branch 'btfm_next-l24.11-p5' of git://dev.omapzoom.org/pub/scm/manju/L24x-btfm into L24.11ti-2.6.35-omap4-L24.11-p5
-rw-r--r--drivers/staging/ti-st/Makefile2
-rw-r--r--drivers/staging/ti-st/fmdrv.h33
-rw-r--r--drivers/staging/ti-st/fmdrv_common.c728
-rw-r--r--drivers/staging/ti-st/fmdrv_common.h319
-rw-r--r--drivers/staging/ti-st/fmdrv_rx.c634
-rw-r--r--drivers/staging/ti-st/fmdrv_rx.h43
-rw-r--r--drivers/staging/ti-st/fmdrv_tx.c420
-rw-r--r--drivers/staging/ti-st/fmdrv_tx.h37
-rw-r--r--drivers/staging/ti-st/fmdrv_v4l2.c387
9 files changed, 1541 insertions, 1062 deletions
diff --git a/drivers/staging/ti-st/Makefile b/drivers/staging/ti-st/Makefile
index e6af3f1f0867..bd29c83506b9 100644
--- a/drivers/staging/ti-st/Makefile
+++ b/drivers/staging/ti-st/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_TI_ST) += st_drv.o
st_drv-objs := st_core.o st_kim.o st_ll.o
obj-$(CONFIG_ST_BT) += bt_drv.o
obj-$(CONFIG_ST_FM) += fm_drv.o
-fm_drv-objs := fmdrv_common.o fmdrv_rx.o fmdrv_v4l2.o
+fm_drv-objs := fmdrv_common.o fmdrv_rx.o fmdrv_tx.o fmdrv_v4l2.o
diff --git a/drivers/staging/ti-st/fmdrv.h b/drivers/staging/ti-st/fmdrv.h
index 1f126a9252b2..5ce7bbf934a5 100644
--- a/drivers/staging/ti-st/fmdrv.h
+++ b/drivers/staging/ti-st/fmdrv.h
@@ -46,6 +46,9 @@
#define FM_AF_SWITCH_INPROGRESS 5
#define FM_CORE_TX_XMITING 6
+#define FM_TUNE_COMPLETE 0x1
+#define FM_BAND_LIMIT 0x2
+
#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */
#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */
@@ -137,7 +140,8 @@ struct fm_rds {
#define FM_RDS_MAX_AF_LIST 25
-/* Current RX channel Alternate Frequency cache.
+/*
+ * Current RX channel Alternate Frequency cache.
* This info is used to switch to other freq (AF)
* when current channel signal strengh is below RSSI threshold.
*/
@@ -153,6 +157,7 @@ struct fm_rx {
struct region_info region; /* Current selected band */
unsigned int curr_freq; /* Current RX frquency */
unsigned char curr_mute_mode; /* Current mute mode */
+ unsigned char curr_deemphasis_mode; /* Current deemphasis mode */
/* RF dependent soft mute mode */
unsigned char curr_rf_depend_mute;
unsigned short curr_volume; /* Current volume level */
@@ -178,6 +183,7 @@ struct fm_rx {
struct tx_rds {
unsigned char text_type;
unsigned char text[25];
+ unsigned char flag;
unsigned int af_freq;
};
/*
@@ -192,6 +198,9 @@ struct fmtx_data {
unsigned char pwr_lvl;
unsigned char xmit_state;
unsigned char audio_io;
+ unsigned char region;
+ unsigned short aud_mode;
+ unsigned int preemph;
unsigned long tx_frq;
struct tx_rds rds;
};
@@ -227,4 +236,26 @@ struct fmdrv_ops {
struct fm_rx rx; /* FM receiver info */
struct fmtx_data tx_data;
};
+
+/* TODO:
+ * move the following CIDs to videodev2.h upon acceptance
+ */
+
+#define V4L2_CTRL_CLASS_FM_RX 0x009c0000 /* FM Tuner control class */
+/* FM Tuner class control IDs */
+#define V4L2_CID_FM_RX_CLASS_BASE (V4L2_CTRL_CLASS_FM_RX | 0x900)
+#define V4L2_CID_FM_RX_CLASS (V4L2_CTRL_CLASS_FM_RX | 1)
+#define V4L2_CID_RSSI_THRESHOLD (V4L2_CID_FM_RX_CLASS_BASE + 2)
+#define V4L2_CID_TUNE_AF (V4L2_CID_FM_RX_CLASS_BASE + 3)
+enum v4l2_tune_af {
+ V4L2_FM_AF_OFF = 0,
+ V4L2_FM_AF_ON = 1
+};
+#define V4L2_CID_FM_BAND (V4L2_CID_FM_RX_CLASS_BASE + 1)
+enum v4l2_fm_band {
+ V4L2_FM_BAND_OTHER = 0,
+ V4L2_FM_BAND_JAPAN = 1,
+ V4L2_FM_BAND_OIRT = 2
+};
+
#endif
diff --git a/drivers/staging/ti-st/fmdrv_common.c b/drivers/staging/ti-st/fmdrv_common.c
index ae3641a04da9..dbc6c4fe2d53 100644
--- a/drivers/staging/ti-st/fmdrv_common.c
+++ b/drivers/staging/ti-st/fmdrv_common.c
@@ -14,6 +14,7 @@
* firmware files based on mode selection)
*
* Copyright (C) 2010 Texas Instruments
+ * Author: Raja Mani <raja_mani@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -37,158 +38,9 @@
#include "fmdrv_v4l2.h"
#include "fmdrv_common.h"
#include "st.h"
+#include "st_kim.h"
#include "fmdrv_rx.h"
-/* TODO: Enable when FM TX is supported */
-/* #include "fmdrv_tx.h" */
-
-#ifndef DEBUG
-#ifdef pr_info
-#undef pr_info
-#define pr_info(fmt, arg...)
-#endif
-#endif
-
-/* FM chip register table */
-static struct fm_reg_table fm_reg_info[] = {
- /* ----- FM RX registers -------*/
- /* opcode, type(rd/wr), reg name */
- {0x00, REG_RD, "STEREO_GET"},
- {0x01, REG_RD, "RSSI_LVL_GET"},
- {0x02, REG_RD, "IF_COUNT_GET"},
- {0x03, REG_RD, "FLAG_GET"},
- {0x04, REG_RD, "RDS_SYNC_GET"},
- {0x05, REG_RD, "RDS_DATA_GET"},
- {0x0a, REG_WR, "FREQ_SET"},
- {0x0a, REG_RD, "FREQ_GET"},
- {0x0b, REG_WR, "AF_FREQ_SET"},
- {0x0b, REG_RD, "AF_FREQ_GET"},
- {0x0c, REG_WR, "MOST_MODE_SET"},
- {0x0c, REG_RD, "MOST_MODE_GET"},
- {0x0d, REG_WR, "MOST_BLEND_SET"},
- {0x0d, REG_RD, "MOST_BLEND_GET"},
- {0x0e, REG_WR, "DEMPH_MODE_SET"},
- {0x0e, REG_RD, "DEMPH_MODE_GET"},
- {0x0f, REG_WR, "SEARCH_LVL_SET"},
- {0x0f, REG_RD, "SEARCH_LVL_GET"},
- {0x10, REG_WR, "RX_BAND_SET"},
- {0x10, REG_RD, "RX_BAND_GET"},
- {0x11, REG_WR, "MUTE_STATUS_SET"},
- {0x11, REG_RD, "MUTE_STATUS_GET"},
- {0x12, REG_WR, "RDS_PAUSE_LVL_SET"},
- {0x12, REG_RD, "RDS_PAUSE_LVL_GET"},
- {0x13, REG_WR, "RDS_PAUSE_DUR_SET"},
- {0x13, REG_RD, "RDS_PAUSE_DUR_GET"},
- {0x14, REG_WR, "RDS_MEM_SET"},
- {0x14, REG_RD, "RDS_MEM_GET"},
- {0x15, REG_WR, "RDS_BLK_B_SET"},
- {0x15, REG_RD, "RDS_BLK_B_GET"},
- {0x16, REG_WR, "RDS_MSK_B_SET"},
- {0x16, REG_RD, "RDS_MSK_B_GET"},
- {0x17, REG_WR, "RDS_PI_MASK_SET"},
- {0x17, REG_RD, "RDS_PI_MASK_GET"},
- {0x18, REG_WR, "RDS_PI_SET"},
- {0x18, REG_RD, "RDS_PI_GET"},
- {0x19, REG_WR, "RDS_SYSTEM_SET"},
- {0x19, REG_RD, "RDS_SYSTEM_GET"},
- {0x1a, REG_WR, "INT_MASK_SET"},
- {0x1a, REG_RD, "INT_MASK_GET"},
- {0x1b, REG_WR, "SRCH_DIR_SET"},
- {0x1b, REG_RD, "SRCH_DIR_GET"},
- {0x1c, REG_WR, "VOLUME_SET"},
- {0x1c, REG_RD, "VOLUME_GET"},
- {0x1d, REG_WR, "AUDIO_ENABLE(SET)"},
- {0x1d, REG_RD, "AUDIO_ENABLE(GET)"},
- {0x1e, REG_WR, "PCM_MODE_SET"},
- {0x1e, REG_RD, "PCM_MODE_SET"},
- {0x1f, REG_WR, "I2S_MD_CFG_SET"},
- {0x1f, REG_RD, "I2S_MD_CFG_GET"},
- {0x20, REG_WR, "POWER_SET"},
- {0x20, REG_RD, "POWER_GET"},
- {0x21, REG_WR, "INTx_CONFIG_SET"},
- {0x21, REG_RD, "INTx_CONFIG_GET"},
- {0x22, REG_WR, "PULL_EN_SET"},
- {0x22, REG_RD, "PULL_EN_GET"},
- {0x23, REG_WR, "HILO_SET"},
- {0x23, REG_RD, "HILO_GET"},
- {0x24, REG_WR, "SWITCH2FREF"},
- {0x25, REG_WR, "FREQ_DRIFT_REP"},
- {0x28, REG_RD, "PCE_GET"},
- {0x29, REG_RD, "FIRM_VER_GET"},
- {0x2a, REG_RD, "ASIC_VER_GET"},
- {0x2b, REG_RD, "ASIC_ID_GET"},
- {0x2c, REG_RD, "MAIN_ID_GET"},
- {0x2d, REG_WR, "TUNER_MODE_SET"},
- {0x2e, REG_WR, "STOP_SEARCH"},
- {0x2f, REG_WR, "RDS_CNTRL_SET"},
- {0x64, REG_WR, "WR_HW_REG"},
- {0x65, REG_WR, "CODE_DOWNLOAD"},
- {0x66, REG_WR, "RESET"},
- {0xfe, REG_WR, "FM_POWER_MODE(SET)"},
- {0xff, REG_RD, "FM_INTERRUPT"},
-
- /* --- FM TX registers ------ */
- {0x37, REG_WR, "CHANL_SET"},
- {0x37, REG_RD, "CHANL_GET"},
- {0x38, REG_WR, "CHANL_BW_SET"},
- {0x38, REG_RD, "CHANL_BW_GET"},
- {0x87, REG_WR, "REF_SET"},
- {0x87, REG_RD, "REF_GET"},
- {0x5a, REG_WR, "POWER_ENB_SET"},
- {0x3a, REG_WR, "POWER_ATT_SET"},
- {0x3a, REG_RD, "POWER_ATT_GET"},
- {0x3b, REG_WR, "POWER_LEL_SET"},
- {0x3b, REG_RD, "POWER_LEL_GET"},
- {0x3c, REG_WR, "AUDIO_DEV_SET"},
- {0x3c, REG_RD, "AUDIO_DEV_GET"},
- {0x3d, REG_WR, "PILOT_DEV_SET"},
- {0x3d, REG_RD, "PILOT_DEV_GET"},
- {0x3e, REG_WR, "RDS_DEV_SET"},
- {0x3e, REG_RD, "RDS_DEV_GET"},
- {0x5b, REG_WR, "PUPD_SET"},
- {0x3f, REG_WR, "AUDIO_IO_SET"},
- {0x40, REG_WR, "PREMPH_SET"},
- {0x40, REG_RD, "PREMPH_GET"},
- {0x41, REG_WR, "TX_BAND_SET"},
- {0x41, REG_RD, "TX_BAND_GET"},
- {0x42, REG_WR, "MONO_SET"},
- {0x42, REG_RD, "MONO_GET"},
- {0x5C, REG_WR, "MUTE"},
- {0x43, REG_WR, "MPX_LMT_ENABLE"},
- {0x06, REG_RD, "LOCK_GET"},
- {0x5d, REG_WR, "REF_ERR_SET"},
- {0x44, REG_WR, "PI_SET"},
- {0x44, REG_RD, "PI_GET"},
- {0x45, REG_WR, "TYPE_SET"},
- {0x45, REG_RD, "TYPE_GET"},
- {0x46, REG_WR, "PTY_SET"},
- {0x46, REG_RD, "PTY_GET"},
- {0x47, REG_WR, "AF_SET"},
- {0x47, REG_RD, "AF_GET"},
- {0x48, REG_WR, "DISPLAY_SIZE_SET"},
- {0x48, REG_RD, "DISPLAY_SIZE_GET"},
- {0x49, REG_WR, "RDS_MODE_SET"},
- {0x49, REG_RD, "RDS_MODE_GET"},
- {0x4a, REG_WR, "DISPLAY_MODE_SET"},
- {0x4a, REG_RD, "DISPLAY_MODE_GET"},
- {0x62, REG_WR, "LENGHT_SET"},
- {0x4b, REG_RD, "LENGHT_GET"},
- {0x4c, REG_WR, "TOGGLE_AB_SET"},
- {0x4c, REG_RD, "TOGGLE_AB_GET"},
- {0x4d, REG_WR, "RDS_REP_SET"},
- {0x4d, REG_RD, "RDS_REP_GET"},
- {0x63, REG_WR, "RDS_DATA_SET"},
- {0x5e, REG_WR, "RDS_DATA_ENB"},
- {0x4e, REG_WR, "TA_SET"},
- {0x4e, REG_RD, "TA_GET"},
- {0x4f, REG_WR, "TP_SET"},
- {0x4f, REG_RD, "TP_GET"},
- {0x50, REG_WR, "DI_SET"},
- {0x50, REG_RD, "DI_GET"},
- {0x51, REG_WR, "MS_SET"},
- {0x51, REG_RD, "MS_GET"},
- {0x52, REG_WR, "PS_SCROLL_SPEED_SET"},
- {0x52, REG_RD, "PS_SCROLL_SPEED_GET"},
-};
+#include "fmdrv_tx.h"
/* Region info */
static struct region_info region_configs[] = {
@@ -250,10 +102,11 @@ static void fm_irq_handle_low_rssi_finish(void *);
static void fm_irq_send_intmsk_cmd(void *);
static void fm_irq_handle_intmsk_cmd_resp(void *);
-/* When FM common module receives interrupt packet, following handlers
+/*
+ * When FM common module receives interrupt packet, following handlers
* will be executed one after another to service the interrupt(s)
*/
-enum fmc_irq_handler_index{
+enum fmc_irq_handler_index {
FM_SEND_FLAG_GETCMD_INDEX,
FM_HANDLE_FLAG_GETCMD_RESP_INDEX,
@@ -384,7 +237,8 @@ void fmc_update_region_info(struct fmdrv_ops *fmdev,
sizeof(struct region_info));
}
-/* FM common sub-module will schedule this tasklet whenever it receives
+/*
+ * FM common sub-module will schedule this tasklet whenever it receives
* FM packet from ST driver.
*/
static void __recv_tasklet(unsigned long arg)
@@ -400,7 +254,7 @@ static void __recv_tasklet(unsigned long arg)
while ((skb = skb_dequeue(&fmdev->rx_q))) {
if (skb->len < sizeof(struct fm_event_msg_hdr)) {
pr_err("(fmdrv): skb(%p) has only %d bytes"
- "atleast need %d bytes to decode",
+ "atleast need %d bytes to decode\n",
skb, skb->len,
sizeof(struct fm_event_msg_hdr));
kfree_skb(skb);
@@ -411,18 +265,19 @@ static void __recv_tasklet(unsigned long arg)
num_fm_hci_cmds = fm_evt_hdr->num_fm_hci_cmds;
/* FM interrupt packet? */
- if (fm_evt_hdr->fm_opcode == fm_reg_info[FM_INTERRUPT].opcode) {
+ if (fm_evt_hdr->fm_opcode == FM_INTERRUPT) {
/* FM interrupt handler started already? */
if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
set_bit(FM_INTTASK_RUNNING, &fmdev->flag);
if (fmdev->irq_info.stage_index != 0) {
pr_err("(fmdrv): Invalid stage index,"
- "resetting to zero");
+ "resetting to zero\n");
fmdev->irq_info.stage_index = 0;
}
- /* Execute first function
- * in interrupt handler table
+ /*
+ * Execute first function in interrupt handler
+ * table.
*/
fmdev->irq_info.fm_int_handlers
[fmdev->irq_info.stage_index](fmdev);
@@ -436,7 +291,7 @@ static void __recv_tasklet(unsigned long arg)
else if (fm_evt_hdr->fm_opcode == fmdev->last_sent_pkt_opcode &&
fmdev->response_completion != NULL) {
if (fmdev->response_skb != NULL)
- pr_err("(fmdrv): Response SKB ptr not NULL");
+ pr_err("(fmdrv): Response SKB ptr not NULL\n");
spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
fmdev->response_skb = skb;
@@ -450,7 +305,7 @@ static void __recv_tasklet(unsigned long arg)
else if (fm_evt_hdr->fm_opcode == fmdev->last_sent_pkt_opcode &&
fmdev->response_completion == NULL) {
if (fmdev->response_skb != NULL)
- pr_err("(fmdrv): Response SKB ptr not NULL");
+ pr_err("(fmdrv): Response SKB ptr not NULL\n");
spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
fmdev->response_skb = skb;
@@ -463,12 +318,13 @@ static void __recv_tasklet(unsigned long arg)
kfree_skb(skb);
atomic_set(&fmdev->tx_cnt, 1);
} else {
- pr_err("(fmdrv): Nobody claimed SKB(%p),purging", skb);
+ pr_err("(fmdrv): Nobody claimed SKB(%p),purging\n",
+ skb);
}
- /* Check flow control field.
- * If Num_FM_HCI_Commands field is not zero,
- * schedule FM TX tasklet.
+ /*
+ * Check flow control field. If Num_FM_HCI_Commands field is
+ * not zero, schedule FM TX tasklet.
*/
if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) {
if (!skb_queue_empty(&fmdev->tx_q))
@@ -488,7 +344,7 @@ static void __send_tasklet(unsigned long arg)
/* Check, is there any timeout happenned to last transmitted packet */
if (!atomic_read(&fmdev->tx_cnt) &&
((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT)) {
- pr_err("(fmdrv): TX timeout occurred");
+ pr_err("(fmdrv): TX timeout occurred\n");
atomic_set(&fmdev->tx_cnt, 1);
}
/* Send queued FM TX packets */
@@ -500,7 +356,7 @@ static void __send_tasklet(unsigned long arg)
if (fmdev->response_completion != NULL)
pr_err("(fmdrv): Response completion handler"
- "is not NULL");
+ "is not NULL\n");
fmdev->response_completion = fm_cb(skb)->completion;
@@ -509,8 +365,8 @@ static void __send_tasklet(unsigned long arg)
if (len < 0) {
kfree_skb(skb);
fmdev->response_completion = NULL;
- pr_err("(fmdrv): TX tasklet failed to send" \
- "skb(%p)", skb);
+ pr_err("(fmdrv): TX tasklet failed to send"
+ "skb(%p)\n", skb);
atomic_set(&fmdev->tx_cnt, 1);
} else {
fmdev->last_tx_jiffies = jiffies;
@@ -519,10 +375,13 @@ static void __send_tasklet(unsigned long arg)
}
}
-/* Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
- * transmission */
-static int __fm_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
- void *payload, int payload_len,
+/*
+ * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
+ * transmission
+ */
+static int __fm_send_cmd(struct fmdrv_ops *fmdev, unsigned char fm_opcode,
+ unsigned short int type, void *payload,
+ int payload_len,
struct completion *wait_completion)
{
struct sk_buff *skb;
@@ -530,13 +389,13 @@ static int __fm_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
int size;
- if (fmreg_index >= FM_REG_MAX_ENTRIES) {
- pr_err("(fmdrv): Invalid fm register index");
+ if (fm_opcode >= FM_INTERRUPT) {
+ pr_err("(fmdrv): Invalid fm register index\n");
return -EINVAL;
}
if (test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag) &&
payload == NULL) {
- pr_err("(fmdrv): Payload data is NULL during fw download");
+ pr_err("(fmdrv): Payload data is NULL during fw download\n");
return -EINVAL;
}
if (!test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag))
@@ -547,11 +406,13 @@ static int __fm_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
skb = alloc_skb(size, GFP_ATOMIC);
if (!skb) {
- pr_err("(fmdrv): No memory to create new SKB");
+ pr_err("(fmdrv): No memory to create new SKB\n");
return -ENOMEM;
}
- /* Don't fill FM header info for the commands which come from
- * FM firmware file */
+ /*
+ * Don't fill FM header info for the commands which come from
+ * FM firmware file.
+ */
if (!test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag) ||
test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
/* Fill command header info */
@@ -561,11 +422,20 @@ static int __fm_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
/* 3 (fm_opcode,rd_wr,dlen) + payload len) */
cmd_hdr->len = ((payload == NULL) ? 0 : payload_len) + 3;
/* FM opcode */
- cmd_hdr->fm_opcode = fm_reg_info[fmreg_index].opcode;
+ cmd_hdr->fm_opcode = fm_opcode;
/* read/write type */
- cmd_hdr->rd_wr = fm_reg_info[fmreg_index].type;
+ cmd_hdr->rd_wr = type;
cmd_hdr->dlen = payload_len;
- fm_cb(skb)->fm_opcode = fm_reg_info[fmreg_index].opcode;
+ fm_cb(skb)->fm_opcode = fm_opcode;
+ /*
+ * If firmware download has finished and the command is
+ * not a read command then payload is != NULL - a write
+ * command with unsigned short payload - convert to be16
+ */
+ if (payload != NULL) {
+ *(unsigned short *)payload =
+ cpu_to_be16(*(unsigned short *)payload);
+ }
} else if (payload != NULL) {
fm_cb(skb)->fm_opcode = *((char *)payload + 2);
}
@@ -580,10 +450,9 @@ static int __fm_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
}
/* Sends FM Channel-8 command to the chip and waits for the reponse */
-int fmc_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
- void *payload, int payload_len,
- struct completion *wait_completion, void *reponse,
- int *reponse_len)
+int fmc_send_cmd(struct fmdrv_ops *fmdev, unsigned char fm_opcode,
+ unsigned short int type, void *payload, int payload_len,
+ void *reponse, int *reponse_len)
{
struct sk_buff *skb;
struct fm_event_msg_hdr *fm_evt_hdr;
@@ -591,23 +460,25 @@ int fmc_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
unsigned long flags;
int ret;
- init_completion(wait_completion);
- ret = __fm_send_cmd(fmdev, fmreg_index, payload, payload_len,
- wait_completion);
+ init_completion(&fmdev->maintask_completion);
+ ret = __fm_send_cmd(fmdev, fm_opcode, type, payload, payload_len,
+ &fmdev->maintask_completion);
if (ret < 0)
- return ret;
+ goto exit;
- timeleft = wait_for_completion_timeout(wait_completion,
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
FM_DRV_TX_TIMEOUT);
if (!timeleft) {
pr_err("(fmdrv): Timeout(%d sec),didn't get reg"
- "completion signal from RX tasklet",
+ "completion signal from RX tasklet\n",
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
return -ETIMEDOUT;
+ goto exit;
}
if (!fmdev->response_skb) {
- pr_err("(fmdrv): Reponse SKB is missing ");
+ pr_err("(fmdrv): Reponse SKB is missing\n");
return -EFAULT;
+ goto exit;
}
spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
skb = fmdev->response_skb;
@@ -616,10 +487,11 @@ int fmc_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
fm_evt_hdr = (void *)skb->data;
if (fm_evt_hdr->status != 0) {
- pr_err("(fmdrv): Received event pkt status(%d) is not zero",
+ pr_err("(fmdrv): Received event pkt status(%d) is not zero\n",
fm_evt_hdr->status);
kfree_skb(skb);
- return -EIO;
+ ret = -EIO;
+ goto exit;
}
/* Send reponse data to caller */
if (reponse != NULL && reponse_len != NULL && fm_evt_hdr->dlen) {
@@ -631,7 +503,13 @@ int fmc_send_cmd(struct fmdrv_ops *fmdev, unsigned char fmreg_index,
*reponse_len = 0;
}
kfree_skb(skb);
- return 0;
+exit:
+ if (ret < 0) {
+ pr_err("(fmdrv): Command %d failed\n", fm_opcode);
+ return ret;
+ }
+
+ return ret;
}
/* --- Helper functions used in FM interrupt handlers ---*/
@@ -648,7 +526,7 @@ static inline int __check_cmdresp_status(struct fmdrv_ops *fmdev,
fm_evt_hdr = (void *)(*skb)->data;
if (fm_evt_hdr->status != 0) {
- pr_err("(fmdrv): irq: opcode %x response status is not zero",
+ pr_err("(fmdrv): irq: opcode %x response status is not zero\n",
fm_evt_hdr->fm_opcode);
return -1;
}
@@ -656,7 +534,8 @@ static inline int __check_cmdresp_status(struct fmdrv_ops *fmdev,
return 0;
}
-/* Interrupt process timeout handler.
+/*
+ * Interrupt process timeout handler.
* One of the irq handler did not get proper response from the chip. So take
* recovery action here. FM interrupts are disabled in the beginning of
* interrupt process. Therefore reset stage index to re-enable default
@@ -666,7 +545,7 @@ static void __int_timeout_handler(unsigned long data)
{
struct fmdrv_ops *fmdev;
- pr_info("(fmdrv): irq: timeout,trying to re-enable fm interrupts");
+ pr_debug("(fmdrv): irq: timeout,trying to re-enable fm interrupts\n");
fmdev = (struct fmdrv_ops *)data;
fmdev->irq_info.irq_service_timeout_retry++;
@@ -676,13 +555,14 @@ static void __int_timeout_handler(unsigned long data)
fmdev->irq_info.fm_int_handlers[fmdev->irq_info.
stage_index] (fmdev);
} else {
- /* Stop recovery action (interrupt reenable process) and
+ /*
+ * Stop recovery action (interrupt reenable process) and
* reset stage index & retry count values
*/
fmdev->irq_info.stage_index = 0;
fmdev->irq_info.irq_service_timeout_retry = 0;
- pr_err("(fmdrv): Recovery action failed during \
- irq processing, max retry reached");
+ pr_err("(fmdrv): Recovery action failed during"
+ "irq processing, max retry reached\n");
}
}
@@ -695,10 +575,10 @@ static void fm_irq_send_flag_getcmd(void *arg)
fmdev = arg;
/* Send FLAG_GET command , to know the source of interrupt */
- ret = __fm_send_cmd(fmdev, FLAG_GET, NULL, sizeof(flag), NULL);
+ ret = __fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL);
if (ret)
pr_err("(fmdrv): irq: failed to send flag_get command,"
- "initiating irq recovery process");
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index = FM_HANDLE_FLAG_GETCMD_RESP_INDEX;
@@ -718,7 +598,7 @@ static void fm_irq_handle_flag_getcmd_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -729,8 +609,8 @@ static void fm_irq_handle_flag_getcmd_resp(void *arg)
skb_pull(skb, sizeof(struct fm_event_msg_hdr));
memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
- FM_STORE_BE16_TO_LE16(fmdev->irq_info.flag, fmdev->irq_info.flag);
- pr_info("(fmdrv): irq: flag register(0x%x)", fmdev->irq_info.flag);
+ fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag);
+ pr_debug("(fmdrv): irq: flag register(0x%x)\n", fmdev->irq_info.flag);
/* Continue next function in interrupt handler table */
fmdev->irq_info.stage_index = FM_HW_MAL_FUNC_INDEX;
@@ -744,7 +624,7 @@ static void fm_irq_handle_hw_malfunction(void *arg)
fmdev = arg;
if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask)
- pr_err("(fmdrv): irq: HW MAL interrupt received - do nothing");
+ pr_err("(fmdrv): irq: HW MAL int received - do nothing\n");
/* Continue next function in interrupt handler table */
fmdev->irq_info.stage_index = FM_RDS_START_INDEX;
@@ -757,7 +637,7 @@ static void fm_irq_handle_rds_start(void *arg)
fmdev = arg;
if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) {
- pr_info("(fmdrv): irq: rds threshold reached");
+ pr_debug("(fmdrv): irq: rds threshold reached\n");
fmdev->irq_info.stage_index = FM_RDS_SEND_RDS_GETCMD_INDEX;
} else {
/* Continue next function in interrupt handler table */
@@ -773,11 +653,11 @@ static void fm_irq_send_rdsdata_getcmd(void *arg)
fmdev = arg;
/* Send the command to read RDS data from the chip */
- ret = __fm_send_cmd(fmdev, RDS_DATA_GET, NULL,
+ ret = __fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL,
(FM_RX_RDS_FIFO_THRESHOLD * 3), NULL);
if (ret < 0)
pr_err("(fmdrv): irq : failed to send rds get command,"
- "initiating irq recovery process");
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index =
FM_RDS_HANDLE_RDS_GETCMD_RESP_INDEX;
@@ -799,7 +679,7 @@ static void __fm_rx_update_af_cache(struct fmdrv_ops *fmdev,
fmdev->rx.cur_station_info.af_list_max =
(af - FM_RDS_1_AF_FOLLOWS + 1);
fmdev->rx.cur_station_info.no_of_items_in_afcache = 0;
- pr_info("(fmdrv): No of expected AF : %d",
+ pr_debug("(fmdrv): No of expected AF : %d\n",
fmdev->rx.cur_station_info.af_list_max);
} else if (((af >= FM_RDS_MIN_AF)
&& (fmdev->rx.region.region_index == FM_BAND_EUROPE_US)
@@ -811,8 +691,8 @@ static void __fm_rx_update_af_cache(struct fmdrv_ops *fmdev,
FM_RDS_MAX_AF_JAPAN))) {
freq = fmdev->rx.region.bottom_frequency + (af * 100);
if (freq == fmdev->rx.curr_freq) {
- pr_info("(fmdrv): Current frequency(%d) is \
- matching with received AF(%d)",
+ pr_debug("(fmdrv): Current frequency(%d) is"
+ "matching with received AF(%d)\n",
fmdev->rx.curr_freq, freq);
return;
}
@@ -825,15 +705,16 @@ static void __fm_rx_update_af_cache(struct fmdrv_ops *fmdev,
}
/* Reached the limit of the list - ignore the next AF */
if (index == fmdev->rx.cur_station_info.af_list_max) {
- pr_info("(fmdrv): AF cache is full");
+ pr_debug("(fmdrv): AF cache is full\n");
return;
}
- /* If we reached the end of the list then
- * this AF is not in the list - add it
+ /*
+ * If we reached the end of the list then this AF is not
+ * in the list - add it.
*/
if (index == fmdev->rx.cur_station_info.
no_of_items_in_afcache) {
- pr_info("(fmdrv): Storing AF %d to AF cache index %d",
+ pr_debug("(fmdrv): Storing AF %d to cache index %d\n",
freq, index);
fmdev->rx.cur_station_info.af_cache[index] = freq;
fmdev->rx.cur_station_info.no_of_items_in_afcache++;
@@ -841,8 +722,9 @@ static void __fm_rx_update_af_cache(struct fmdrv_ops *fmdev,
}
}
-/* Converts RDS buffer data from big endian format
- * to little endian format
+/*
+ * Converts RDS buffer data from big endian format
+ * to little endian format.
*/
static void __fm_rdsparse_swapbytes(struct fmdrv_ops *fmdev,
struct fm_rdsdata_format *rds_format)
@@ -851,9 +733,11 @@ static void __fm_rdsparse_swapbytes(struct fmdrv_ops *fmdev,
unsigned char index = 0;
char *rds_buff;
- /* Since in Orca the 2 RDS Data bytes are in little endian and
+ /*
+ * Since in Orca the 2 RDS Data bytes are in little endian and
* in Dolphin they are in big endian, the parsing of the RDS data
- * is chip dependent */
+ * is chip dependent
+ */
if (fmdev->asci_id != 0x6350) {
rds_buff = &rds_format->rdsdata.groupdatabuff.rdsbuff[0];
while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) {
@@ -884,7 +768,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -897,22 +781,28 @@ static void fm_irq_handle_rdsdata_getcmd_resp(void *arg)
/* Parse the RDS data */
while (rds_len >= FM_RDS_BLOCK_SIZE) {
meta_data = rds_data[2];
- /* Get the type:
- * 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */
+ /*
+ * Get the type:
+ * 0=A, 1=B, 2=C, 3=C', 4=D, 5=E
+ */
type = (meta_data & 0x07);
- /* Transform the block type
- * into an index sequence (0, 1, 2, 3, 4) */
+ /*
+ * Transform the block type into an
+ * index sequence (0, 1, 2, 3, 4)
+ */
block_index = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
- pr_info("(fmdrv): Block index:%d(%s) ", block_index,
+ pr_debug("(fmdrv): Block index:%d(%s)\n", block_index,
(meta_data & FM_RDS_STATUS_ERROR_MASK) ? "Bad" :
"Ok");
if (((meta_data & FM_RDS_STATUS_ERROR_MASK) == 0)
&& (block_index == FM_RDS_BLOCK_INDEX_A
|| (block_index == fmdev->rx.rds.last_block_index + 1
&& block_index <= FM_RDS_BLOCK_INDEX_D))) {
- /* Skip checkword (control) byte
- * and copy only data byte */
+ /*
+ * Skip checkword (control) byte and copy only data
+ * byte
+ */
memcpy(&rds_format.rdsdata.groupdatabuff.
rdsbuff[block_index * (FM_RDS_BLOCK_SIZE - 1)],
rds_data, (FM_RDS_BLOCK_SIZE - 1));
@@ -920,24 +810,25 @@ static void fm_irq_handle_rdsdata_getcmd_resp(void *arg)
/* If completed a whole group then handle it */
if (block_index == FM_RDS_BLOCK_INDEX_D) {
- pr_info("(fmdrv): Good block received");
+ pr_debug("(fmdrv): Good block received\n");
__fm_rdsparse_swapbytes(fmdev, &rds_format);
- /* Extract PI code and store in local cache.
- * We need this during AF switch processing */
- cur_picode =
- FM_BE16_TO_LE16(rds_format.rdsdata.
- groupgeneral.pidata);
+ /*
+ * Extract PI code and store in local cache.
+ * We need this during AF switch processing.
+ */
+ cur_picode = be16_to_cpu
+ (rds_format.rdsdata.groupgeneral.pidata);
if (fmdev->rx.cur_station_info.picode !=
cur_picode)
fmdev->rx.cur_station_info.picode =
cur_picode;
- pr_info("(fmdrv): picode:%d", cur_picode);
+ pr_debug("(fmdrv): picode:%d\n", cur_picode);
group_index =
(rds_format.rdsdata.groupgeneral.
block_b_byte1 >> 3);
- pr_info("(fmdrv):Group:%ld%s", group_index / 2,
+ pr_debug("(fmdrv):Group:%ld%s\n", group_index/2,
(group_index % 2) ? "B" : "A");
group_index =
@@ -953,7 +844,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(void *arg)
}
}
} else {
- pr_info("(fmdrv): Block sequence mismatch");
+ pr_debug("(fmdrv): Block sequence mismatch\n");
fmdev->rx.rds.last_block_index = -1;
}
rds_len -= FM_RDS_BLOCK_SIZE;
@@ -966,7 +857,8 @@ static void fm_irq_handle_rdsdata_getcmd_resp(void *arg)
spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
while (rds_len > 0) {
- /* Fill RDS buffer as per V4L2 specification.
+ /*
+ * Fill RDS buffer as per V4L2 specification.
* Store control byte
*/
type = (rds_data[2] & 0x07);
@@ -986,7 +878,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(void *arg)
/* Check for overflow & start over */
if (fmdev->rx.rds.wr_index == fmdev->rx.rds.rd_index) {
- pr_info("(fmdrv): RDS buffer overflow");
+ pr_debug("(fmdrv): RDS buffer overflow\n");
fmdev->rx.rds.wr_index = 0;
fmdev->rx.rds.rd_index = 0;
break;
@@ -1020,7 +912,7 @@ static void fm_irq_handle_tune_op_ended(void *arg)
fmdev = arg;
if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev->
irq_info.mask) {
- pr_info("(fmdrv): irq: tune ended/bandlimit reached");
+ pr_debug("(fmdrv): irq: tune ended/bandlimit reached\n");
if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) {
fmdev->irq_info.stage_index = FM_AF_JUMP_RD_FREQ_INDEX;
} else {
@@ -1039,7 +931,7 @@ static void fm_irq_handle_power_enb(void *arg)
fmdev = arg;
if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) {
- pr_info("(fmdrv): irq: Power Enabled/Disabled");
+ pr_debug("(fmdrv): irq: Power Enabled/Disabled\n");
complete(&fmdev->maintask_completion);
}
@@ -1057,8 +949,8 @@ static void fm_irq_handle_low_rssi_start(void *arg)
(fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) &&
(fmdev->rx.curr_freq != FM_UNDEFINED_FREQ) &&
(fmdev->rx.cur_station_info.no_of_items_in_afcache != 0)) {
- pr_info("(fmdrv): irq: rssi level has fallen below" \
- " threshold level");
+ pr_debug("(fmdrv): irq: rssi level has fallen below"
+ " threshold level\n");
/* Disable further low RSSI interrupts */
fmdev->irq_info.mask &= ~FM_LEV_EVENT;
@@ -1081,12 +973,12 @@ static void fm_irq_afjump_set_pi(void *arg)
fmdev = arg;
/* Set PI code - must be updated if the AF list is not empty */
- payload = FM_LE16_TO_BE16(fmdev->rx.cur_station_info.picode);
- ret = __fm_send_cmd(fmdev, RDS_PI_SET, &payload, sizeof(payload),
- NULL);
+ payload = fmdev->rx.cur_station_info.picode;
+ ret = __fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload,
+ sizeof(payload), NULL);
if (ret < 0)
pr_err("(fmdrv): irq : failed to set PI,"
- "initiating irq recovery process");
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index =
FM_AF_JUMP_HANDLE_SETPI_RESP_INDEX;
@@ -1106,7 +998,7 @@ static void fm_irq_handle_set_pi_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -1117,7 +1009,8 @@ static void fm_irq_handle_set_pi_resp(void *arg)
fmdev->irq_info.fm_int_handlers[fmdev->irq_info.stage_index](fmdev);
}
-/* Set PI mask.
+/*
+ * Set PI mask.
* 0xFFFF = Enable PI code matching
* 0x0000 = Disable PI code matching
*/
@@ -1129,11 +1022,11 @@ static void fm_irq_afjump_set_pimask(void *arg)
fmdev = arg;
payload = 0x0000;
- ret = __fm_send_cmd(fmdev, RDS_PI_MASK_SET, &payload, sizeof(payload),
- NULL);
+ ret = __fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL);
if (ret < 0)
- pr_err("(fmdrv): irq: failed to set PI mask,"
- "initiating irq recovery process");
+ pr_err("(fmdrv): irq: failed to set PI mask, "
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index =
FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_INDEX;
@@ -1153,7 +1046,7 @@ static void fm_irq_handle_set_pimask_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -1171,18 +1064,18 @@ static void fm_irq_afjump_setfreq(void *arg)
int ret;
fmdev = arg;
- pr_info("(fmdrv): Swtiching to %d KHz\n",
+ pr_debug("(fmdrv): Swtiching to %d KHz\n",
fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_afjump_index]);
frq_index =
(fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_afjump_index] -
fmdev->rx.region.bottom_frequency) / FM_FREQ_MUL;
- FM_STORE_LE16_TO_BE16(payload, frq_index);
- ret = __fm_send_cmd(fmdev, AF_FREQ_SET, &payload, sizeof(payload),
- NULL);
+ payload = frq_index;
+ ret = __fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload,
+ sizeof(payload), NULL);
if (ret < 0)
- pr_err("(fmdrv): irq : failed to set AF freq,"
- "initiating irq recovery process");
+ pr_err("(fmdrv): irq : failed to set AF freq, "
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index =
FM_AF_JUMP_HENDLE_SET_AFFREQ_RESP_INDEX;
@@ -1202,7 +1095,7 @@ static void fm_irq_handle_setfreq_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -1221,12 +1114,12 @@ static void fm_irq_afjump_enableint(void *arg)
fmdev = arg;
/* Enable FR (tuning operation ended) interrupt */
- payload = FM_LE16_TO_BE16(FM_FR_EVENT);
- ret = __fm_send_cmd(fmdev, INT_MASK_SET, &payload, sizeof(payload),
- NULL);
+ payload = FM_FR_EVENT;
+ ret = __fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL);
if (ret)
- pr_err("(fmdrv): irq : failed to enable FR interrupt,"
- "initiating irq recovery process");
+ pr_err("(fmdrv): irq : failed to enable FR interrupt, "
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index = FM_AF_JUMP_ENABLE_INT_RESP_INDEX;
@@ -1245,7 +1138,7 @@ static void fm_irq_afjump_enableint_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -1262,12 +1155,12 @@ static void fm_irq_start_afjump(void *arg)
int ret;
fmdev = arg;
- FM_STORE_LE16_TO_BE16(payload, FM_TUNER_AF_JUMP_MODE);
- ret = __fm_send_cmd(fmdev, TUNER_MODE_SET, &payload, sizeof(payload),
- NULL);
+ payload = FM_TUNER_AF_JUMP_MODE;
+ ret = __fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL);
if (ret)
- pr_err("(fmdrv): irq : failed to start af switch,"
- "initiating irq recovery process");
+ pr_err("(fmdrv): irq : failed to start af switch, "
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index =
FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_INDEX;
@@ -1287,7 +1180,7 @@ static void fm_irq_handle_start_afjump_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -1304,10 +1197,11 @@ static void fm_irq_afjump_rd_freq(void *arg)
int ret;
fmdev = arg;
- ret = __fm_send_cmd(fmdev, FREQ_GET, NULL, sizeof(payload), NULL);
+ ret = __fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL,
+ sizeof(payload), NULL);
if (ret < 0)
- pr_err("(fmdrv): irq: failed to read cur freq,"
- "initiating irq recovery process");
+ pr_err("(fmdrv): irq: failed to read cur freq, "
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index = FM_AF_JUMP_RD_FREQ_RESP_INDEX;
@@ -1329,7 +1223,7 @@ static void fm_irq_afjump_rd_freq_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
@@ -1337,7 +1231,7 @@ static void fm_irq_afjump_rd_freq_resp(void *arg)
/* Skip header info and copy only response data */
skb_pull(skb, sizeof(struct fm_event_msg_hdr));
memcpy(&read_freq, skb->data, sizeof(read_freq));
- read_freq = FM_BE16_TO_LE16(read_freq);
+ read_freq = be16_to_cpu(read_freq);
curr_freq = fmdev->rx.region.bottom_frequency +
((unsigned int)read_freq * FM_FREQ_MUL);
@@ -1347,8 +1241,8 @@ static void fm_irq_afjump_rd_freq_resp(void *arg)
/* If the frequency was changed the jump succeeded */
if ((curr_freq != fmdev->rx.freq_before_jump) &&
(curr_freq == jumped_freq)) {
- pr_info("(fmdrv): Successfully switched to alternate" \
- "frequency %d", curr_freq);
+ pr_debug("(fmdrv): Successfully switched to alternate"
+ "frequency %d\n", curr_freq);
fmdev->rx.curr_freq = curr_freq;
fm_rx_reset_rds_cache(fmdev);
@@ -1363,11 +1257,11 @@ static void fm_irq_afjump_rd_freq_resp(void *arg)
/* If we reached the end of the list - stop searching */
if (fmdev->rx.cur_afjump_index >=
fmdev->rx.cur_station_info.no_of_items_in_afcache) {
- pr_info("(fmdrv): AF switch processing failed");
+ pr_debug("(fmdrv): AF switch processing failed\n");
fmdev->irq_info.stage_index = FM_LOW_RSSI_FINISH_INDEX;
} else { /* AF List is not over - try next one */
- pr_info("(fmdrv): Trying next frequency in af cache");
+ pr_debug("(fmdrv): Trying next freq in AF cache\n");
fmdev->irq_info.stage_index = FM_AF_JUMP_SETPI_INDEX;
}
}
@@ -1393,12 +1287,12 @@ static void fm_irq_send_intmsk_cmd(void *arg)
fmdev = arg;
/* Re-enable FM interrupts */
- FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
- ret = __fm_send_cmd(fmdev, INT_MASK_SET, &payload, sizeof(payload),
- NULL);
+ payload = fmdev->irq_info.mask;
+ ret = __fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL);
if (ret)
- pr_err("(fmdrv): irq: failed to send int_mask_set cmd,"
- "initiating irq recovery process");
+ pr_err("(fmdrv): irq: failed to send int_mask_set cmd, "
+ "initiating irq recovery process\n");
else
fmdev->irq_info.stage_index = FM_HANDLE_INTMSK_CMD_RESP_INDEX;
@@ -1418,12 +1312,13 @@ static void fm_irq_handle_intmsk_cmd_resp(void *arg)
ret = __check_cmdresp_status(fmdev, &skb);
if (ret < 0) {
- pr_err("(fmdrv): Initiating irq recovery process");
+ pr_err("(fmdrv): Initiating irq recovery process\n");
mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
FM_DRV_TX_TIMEOUT);
return;
}
- /* This is last function in interrupt table to be executed.
+ /*
+ * This is last function in interrupt table to be executed.
* So, reset stage index to 0.
*/
fmdev->irq_info.stage_index = FM_SEND_FLAG_GETCMD_INDEX;
@@ -1505,9 +1400,8 @@ int fmc_set_frequency(struct fmdrv_ops *fmdev, unsigned int freq_to_set)
break;
case FM_MODE_TX:
- /* TODO: Enable when FM TX is supported */
- /* ret = fm_tx_set_frequency(fmdev, freq_to_set); */
- /* break; */
+ ret = fm_tx_set_frequency(fmdev, freq_to_set);
+ break;
default:
ret = -EINVAL;
@@ -1520,14 +1414,12 @@ int fmc_get_frequency(struct fmdrv_ops *fmdev, unsigned int *cur_tuned_frq)
int ret = 0;
if (fmdev->rx.curr_freq == FM_UNDEFINED_FREQ) {
- pr_err("(fmdrv): RX frequency is not set");
- ret = -EPERM;
- goto exit;
+ pr_err("(fmdrv): RX frequency is not set\n");
+ return -EPERM;
}
if (cur_tuned_frq == NULL) {
- pr_err("(fmdrv): Invalid memory");
- ret = -ENOMEM;
- goto exit;
+ pr_err("(fmdrv): Invalid memory\n");
+ return -ENOMEM;
}
switch (fmdev->curr_fmmode) {
@@ -1542,15 +1434,8 @@ int fmc_get_frequency(struct fmdrv_ops *fmdev, unsigned int *cur_tuned_frq)
default:
ret = -EINVAL;
}
-exit:
- return ret;
-}
-/* Returns current band index (0-Europe/US; 1-Japan) */
-int fmc_get_region(struct fmdrv_ops *fmdev, unsigned char *region)
-{
- *region = fmdev->rx.region.region_index;
- return 0;
+ return ret;
}
int fmc_set_region(struct fmdrv_ops *fmdev, unsigned char region_to_set)
@@ -1563,9 +1448,8 @@ int fmc_set_region(struct fmdrv_ops *fmdev, unsigned char region_to_set)
break;
case FM_MODE_TX:
- /* TODO: Enable when FM TX is supported */
- /* ret = fm_tx_set_region(fmdev, region_to_set); */
- /* break; */
+ ret = fm_tx_set_region(fmdev, region_to_set);
+ break;
default:
ret = -EINVAL;
@@ -1583,9 +1467,8 @@ int fmc_set_mute_mode(struct fmdrv_ops *fmdev, unsigned char mute_mode_toset)
break;
case FM_MODE_TX:
- /* TODO: Enable when FM TX is supported */
- /* ret = fm_tx_set_mute_mode(fmdev, mute_mode_toset); */
- /* break; */
+ ret = fm_tx_set_mute_mode(fmdev, mute_mode_toset);
+ break;
default:
ret = -EINVAL;
@@ -1603,9 +1486,8 @@ int fmc_set_stereo_mono(struct fmdrv_ops *fmdev, unsigned short mode)
break;
case FM_MODE_TX:
- /* TODO: Enable when FM TX is supported */
- /* ret = fm_tx_set_stereo_mono(fmdev, mode); */
- /* break; */
+ ret = fm_tx_set_stereo_mono(fmdev, mode);
+ break;
default:
ret = -EINVAL;
@@ -1623,9 +1505,8 @@ int fmc_set_rds_mode(struct fmdrv_ops *fmdev, unsigned char rds_en_dis)
break;
case FM_MODE_TX:
- /* TODO: Enable when FM TX is supported */
- /* ret = fm_tx_set_rds_mode(fmdev, rds_en_dis); */
- /* break; */
+ ret = fm_tx_set_rds_mode(fmdev, rds_en_dis);
+ break;
default:
ret = -EINVAL;
@@ -1640,25 +1521,24 @@ static int fm_power_down(struct fmdrv_ops *fmdev)
int ret = 0;
if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
- pr_err("(fmdrv): FM core is not ready");
- ret = -EPERM;
- goto exit;
+ pr_err("(fmdrv): FM core is not ready\n");
+ return -EPERM;
}
if (fmdev->curr_fmmode == FM_MODE_OFF) {
- pr_err("(fmdrv): FM chip is already in OFF state");
- goto exit;
+ pr_debug("(fmdrv): FM chip is already in OFF state\n");
+ return ret;
}
- FM_STORE_LE16_TO_BE16(payload, 0x0);
- ret = fmc_send_cmd(fmdev, FM_POWER_MODE, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = 0x0;
+ ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
ret = fmc_release(fmdev);
if (ret < 0)
- pr_err("(fmdrv): FM CORE release failed");
+ pr_err("(fmdrv): FM CORE release failed\n");
-exit:
return ret;
}
@@ -1678,13 +1558,12 @@ static int fm_download_firmware(struct fmdrv_ops *fmdev,
ret = request_firmware(&fw_entry, firmware_name,
&fmdev->radio_dev->dev);
- if ((ret < 0) || (fw_entry == NULL) || (fw_entry->data == NULL) ||
- (fw_entry->size == 0)) {
+ if (ret < 0) {
pr_err("(fmdrv): Unable to read firmware(%s) content\n",
firmware_name);
- goto exit;
+ return ret;
}
- pr_info("(fmdrv): Firmware(%s) length : %d bytes", firmware_name,
+ pr_debug("(fmdrv): Firmware(%s) length : %d bytes\n", firmware_name,
fw_entry->size);
fw_data = (void *)fw_entry->data;
@@ -1692,12 +1571,12 @@ static int fm_download_firmware(struct fmdrv_ops *fmdev,
fw_header = (struct bts_header *)fw_data;
if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) {
- pr_err("(fmdrv): %s not a legal TI firmware file",
+ pr_err("(fmdrv): %s not a legal TI firmware file\n",
firmware_name);
ret = -EINVAL;
- goto exit;
+ goto rel_fw;
}
- pr_info("(fmdrv): Firmware(%s) magic number : 0x%x", firmware_name,
+ pr_debug("(fmdrv): Firmware(%s) magic number : 0x%x\n", firmware_name,
fw_header->magic);
/* Skip file header info , we already verified it */
@@ -1709,11 +1588,10 @@ static int fm_download_firmware(struct fmdrv_ops *fmdev,
switch (action->type) {
case ACTION_SEND_COMMAND: /* Send */
- ret = fmc_send_cmd(fmdev, 0, action->data,
- action->size, &fmdev->maintask_completion,
- NULL, NULL);
+ ret = fmc_send_cmd(fmdev, 0, 0, action->data,
+ action->size, NULL, NULL);
if (ret < 0)
- goto exit;
+ goto rel_fw;
cmd_cnt++;
break;
@@ -1727,10 +1605,11 @@ static int fm_download_firmware(struct fmdrv_ops *fmdev,
fw_data += (sizeof(struct bts_action) + (action->size));
fw_len -= (sizeof(struct bts_action) + (action->size));
}
- pr_info("(fmdrv): Firmare commands(%d) loaded to the chip", cmd_cnt);
-exit:
+ pr_debug("(fmdrv): Firmare commands(%d) loaded to chip\n", cmd_cnt);
+rel_fw:
release_firmware(fw_entry);
clear_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag);
+
return ret;
}
@@ -1755,71 +1634,64 @@ static int fm_power_up(struct fmdrv_ops *fmdev, unsigned char fw_option)
char fw_name[50];
if (fw_option >= FM_MODE_ENTRY_MAX) {
- pr_err("(fmdrv): Invalid firmware download option");
- ret = -EINVAL;
- goto exit;
+ pr_err("(fmdrv): Invalid firmware download option\n");
+ return -EINVAL;
}
- /* Initialize FM common module. FM GPIO toggling is
+ /*
+ * Initialize FM common module. FM GPIO toggling is
* taken care in Shared Transport driver.
*/
ret = fmc_prepare(fmdev);
if (ret < 0) {
- pr_err("(fmdrv): Unable to prepare FM Common");
- goto exit;
+ pr_err("(fmdrv): Unable to prepare FM Common\n");
+ return ret;
}
- FM_STORE_LE16_TO_BE16(payload, FM_ENABLE);
- ret = fmc_send_cmd(fmdev, FM_POWER_MODE, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- if (ret < 0) {
- pr_err("(fmdrv): Failed enable FM over Channel 8");
+ payload = FM_ENABLE;
+ ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
goto rel;
- }
/* Allow the chip to settle down in Channel-8 mode */
- msleep(5);
+ msleep(20);
- ret = fmc_send_cmd(fmdev, ASIC_ID_GET, NULL, sizeof(asic_id),
- &fmdev->maintask_completion, &asic_id,
- &resp_len);
- if (ret < 0) {
- pr_err("(fmdrv): Failed read FM chip ASIC ID");
+ ret = fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL,
+ sizeof(asic_id), &asic_id, &resp_len);
+ if (ret < 0)
goto rel;
- }
- ret = fmc_send_cmd(fmdev, ASIC_VER_GET, NULL, sizeof(asic_ver),
- &fmdev->maintask_completion, &asic_ver,
- &resp_len);
- if (ret < 0) {
- pr_err("(fmdrv): Failed read FM chip ASIC Version");
+
+ ret = fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL,
+ sizeof(asic_ver), &asic_ver, &resp_len);
+ if (ret < 0)
goto rel;
- }
- pr_info("(fmdrv): ASIC ID: 0x%x , ASIC Version: %d",
- FM_BE16_TO_LE16(asic_id), FM_BE16_TO_LE16(asic_ver));
+ pr_debug("(fmdrv): ASIC ID: 0x%x , ASIC Version: %d\n",
+ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START,
- FM_BE16_TO_LE16(asic_id), FM_BE16_TO_LE16(asic_ver));
+ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
ret = fm_download_firmware(fmdev, fw_name);
if (ret < 0) {
- pr_info("(fmdrv): Failed to download firmware file %s\n",
+ pr_debug("(fmdrv): Failed to download firmware file %s\n",
fw_name);
goto rel;
}
sprintf(fw_name, "%s_%x.%d.bts", (fw_option == FM_MODE_RX) ?
FM_RX_FW_FILE_START : FM_TX_FW_FILE_START,
- FM_BE16_TO_LE16(asic_id), FM_BE16_TO_LE16(asic_ver));
+ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
ret = fm_download_firmware(fmdev, fw_name);
if (ret < 0) {
- pr_info("(fmdrv): Failed to download firmware file %s\n",
+ pr_debug("(fmdrv): Failed to download firmware file %s\n",
fw_name);
goto rel;
} else
- goto exit;
+ return ret;
rel:
fmc_release(fmdev);
-exit:
+
return ret;
}
@@ -1829,21 +1701,20 @@ int fmc_set_mode(struct fmdrv_ops *fmdev, unsigned char fm_mode)
int ret = 0;
if (fm_mode >= FM_MODE_ENTRY_MAX) {
- pr_err("(fmdrv): Invalid FM mode");
- ret = -EINVAL;
- goto exit;
+ pr_err("(fmdrv): Invalid FM mode\n");
+ return -EINVAL;
}
if (fmdev->curr_fmmode == fm_mode) {
- pr_info("(fmdrv): Already fm is in mode(%d)", fm_mode);
- goto exit;
+ pr_debug("(fmdrv): Already fm is in mode(%d)\n", fm_mode);
+ return ret;
}
switch (fm_mode) {
case FM_MODE_OFF: /* OFF Mode */
ret = fm_power_down(fmdev);
if (ret < 0) {
- pr_err("(fmdrv): Failed to set OFF mode");
- goto exit;
+ pr_err("(fmdrv): Failed to set OFF mode\n");
+ return ret;
}
break;
@@ -1853,27 +1724,27 @@ int fmc_set_mode(struct fmdrv_ops *fmdev, unsigned char fm_mode)
if (fmdev->curr_fmmode != FM_MODE_OFF) {
ret = fm_power_down(fmdev);
if (ret < 0) {
- pr_err("(fmdrv): Failed to set OFF mode");
- goto exit;
+ pr_err("(fmdrv): Failed to set OFF mode\n");
+ return ret;
}
msleep(30);
}
ret = fm_power_up(fmdev, fm_mode);
if (ret < 0) {
pr_err("(fmdrv): Failed to load firmware\n");
- goto exit;
+ return ret;
}
}
fmdev->curr_fmmode = fm_mode;
/* Set default configuration */
if (fmdev->curr_fmmode == FM_MODE_RX) {
- pr_info("(fmdrv): Loading default rx configuration..\n");
+ pr_debug("(fmdrv): Loading default rx configuration..\n");
ret = __load_default_rx_configuration(fmdev);
if (ret < 0)
pr_err("(fmdrv): Failed to load default values\n");
}
-exit:
+
return ret;
}
@@ -1881,11 +1752,11 @@ exit:
int fmc_get_mode(struct fmdrv_ops *fmdev, unsigned char *fmmode)
{
if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
- pr_err("(fmdrv): FM core is not ready");
+ pr_err("(fmdrv): FM core is not ready\n");
return -EPERM;
}
if (fmmode == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
@@ -1901,12 +1772,12 @@ static long fm_st_receive(void *arg, struct sk_buff *skb)
fmdev = (struct fmdrv_ops *)arg;
if (skb == NULL) {
- pr_err("(fmdrv): Invalid SKB received from ST");
+ pr_err("(fmdrv): Invalid SKB received from ST\n");
return -EFAULT;
}
if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) {
- pr_err("(fmdrv): Received SKB (%p) is not FM Channel 8 pkt",
+ pr_err("(fmdrv): Received SKB (%p) is not FM Channel 8 pkt\n",
skb);
return -EINVAL;
}
@@ -1918,7 +1789,8 @@ static long fm_st_receive(void *arg, struct sk_buff *skb)
return 0;
}
-/* Called by ST layer to indicate protocol registration completion
+/*
+ * Called by ST layer to indicate protocol registration completion
* status.
*/
static void fm_st_reg_comp_cb(void *arg, char data)
@@ -1930,7 +1802,8 @@ static void fm_st_reg_comp_cb(void *arg, char data)
complete(&wait_for_fmdrv_reg_comp);
}
-/* This function will be called from FM V4L2 open function.
+/*
+ * This function will be called from FM V4L2 open function.
* Register with ST driver and initialize driver data.
*/
int fmc_prepare(struct fmdrv_ops *fmdev)
@@ -1940,8 +1813,8 @@ int fmc_prepare(struct fmdrv_ops *fmdev)
int ret = 0;
if (test_bit(FM_CORE_READY, &fmdev->flag)) {
- pr_info("(fmdrv): FM Core is already up");
- goto exit;
+ pr_debug("(fmdrv): FM Core is already up\n");
+ return ret;
}
memset(&fm_st_proto, 0, sizeof(fm_st_proto));
@@ -1956,43 +1829,38 @@ int fmc_prepare(struct fmdrv_ops *fmdev)
if (ret == -EINPROGRESS) {
init_completion(&wait_for_fmdrv_reg_comp);
fmdev->streg_cbdata = -EINPROGRESS;
- pr_info("(fmdrv): %s waiting for ST reg completion signal",
- __func__);
+ pr_debug("(fmdrv): %s waiting for ST reg completion signal\n",
+ __func__);
timeleft =
wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
FM_ST_REGISTER_TIMEOUT);
if (!timeleft) {
- pr_err("(fmdrv): Timeout(%d sec), didn't get reg"
- "completion signal from ST",
- jiffies_to_msecs(FM_ST_REGISTER_TIMEOUT) /
- 1000);
- ret = -ETIMEDOUT;
- goto exit;
+ pr_err("(fmdrv): Timeout(%d sec), didn't get reg "
+ "completion signal from ST\n",
+ jiffies_to_msecs(FM_ST_REGISTER_TIMEOUT) / 1000);
+ return -ETIMEDOUT;
}
if (fmdev->streg_cbdata != 0) {
- pr_err("(fmdrv): ST reg comp CB called with error"
- "status %d", fmdev->streg_cbdata);
- ret = -EAGAIN;
- goto exit;
+ pr_err("(fmdrv): ST reg comp CB called with error "
+ "status %d\n", fmdev->streg_cbdata);
+ return -EAGAIN;
}
ret = 0;
} else if (ret == -1) {
- pr_err("(fmdrv): st_register failed %d", ret);
- ret = -EAGAIN;
- goto exit;
+ pr_err("(fmdrv): st_register failed %d\n", ret);
+ return -EAGAIN;
}
if (fm_st_proto.write != NULL) {
g_st_write = fm_st_proto.write;
} else {
- pr_err("(fmdrv): Failed to get ST write func pointer");
+ pr_err("(fmdrv): Failed to get ST write func pointer\n");
ret = st_unregister(ST_FM);
if (ret < 0)
- pr_err("(fmdrv): st_unregister failed %d", ret);
- ret = -EAGAIN;
- goto exit;
+ pr_err("(fmdrv): st_unregister failed %d\n", ret);
+ return -EAGAIN;
}
spin_lock_init(&fmdev->rds_buff_lock);
@@ -2034,11 +1902,12 @@ int fmc_prepare(struct fmdrv_ops *fmdev)
fm_rx_reset_curr_station_info(fmdev);
set_bit(FM_CORE_READY, &fmdev->flag);
-exit:
+
return ret;
}
-/* This function will be called from FM V4L2 release function.
+/*
+ * This function will be called from FM V4L2 release function.
* Unregister from ST driver.
*/
int fmc_release(struct fmdrv_ops *fmdev)
@@ -2046,7 +1915,7 @@ int fmc_release(struct fmdrv_ops *fmdev)
int ret;
if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
- pr_info("(fmdrv): FM Core is already down");
+ pr_debug("(fmdrv): FM Core is already down\n");
return 0;
}
/* Sevice pending read */
@@ -2063,15 +1932,16 @@ int fmc_release(struct fmdrv_ops *fmdev)
ret = st_unregister(ST_FM);
if (ret < 0)
- pr_err("(fmdrv): Failed to de-register FM from ST - %d", ret);
+ pr_err("(fmdrv): Failed to de-register FM from ST %d\n", ret);
else
- pr_info("(fmdrv): Successfully unregistered from ST");
+ pr_debug("(fmdrv): Successfully unregistered from ST\n");
clear_bit(FM_CORE_READY, &fmdev->flag);
return ret;
}
-/* Module init function. Ask FM V4L module to register video device.
+/*
+ * Module init function. Ask FM V4L module to register video device.
* Allocate memory for FM driver context and RX RDS buffer.
*/
static int __init fm_drv_init(void)
@@ -2079,17 +1949,17 @@ static int __init fm_drv_init(void)
struct fmdrv_ops *fmdev = NULL;
int ret = -ENOMEM;
- pr_info("(fmdrv): FM driver version %s", FM_DRV_VERSION);
+ pr_debug("(fmdrv): FM driver version %s\n", FM_DRV_VERSION);
fmdev = kzalloc(sizeof(struct fmdrv_ops), GFP_KERNEL);
if (NULL == fmdev) {
- pr_err("(fmdrv): Can't allocate operation structure memory");
- goto exit;
+ pr_err("(fmdrv): Can't allocate operation structure memory\n");
+ return ret;
}
fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLOCK_SIZE;
fmdev->rx.rds.buffer = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL);
if (NULL == fmdev->rx.rds.buffer) {
- pr_err("(fmdrv): Can't allocate rds ring buffer");
+ pr_err("(fmdrv): Can't allocate rds ring buffer\n");
goto rel_dev;
}
@@ -2099,13 +1969,15 @@ static int __init fm_drv_init(void)
fmdev->irq_info.fm_int_handlers = g_IntHandlerTable;
fmdev->curr_fmmode = FM_MODE_OFF;
- goto exit;
+ fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF;
+ fmdev->tx_data.preemph = FM_TX_PREEMPH_50US;
+ return ret;
rel_rdsbuf:
kfree(fmdev->rx.rds.buffer);
rel_dev:
kfree(fmdev);
-exit:
+
return ret;
}
diff --git a/drivers/staging/ti-st/fmdrv_common.h b/drivers/staging/ti-st/fmdrv_common.h
index 689a764a3d1b..065192b77c19 100644
--- a/drivers/staging/ti-st/fmdrv_common.h
+++ b/drivers/staging/ti-st/fmdrv_common.h
@@ -34,148 +34,104 @@ struct fm_reg_table {
char *name;
};
-/* FM register index */
-enum fm_reg_index {
- /* FM RX registers */
- STEREO_GET,
- RSSI_LVL_GET,
- IF_COUNT_GET,
- FLAG_GET,
- RDS_SYNC_GET,
- RDS_DATA_GET,
- FREQ_SET,
- FREQ_GET,
- AF_FREQ_SET,
- AF_FREQ_GET,
- MOST_MODE_SET,
- MOST_MODE_GET,
- MOST_BLEND_SET,
- MOST_BLEND_GET,
- DEMPH_MODE_SET,
- DEMPH_MODE_GET,
- SEARCH_LVL_SET,
- SEARCH_LVL_GET,
- RX_BAND_SET,
- RX_BAND_GET,
- MUTE_STATUS_SET,
- MUTE_STATUS_GET,
- RDS_PAUSE_LVL_SET,
- RDS_PAUSE_LVL_GET,
- RDS_PAUSE_DUR_SET,
- RDS_PAUSE_DUR_GET,
- RDS_MEM_SET,
- RDS_MEM_GET,
- RDS_BLK_B_SET,
- RDS_BLK_B_GET,
- RDS_MSK_B_SET,
- RDS_MSK_B_GET,
- RDS_PI_MASK_SET,
- RDS_PI_MASK_GET,
- RDS_PI_SET,
- RDS_PI_GET,
- RDS_SYSTEM_SET,
- RDS_SYSTEM_GET,
- INT_MASK_SET,
- INT_MASK_GET,
- SEARCH_DIR_SET,
- SEARCH_DIR_GET,
- VOLUME_SET,
- VOLUME_GET,
- AUDIO_ENABLE_SET,
- AUDIO_ENABLE_GET,
- PCM_MODE_SET,
- PCM_MODE_GET,
- I2S_MODE_CONFIG_SET,
- I2S_MODE_CONFIG_GET,
- POWER_SET,
- POWER_GET,
- INTx_CONFIG_SET,
- INTx_CONFIG_GET,
- PULL_EN_SET,
- PULL_EN_GET,
- HILO_SET,
- HILO_GET,
- SWITCH2FREF,
- FREQ_DRIFT_REPORT,
- PCE_GET,
- FIRM_VER_GET,
- ASIC_VER_GET,
- ASIC_ID_GET,
- MAIN_ID_GET,
- TUNER_MODE_SET,
- STOP_SEARCH,
- RDS_CNTRL_SET,
- WRITE_HARDWARE_REG,
- CODE_DOWNLOAD,
- RESET,
- FM_POWER_MODE,
- FM_INTERRUPT,
-
- /* FM TX registers */
- CHANL_SET,
- CHANL_GET,
- CHANL_BW_SET,
- CHANL_BW_GET,
- REF_SET,
- REF_GET,
- POWER_ENB_SET,
- POWER_ATT_SET,
- POWER_ATT_GET,
- POWER_LEL_SET,
- POWER_LEL_GET,
- AUDIO_DEV_SET,
- AUDIO_DEV_GET,
- PILOT_DEV_SET,
- PILOT_DEV_GET,
- RDS_DEV_SET,
- RDS_DEV_GET,
- PUPD_SET,
- AUDIO_IO_SET,
- PREMPH_SET,
- PREMPH_GET,
- TX_BAND_SET,
- TX_BAND_GET,
- MONO_SET,
- MONO_GET,
- MUTE,
- MPX_LMT_ENABLE,
- LOCK_GET,
- REF_ERR_SET,
- PI_SET,
- PI_GET,
- TYPE_SET,
- TYPE_GET,
- PTY_SET,
- PTY_GET,
- AF_SET,
- AF_GET,
- DISPLAY_SIZE_SET,
- DISPLAY_SIZE_GET,
- RDS_MODE_SET,
- RDS_MODE_GET,
- DISPLAY_MODE_SET,
- DISPLAY_MODE_GET,
- LENGHT_SET,
- LENGHT_GET,
- TOGGLE_AB_SET,
- TOGGLE_AB_GET,
- RDS_REP_SET,
- RDS_REP_GET,
- RDS_DATA_SET,
- RDS_DATA_ENB,
- TA_SET,
- TA_GET,
- TP_SET,
- TP_GET,
- DI_SET,
- DI_GET,
- MS_SET,
- MS_GET,
- PS_SCROLL_SPEED_SET,
- PS_SCROLL_SPEED_GET,
-
- FM_REG_MAX_ENTRIES
-};
+#define STEREO_GET 0
+#define RSSI_LVL_GET 1
+#define IF_COUNT_GET 2
+#define FLAG_GET 3
+#define RDS_SYNC_GET 4
+#define RDS_DATA_GET 5
+#define FREQ_SET 10
+#define AF_FREQ_SET 11
+#define MOST_MODE_SET 12
+#define MOST_BLEND_SET 13
+#define DEMPH_MODE_SET 14
+#define SEARCH_LVL_SET 15
+#define BAND_SET 16
+#define MUTE_STATUS_SET 17
+#define RDS_PAUSE_LVL_SET 18
+#define RDS_PAUSE_DUR_SET 19
+#define RDS_MEM_SET 20
+#define RDS_BLK_B_SET 21
+#define RDS_MSK_B_SET 22
+#define RDS_PI_MASK_SET 23
+#define RDS_PI_SET 24
+#define RDS_SYSTEM_SET 25
+#define INT_MASK_SET 26
+#define SEARCH_DIR_SET 27
+#define VOLUME_SET 28
+#define AUDIO_ENABLE_SET 29
+#define PCM_MODE_SET 30
+#define I2S_MODE_CONFIG_SET 31
+#define POWER_SET 32
+#define INTX_CONFIG_SET 33
+#define PULL_EN_SET 34
+#define HILO_SET 35
+#define SWITCH2FREF 36
+#define FREQ_DRIFT_REPORT 37
+
+#define PCE_GET 40
+#define FIRM_VER_GET 41
+#define ASIC_VER_GET 42
+#define ASIC_ID_GET 43
+#define MAN_ID_GET 44
+#define TUNER_MODE_SET 45
+#define STOP_SEARCH 46
+#define RDS_CNTRL_SET 47
+
+#define WRITE_HARDWARE_REG 100
+#define CODE_DOWNLOAD 101
+#define RESET 102
+
+#define FM_POWER_MODE 254
+#define FM_INTERRUPT 255
+
+/* Transmitter API */
+
+#define CHANL_SET 55
+#define CHANL_BW_SET 56
+#define REF_SET 57
+#define POWER_ENB_SET 90
+#define POWER_ATT_SET 58
+#define POWER_LEV_SET 59
+#define AUDIO_DEV_SET 60
+#define PILOT_DEV_SET 61
+#define RDS_DEV_SET 62
+#define TX_BAND_SET 65
+#define PUPD_SET 91
+#define AUDIO_IO_SET 63
+#define PREMPH_SET 64
+#define MONO_SET 66
+#define MUTE 92
+#define MPX_LMT_ENABLE 67
+#define PI_SET 93
+#define ECC_SET 69
+#define PTY 70
+#define AF 71
+#define DISPLAY_MODE 74
+#define RDS_REP_SET 77
+#define RDS_CONFIG_DATA_SET 98
+#define RDS_DATA_SET 99
+#define RDS_DATA_ENB 94
+#define TA_SET 78
+#define TP_SET 79
+#define DI_SET 80
+#define MS_SET 81
+#define PS_SCROLL_SPEED 82
+#define TX_AUDIO_LEVEL_TEST 96
+#define TX_AUDIO_LEVEL_TEST_THRESHOLD 73
+#define TX_AUDIO_INPUT_LEVEL_RANGE_SET 54
+#define RX_ANTENNA_SELECT 87
+#define I2C_DEV_ADDR_SET 86
+#define REF_ERR_CALIB_PARAM_SET 88
+#define REF_ERR_CALIB_PERIODICITY_SET 89
+#define SOC_INT_TRIGGER 52
+#define SOC_AUDIO_PATH_SET 83
+#define SOC_PCMI_OVERRIDE 84
+#define SOC_I2S_OVERRIDE 85
+#define RSSI_BLOCK_SCAN_FREQ_SET 95
+#define RSSI_BLOCK_SCAN_START 97
+#define RSSI_BLOCK_SCAN_DATA_GET 5
+#define READ_FMANT_TUNE_VALUE 104
/* SKB helpers */
struct fm_skb_cb {
@@ -212,42 +168,6 @@ struct fm_event_msg_hdr {
/* TI's magic number in firmware file */
#define FM_FW_FILE_HEADER_MAGIC 0x42535442
-/* Firmware header */
-struct bts_header {
- uint32_t magic;
- uint32_t version;
- uint8_t future[24];
- uint8_t actions[0];
-} __attribute__ ((packed));
-
-/* Firmware action */
-struct bts_action {
- uint16_t type;
- uint16_t size;
- uint8_t data[0];
-} __attribute__ ((packed));
-
-/* Firmware delay */
-struct bts_action_delay {
- uint32_t msec;
-} __attribute__ ((packed));
-
-#define ACTION_SEND_COMMAND 1
-#define ACTION_WAIT_EVENT 2
-#define ACTION_SERIAL 3
-#define ACTION_DELAY 4
-#define ACTION_REMARKS 6
-
-/* Converts little endian to big endian */
-#define FM_STORE_LE16_TO_BE16(data, value) \
- (data = ((value >> 8) | ((value & 0xFF) << 8)))
-#define FM_LE16_TO_BE16(value) (((value >> 8) | ((value & 0xFF) << 8)))
-
-/* Converts big endian to little endian */
-#define FM_STORE_BE16_TO_LE16(data, value) \
- (data = ((value & 0xFF) << 8) | ((value >> 8)))
-#define FM_BE16_TO_LE16(value) (((value & 0xFF) << 8) | ((value >> 8)))
-
#define FM_ENABLE 1
#define FM_DISABLE 0
@@ -265,17 +185,14 @@ struct bts_action_delay {
#define FM_MAL_EVENT (1 << 10)
#define FM_POW_ENB_EVENT (1 << 11)
-/* Firmware files of the FM, ASIC ID and
- * ASIC version will be appened to this later
+/*
+ * Firmware files of FM. ASIC ID and ASIC version will be appened to this,
+ * later.
*/
#define FM_FMC_FW_FILE_START ("fmc_ch8")
#define FM_RX_FW_FILE_START ("fm_rx_ch8")
#define FM_TX_FW_FILE_START ("fm_tx_ch8")
-#define FM_CHECK_SEND_CMD_STATUS(ret) \
- if (ret < 0) {\
- return ret;\
- }
#define FM_UNDEFINED_FREQ 0xFFFFFFFF
/* Band types */
@@ -300,8 +217,8 @@ struct bts_action_delay {
#define FM_RX_VOLUME_GAIN_STEP 0x370
/* Mute modes */
-#define FM_MUTE_ON 0
-#define FM_MUTE_OFF 1
+#define FM_MUTE_ON 0
+#define FM_MUTE_OFF 1
#define FM_MUTE_ATTENUATE 2
#define FM_RX_MUTE_UNMUTE_MODE 0x00
@@ -360,9 +277,9 @@ struct bts_action_delay {
#define FM_RDS_STATUS_ERROR_MASK 0x18
-/* Represents an RDS group type & version.
- * There are 15 groups, each group has 2
- * versions: A and B.
+/*
+ * Represents an RDS group type & version.
+ * There are 15 groups, each group has 2 versions: A and B.
*/
#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0)
#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1)
@@ -426,19 +343,37 @@ struct bts_action_delay {
#define FM_RX_IFFREQ_TO_LO_SIDE 0x1
#define FM_RX_IFFREQ_HILO_AUTOMATIC 0x2
-/* Default RX mode configuration. Chip will be configured
+/*
+ * Default RX mode configuration. Chip will be configured
* with this default values after loading RX firmware.
*/
#define FM_DEFAULT_RX_VOLUME 10
#define FM_DEFAULT_RSSI_THRESHOLD 3
+/* Range for TX power level in units for dB/uV */
+#define FM_PWR_LVL_LOW 91
+#define FM_PWR_LVL_HIGH 122
+
+/* Chip specific default TX power level value */
+#define FM_PWR_LVL_DEF 4
+
+/* FM TX Pre-emphasis filter values */
+#define FM_TX_PREEMPH_OFF 1
+#define FM_TX_PREEMPH_50US 0
+#define FM_TX_PREEMPH_75US 2
+
+/* FM TX antenna impedence values */
+#define FM_TX_ANT_IMP_50 0
+#define FM_TX_ANT_IMP_200 1
+#define FM_TX_ANT_IMP_500 2
+
/* Functions exported by FM common sub-module */
int fmc_prepare(struct fmdrv_ops *);
int fmc_release(struct fmdrv_ops *);
void fmc_update_region_info(struct fmdrv_ops *, unsigned char);
-int fmc_send_cmd(struct fmdrv_ops *, unsigned char, void *, int,
- struct completion *, void *, int *);
+int fmc_send_cmd(struct fmdrv_ops *, unsigned char, unsigned short int,
+ void *, int, void *, int *);
int fmc_is_rds_data_available(struct fmdrv_ops *, struct file *,
struct poll_table_struct *);
int fmc_transfer_rds_from_internal_buff(struct fmdrv_ops *, struct file *,
diff --git a/drivers/staging/ti-st/fmdrv_rx.c b/drivers/staging/ti-st/fmdrv_rx.c
index 5fb182f06a35..536f1c8120c5 100644
--- a/drivers/staging/ti-st/fmdrv_rx.c
+++ b/drivers/staging/ti-st/fmdrv_rx.c
@@ -3,6 +3,7 @@
* This sub-module of FM driver implements FM RX functionality.
*
* Copyright (C) 2010 Texas Instruments
+ * Author: Raja Mani <raja_mani@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,13 +24,6 @@
#include "fmdrv_common.h"
#include "fmdrv_rx.h"
-#ifndef DEBUG
-#ifdef pr_info
-#undef pr_info
-#define pr_info(fmt, arg...)
-#endif
-#endif
-
void fm_rx_reset_rds_cache(struct fmdrv_ops *fmdev)
{
fmdev->rx.rds.flag = FM_RDS_DISABLE;
@@ -39,7 +33,6 @@ void fm_rx_reset_rds_cache(struct fmdrv_ops *fmdev)
if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
fmdev->irq_info.mask |= FM_LEV_EVENT;
-
}
void fm_rx_reset_curr_station_info(struct fmdrv_ops *fmdev)
@@ -56,90 +49,93 @@ int fm_rx_set_frequency(struct fmdrv_ops *fmdev, unsigned int freq_to_set)
unsigned int curr_frq_in_khz;
int ret, resp_len;
- if (fmdev->curr_fmmode != FM_MODE_RX) {
- ret = -EPERM;
- goto exit;
- }
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
if (freq_to_set < fmdev->rx.region.bottom_frequency ||
freq_to_set > fmdev->rx.region.top_frequency) {
- pr_err("(fmdrv): Invalid frequency %d", freq_to_set);
- ret = -EINVAL;
- goto exit;
+ pr_err("(fmdrv): Invalid frequency %d\n", freq_to_set);
+ return -EINVAL;
}
+
/* Set audio enable */
- FM_STORE_LE16_TO_BE16(payload, FM_RX_FM_AUDIO_ENABLE_I2S_AND_ANALOG);
- ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = FM_RX_FM_AUDIO_ENABLE_I2S_AND_ANALOG;
+
+ ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Set hilo to automatic selection */
- FM_STORE_LE16_TO_BE16(payload, FM_RX_IFFREQ_HILO_AUTOMATIC);
- ret = fmc_send_cmd(fmdev, HILO_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = FM_RX_IFFREQ_HILO_AUTOMATIC;
+ ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Calculate frequency index to write */
frq_index = (freq_to_set - fmdev->rx.region.bottom_frequency) /
FM_FREQ_MUL;
/* Set frequency index */
- FM_STORE_LE16_TO_BE16(payload, frq_index);
- ret = fmc_send_cmd(fmdev, FREQ_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = frq_index;
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Read flags - just to clear any pending interrupts if we had */
- ret = fmc_send_cmd(fmdev, FLAG_GET, NULL, 2,
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
+ NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Enable FR, BL interrupts */
fmdev->irq_info.mask |= (FM_FR_EVENT | FM_BL_EVENT);
- FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
- ret = fmc_send_cmd(fmdev, INT_MASK_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Start tune */
- FM_STORE_LE16_TO_BE16(payload, FM_TUNER_PRESET_MODE);
- ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = FM_TUNER_PRESET_MODE;
+ ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Wait for tune ended interrupt */
init_completion(&fmdev->maintask_completion);
timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
FM_DRV_TX_TIMEOUT);
if (!timeleft) {
- pr_err("(fmdrv): Timeout(%d sec),didn't get tune ended int",
+ pr_err("(fmdrv): Timeout(%d sec),didn't get tune ended int\n",
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
- ret = -ETIMEDOUT;
- goto exit;
+ return -ETIMEDOUT;
}
/* Read freq back to confirm */
- ret = fmc_send_cmd(fmdev, FREQ_GET, NULL, 2,
- &fmdev->maintask_completion, &curr_frq, &resp_len);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2,
+ &curr_frq, &resp_len);
+ if (ret < 0)
+ return ret;
- curr_frq = FM_BE16_TO_LE16(curr_frq);
+ curr_frq = be16_to_cpu(curr_frq);
curr_frq_in_khz = (fmdev->rx.region.bottom_frequency
+ ((unsigned int)curr_frq * FM_FREQ_MUL));
/* Re-enable default FM interrupts */
fmdev->irq_info.mask &= ~(FM_FR_EVENT | FM_BL_EVENT);
- FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
- ret = fmc_send_cmd(fmdev, INT_MASK_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
-
- /* Gap BTW two consecutive frequency must be 50KHz, if the requested
- * frequency is odd value then driver will tune to the next higher freq.
- */
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
if (curr_frq_in_khz != freq_to_set) {
- pr_err("(fmdrv): Current chip frequency(%d) is not matching"
- " with requested frequency(%d)", curr_frq_in_khz,
+ pr_info("(fmdrv): Frequency is set to (%d) but"
+ " requested frequency is (%d)\n", curr_frq_in_khz,
freq_to_set);
}
@@ -151,129 +147,175 @@ int fm_rx_set_frequency(struct fmdrv_ops *fmdev, unsigned int freq_to_set)
fm_rx_reset_curr_station_info(fmdev);
/* Do we need to reset anything else? */
-exit:
+
return ret;
}
+/* TODO: Enable this once the kernel moves to 2.6.36 or above*/
+#if 0
+static int fm_rx_set_channel_spacing(struct fmdrv_ops *fmdev,
+ unsigned int spacing)
+{
+ unsigned short payload;
+ int ret;
+
+ if (spacing == 0)
+ spacing = FM_CHANNEL_SPACING_50KHZ;
+ else if (spacing > 0 && spacing <= 50000)
+ spacing = FM_CHANNEL_SPACING_50KHZ;
+ else if (spacing > 50000 && spacing <= 100000)
+ spacing = FM_CHANNEL_SPACING_100KHZ;
+ else
+ spacing = FM_CHANNEL_SPACING_200KHZ;
+
+ /* set channel spacing */
+ payload = spacing;
+ ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.region.channel_spacing = spacing * FM_FREQ_MUL;
+
+ return ret;
+}
+#endif
int fm_rx_seek(struct fmdrv_ops *fmdev, unsigned int seek_upward,
- unsigned int wrap_around)
+ unsigned int wrap_around)
{
int resp_len;
unsigned short curr_frq, next_frq, last_frq;
unsigned short payload, int_reason;
- char offset, spacing;
+ char offset, spacing_index;
unsigned long timeleft;
- int ret, band_lmt_reach = 0;
+ int ret;
- if (fmdev->curr_fmmode != FM_MODE_RX) {
- ret = -EPERM;
- goto exit;
- }
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+ /* TODO: Enable this once the kernel moves to 2.6.36 or above*/
+#if 0
+ /* Set channel spacing */
+ ret = fm_rx_set_channel_spacing(fmdev, spacing);
+ if (ret < 0) {
+ pr_err("(fmdrv): Failed to set channel spacing\n");
+ return ret;
+ }
+#endif
/* Read the current frequency from chip */
- ret = fmc_send_cmd(fmdev, FREQ_GET, NULL, sizeof(curr_frq),
- &fmdev->maintask_completion, &curr_frq, &resp_len);
- FM_CHECK_SEND_CMD_STATUS(ret);
-
- curr_frq = FM_BE16_TO_LE16(curr_frq);
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL,
+ sizeof(curr_frq), &curr_frq, &resp_len);
+ if (ret < 0)
+ return ret;
+ curr_frq = be16_to_cpu(curr_frq);
last_frq = (fmdev->rx.region.top_frequency -
- fmdev->rx.region.bottom_frequency) / FM_FREQ_MUL;
+ fmdev->rx.region.bottom_frequency) / FM_FREQ_MUL;
/* Check the offset in order to be aligned to the channel spacing*/
- spacing = fmdev->rx.region.channel_spacing / FM_FREQ_MUL;
- offset = curr_frq % spacing;
-
- next_frq = seek_upward ? curr_frq + spacing /* Seek Up */ :
- curr_frq - spacing /* Seek Down */ ;
+ spacing_index = fmdev->rx.region.channel_spacing / FM_FREQ_MUL;
+ offset = curr_frq % spacing_index;
- /* Add or subtract offset in order to stay aligned to the channel
- * spacing.
- */
+ next_frq = seek_upward ? curr_frq + spacing_index /* Seek Up */ :
+ curr_frq - spacing_index /* Seek Down */ ;
+ /*
+ * Add or subtract offset in order to stay aligned to the channel
+ * spacing.
+ */
if ((short)next_frq < 0)
next_frq = last_frq - offset;
else if (next_frq > last_frq)
next_frq = 0 + offset;
+again:
/* Set calculated next frequency to perform seek */
- FM_STORE_LE16_TO_BE16(payload, next_frq);
- ret = fmc_send_cmd(fmdev, FREQ_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = next_frq;
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Set search direction (0:Seek Down, 1:Seek Up) */
- FM_STORE_LE16_TO_BE16(payload, (seek_upward ? FM_SEARCH_DIRECTION_UP :
- FM_SEARCH_DIRECTION_DOWN));
- ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = (seek_upward ? FM_SEARCH_DIRECTION_UP :
+ FM_SEARCH_DIRECTION_DOWN);
+ ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Read flags - just to clear any pending interrupts if we had */
- ret = fmc_send_cmd(fmdev, FLAG_GET, NULL, 2,
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
+ NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Enable FR, BL interrupts */
fmdev->irq_info.mask |= (FM_FR_EVENT | FM_BL_EVENT);
- FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
- ret = fmc_send_cmd(fmdev, INT_MASK_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Start seek */
- FM_STORE_LE16_TO_BE16(payload, FM_TUNER_AUTONOMOUS_SEARCH_MODE);
- ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE;
+ ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Wait for tune ended/band limit reached interrupt */
init_completion(&fmdev->maintask_completion);
timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
FM_DRV_RX_SEEK_TIMEOUT);
if (!timeleft) {
- pr_err("(fmdrv): Timeout(%d sec),didn't get tune ended int",
+ pr_err("(fmdrv): Timeout(%d sec),didn't get tune ended int\n",
jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
- ret = -ETIMEDOUT;
- goto exit;
+ return -ETIMEDOUT;
}
- int_reason = fmdev->irq_info.flag & 0x3;
- if (fmdev->irq_info.flag & FM_BL_EVENT)
- band_lmt_reach = 1;
+ int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
/* Re-enable default FM interrupts */
fmdev->irq_info.mask &= ~(FM_FR_EVENT | FM_BL_EVENT);
- FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
- ret = fmc_send_cmd(fmdev, INT_MASK_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
-
- if (band_lmt_reach == 1)
- fmdev->rx.curr_freq = seek_upward ?
- fmdev->rx.region.top_frequency :
- fmdev->rx.region.bottom_frequency;
- else {
- /* Read freq to know where operation tune operation stopped */
- ret = fmc_send_cmd(fmdev, FREQ_GET, NULL, 2,
- &fmdev->maintask_completion, &curr_frq, &resp_len);
- FM_CHECK_SEND_CMD_STATUS(ret);
-
- curr_frq = FM_BE16_TO_LE16(curr_frq);
- fmdev->rx.curr_freq = (fmdev->rx.region.bottom_frequency +
- ((unsigned int)curr_frq * FM_FREQ_MUL));
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ if (int_reason & FM_BL_EVENT) {
+ if (wrap_around == 0) {
+ fmdev->rx.curr_freq = seek_upward ?
+ fmdev->rx.region.top_frequency :
+ fmdev->rx.region.bottom_frequency;
+ } else {
+ fmdev->rx.curr_freq = seek_upward ?
+ fmdev->rx.region.bottom_frequency :
+ fmdev->rx.region.top_frequency;
+ /* Calculate frequency index to write */
+ next_frq = (fmdev->rx.curr_freq -
+ fmdev->rx.region.bottom_frequency) /
+ FM_FREQ_MUL;
+ goto again;
+ }
+ } else {
+ /* Read freq to know where operation tune operation stopped */
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2,
+ &curr_frq, &resp_len);
+ if (ret < 0)
+ return ret;
+
+ curr_frq = be16_to_cpu(curr_frq);
+ fmdev->rx.curr_freq = (fmdev->rx.region.bottom_frequency +
+ ((unsigned int)curr_frq * FM_FREQ_MUL));
}
/* Reset RDS cache and current station pointers */
fm_rx_reset_rds_cache(fmdev);
fm_rx_reset_curr_station_info(fmdev);
- /* Return error if band limit is reached */
- if (int_reason & FM_BL_EVENT) {
- pr_info("(fmdrv): band limit reached\n");
- ret = -EAGAIN;
- }
-exit:
return ret;
}
@@ -285,17 +327,18 @@ int fm_rx_set_volume(struct fmdrv_ops *fmdev, unsigned short vol_to_set)
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
- if (vol_to_set > FM_RX_VOLUME_MAX) {
- pr_err("(fmdrv): Volume is not within(%d-%d) range",
+ if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) {
+ pr_err("(fmdrv): Volume is not within(%d-%d) range\n",
FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
return -EINVAL;
}
vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
- FM_STORE_LE16_TO_BE16(payload, vol_to_set);
- ret = fmc_send_cmd(fmdev, VOLUME_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = vol_to_set;
+ ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
fmdev->rx.curr_volume = vol_to_set;
return ret;
@@ -308,15 +351,17 @@ int fm_rx_get_volume(struct fmdrv_ops *fmdev, unsigned short *curr_vol)
return -EPERM;
if (curr_vol == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
+
*curr_vol = fmdev->rx.curr_volume / FM_RX_VOLUME_GAIN_STEP;
+
return 0;
}
/* To get current band's bottom and top frequency */
-int fm_rx_get_currband_lowhigh_freq(struct fmdrv_ops *fmdev,
+int fm_rx_get_currband_freq_range(struct fmdrv_ops *fmdev,
unsigned int *bottom_frequency,
unsigned int *top_frequency)
{
@@ -329,54 +374,60 @@ int fm_rx_get_currband_lowhigh_freq(struct fmdrv_ops *fmdev,
return 0;
}
+/* Returns current band index (0-Europe/US; 1-Japan) */
+void fm_rx_get_region(struct fmdrv_ops *fmdev, unsigned char *region)
+{
+ *region = fmdev->rx.region.region_index;
+}
+
/* Sets band (0-Europe/US; 1-Japan) */
int fm_rx_set_region(struct fmdrv_ops *fmdev,
unsigned char region_to_set)
{
unsigned short payload;
- unsigned int new_frq;
+ unsigned int new_frq = 0;
int ret = -EPERM;
if (fmdev->curr_fmmode != FM_MODE_RX)
- goto exit;
+ return ret;
if (region_to_set != FM_BAND_EUROPE_US &&
region_to_set != FM_BAND_JAPAN) {
pr_err("(fmdrv): Invalid band\n");
- ret = -EINVAL;
- goto exit;
+ return -EINVAL;
}
+
if (fmdev->rx.region.region_index == region_to_set) {
pr_err("(fmdrv): Requested band is already configured\n");
- goto exit;
+ return ret;
}
+
/* Send cmd to set the band */
- FM_STORE_LE16_TO_BE16(payload, (unsigned short)region_to_set);
- ret = fmc_send_cmd(fmdev, RX_BAND_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = (unsigned short)region_to_set;
+ ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
fmc_update_region_info(fmdev, region_to_set);
/* Check whether current RX frequency is within band boundary */
- if (fmdev->curr_fmmode == FM_MODE_RX) {
- new_frq = 0;
- if (fmdev->rx.curr_freq < fmdev->rx.region.bottom_frequency)
- new_frq = fmdev->rx.region.bottom_frequency;
- else if (fmdev->rx.curr_freq > fmdev->rx.region.top_frequency)
- new_frq = fmdev->rx.region.top_frequency;
-
- if (new_frq) {
- pr_info("(fmdrv): "
- "Current freq is not within band limit boundary,"
- "switching to %d KHz", new_frq);
- /* Current RX frequency is not
- * within boundary. So, update it
- */
- ret = fm_rx_set_frequency(fmdev, new_frq);
- }
+ if (fmdev->rx.curr_freq < fmdev->rx.region.bottom_frequency)
+ new_frq = fmdev->rx.region.bottom_frequency;
+ else if (fmdev->rx.curr_freq > fmdev->rx.region.top_frequency)
+ new_frq = fmdev->rx.region.top_frequency;
+
+ if (new_frq) {
+ pr_debug("(fmdrv): "
+ "Current freq is not within band limit boundary,"
+ "switching to %d KHz\n", new_frq);
+ /*
+ * Current RX frequency is not within boundary. So,
+ * update it.
+ */
+ ret = fm_rx_set_frequency(fmdev, new_frq);
}
-exit:
+
return ret;
}
@@ -388,10 +439,12 @@ int fm_rx_get_mute_mode(struct fmdrv_ops *fmdev,
return -EPERM;
if (curr_mute_mode == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
+
*curr_mute_mode = fmdev->rx.curr_mute_mode;
+
return 0;
}
@@ -405,9 +458,11 @@ static int __fm_config_rx_mute_reg(struct fmdrv_ops *fmdev)
case FM_MUTE_ON:
muteval = FM_RX_MUTE_AC_MUTE_MODE;
break;
+
case FM_MUTE_OFF:
muteval = FM_RX_MUTE_UNMUTE_MODE;
break;
+
case FM_MUTE_ATTENUATE:
muteval = FM_RX_MUTE_SOFT_MUTE_FORCE_MODE;
break;
@@ -417,10 +472,12 @@ static int __fm_config_rx_mute_reg(struct fmdrv_ops *fmdev)
else
muteval &= ~FM_RX_MUTE_RF_DEP_MODE;
- FM_STORE_LE16_TO_BE16(payload, muteval);
- ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = muteval;
+ ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
return 0;
}
@@ -445,6 +502,7 @@ int fm_rx_set_mute_mode(struct fmdrv_ops *fmdev,
fmdev->rx.curr_mute_mode = org_state;
return ret;
}
+
return 0;
}
@@ -455,12 +513,13 @@ int fm_rx_get_rfdepend_softmute(struct fmdrv_ops *fmdev,
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
-
if (curr_mute_mode == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
+
*curr_mute_mode = fmdev->rx.curr_rf_depend_mute;
+
return 0;
}
@@ -474,10 +533,9 @@ int fm_rx_set_rfdepend_softmute(struct fmdrv_ops *fmdev,
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
-
if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
- pr_err("(fmdrv): Invalid RF dependent soft mute");
+ pr_err("(fmdrv): Invalid RF dependent soft mute\n");
return -EINVAL;
}
if (fmdev->rx.curr_rf_depend_mute == rfdepend_mute)
@@ -491,6 +549,7 @@ int fm_rx_set_rfdepend_softmute(struct fmdrv_ops *fmdev,
fmdev->rx.curr_rf_depend_mute = org_state;
return ret;
}
+
return 0;
}
@@ -506,20 +565,22 @@ int fm_rx_get_rssi_level(struct fmdrv_ops *fmdev,
return -EPERM;
if (rssilvl == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
/* Read current RSSI level */
- ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, NULL, 2,
- &fmdev->maintask_completion, &curr_rssi_lel, &resp_len);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2,
+ &curr_rssi_lel, &resp_len);
+ if (ret < 0)
+ return ret;
- *rssilvl = FM_BE16_TO_LE16(curr_rssi_lel);
+ *rssilvl = be16_to_cpu(curr_rssi_lel);
return 0;
}
-/* Sets the signal strength level that once reached
+/*
+ * Sets the signal strength level that once reached
* will stop the auto search process
*/
int fm_rx_set_rssi_threshold(struct fmdrv_ops *fmdev,
@@ -533,13 +594,14 @@ int fm_rx_set_rssi_threshold(struct fmdrv_ops *fmdev,
if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
- pr_err("(fmdrv): Invalid RSSI threshold level");
+ pr_err("(fmdrv): Invalid RSSI threshold level\n");
return -EINVAL;
}
- FM_STORE_LE16_TO_BE16(payload, (unsigned short)rssi_lvl_toset);
- ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = (unsigned short)rssi_lvl_toset;
+ ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
fmdev->rx.curr_rssi_threshold = rssi_lvl_toset;
return 0;
@@ -552,10 +614,12 @@ int fm_rx_get_rssi_threshold(struct fmdrv_ops *fmdev, short *curr_rssi_lvl)
return -EPERM;
if (curr_rssi_lvl == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
+
*curr_rssi_lvl = fmdev->rx.curr_rssi_threshold;
+
return 0;
}
@@ -569,20 +633,23 @@ int fm_rx_set_stereo_mono(struct fmdrv_ops *fmdev, unsigned short mode)
return -EPERM;
if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
- pr_err("(fmdrv): Invalid mode");
+ pr_err("(fmdrv): Invalid mode\n");
return -EINVAL;
}
+
/* Set stereo/mono mode */
- FM_STORE_LE16_TO_BE16(payload, (unsigned short)mode);
- ret = fmc_send_cmd(fmdev, MOST_MODE_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = (unsigned short)mode;
+ ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Set stereo blending mode */
- FM_STORE_LE16_TO_BE16(payload, FM_STEREO_SOFT_BLEND);
- ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = FM_STEREO_SOFT_BLEND;
+ ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
return 0;
}
@@ -597,14 +664,17 @@ int fm_rx_get_stereo_mono(struct fmdrv_ops *fmdev, unsigned short *mode)
return -EPERM;
if (mode == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
- ret = fmc_send_cmd(fmdev, MOST_MODE_GET, NULL, 2,
- &fmdev->maintask_completion, &curr_mode, &resp_len);
- FM_CHECK_SEND_CMD_STATUS(ret);
- *mode = FM_BE16_TO_LE16(curr_mode);
+ ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2,
+ &curr_mode, &resp_len);
+ if (ret < 0)
+ return ret;
+
+ *mode = be16_to_cpu(curr_mode);
+
return 0;
}
@@ -619,14 +689,17 @@ int fm_rx_set_deemphasis_mode(struct fmdrv_ops *fmdev, unsigned short mode)
if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
- pr_err("(fmdrv): Invalid rx de-emphasis mode");
+ pr_err("(fmdrv): Invalid rx de-emphasis mode (%d)\n", mode);
return -EINVAL;
}
- FM_STORE_LE16_TO_BE16(payload, mode);
- ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = mode;
+ ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.curr_deemphasis_mode = mode;
return 0;
}
@@ -634,21 +707,16 @@ int fm_rx_set_deemphasis_mode(struct fmdrv_ops *fmdev, unsigned short mode)
int fm_rx_get_deemphasis_mode(struct fmdrv_ops *fmdev,
unsigned short *curr_deemphasis_mode)
{
- unsigned short curr_mode;
- int ret, resp_len;
-
if (fmdev->curr_fmmode != FM_MODE_RX)
return -EPERM;
if (curr_deemphasis_mode == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
- ret = fmc_send_cmd(fmdev, DEMPH_MODE_GET, NULL, 2,
- &fmdev->maintask_completion, &curr_mode, &resp_len);
- FM_CHECK_SEND_CMD_STATUS(ret);
- *curr_deemphasis_mode = FM_BE16_TO_LE16(curr_mode);
+ *curr_deemphasis_mode = fmdev->rx.curr_deemphasis_mode;
+
return 0;
}
@@ -662,44 +730,48 @@ int fm_rx_set_rds_mode(struct fmdrv_ops *fmdev, unsigned char rds_en_dis)
return -EPERM;
if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
- pr_err("(fmdrv): Invalid rds option");
+ pr_err("(fmdrv): Invalid rds option\n");
return -EINVAL;
}
+
if (rds_en_dis == FM_RDS_ENABLE
&& fmdev->rx.rds.flag == FM_RDS_DISABLE) {
- /* Turn on RX RDS */
- /* Turn on RDS circuit */
- FM_STORE_LE16_TO_BE16(payload,
- FM_RX_POWET_SET_FM_AND_RDS_BLK_ON);
- ret = fmc_send_cmd(fmdev, POWER_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
-
- /* Clear and rest RDS FIFO */
- FM_STORE_LE16_TO_BE16(payload, FM_RX_RDS_FLUSH_FIFO);
- ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, &payload,
- sizeof(payload), &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
-
- /* Read flags - just to clear any
- * pending interrupts if we had
- */
- ret = fmc_send_cmd(fmdev, FLAG_GET, NULL, 2,
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ /* Turn on RX RDS and RDS circuit */
+ payload = FM_RX_POWET_SET_FM_AND_RDS_BLK_ON;
+ ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Clear and reset RDS FIFO */
+ payload = FM_RX_RDS_FLUSH_FIFO;
+ ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Read flags - just to clear any pending interrupts. */
+ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
+ NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Set RDS FIFO threshold value */
- FM_STORE_LE16_TO_BE16(payload, FM_RX_RDS_FIFO_THRESHOLD);
- ret = fmc_send_cmd(fmdev, RDS_MEM_SET, &payload,
- sizeof(payload), &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = FM_RX_RDS_FIFO_THRESHOLD;
+ ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Enable RDS interrupt */
fmdev->irq_info.mask |= FM_RDS_EVENT;
- FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
- ret = fmc_send_cmd(fmdev, INT_MASK_SET, &payload,
- sizeof(payload), &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0) {
+ fmdev->irq_info.mask &= ~FM_RDS_EVENT;
+ return ret;
+ }
/* Update our local flag */
fmdev->rx.rds.flag = FM_RDS_ENABLE;
@@ -707,10 +779,11 @@ int fm_rx_set_rds_mode(struct fmdrv_ops *fmdev, unsigned char rds_en_dis)
&& fmdev->rx.rds.flag == FM_RDS_ENABLE) {
/* Turn off RX RDS */
/* Turn off RDS circuit */
- FM_STORE_LE16_TO_BE16(payload, FM_RX_POWER_SET_FM_ON_RDS_OFF);
- ret = fmc_send_cmd(fmdev, POWER_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = FM_RX_POWER_SET_FM_ON_RDS_OFF;
+ ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
/* Reset RDS pointers */
fmdev->rx.rds.last_block_index = 0;
@@ -722,6 +795,7 @@ int fm_rx_set_rds_mode(struct fmdrv_ops *fmdev, unsigned char rds_en_dis)
fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
fmdev->rx.rds.flag = FM_RDS_DISABLE;
}
+
return 0;
}
@@ -733,10 +807,12 @@ int fm_rx_get_rds_mode(struct fmdrv_ops *fmdev,
return -EPERM;
if (curr_rds_en_dis == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
+
*curr_rds_en_dis = fmdev->rx.rds.flag;
+
return 0;
}
@@ -750,16 +826,18 @@ int fm_rx_set_rds_system(struct fmdrv_ops *fmdev, unsigned char rds_mode)
return -EPERM;
if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
- pr_err("(fmdrv): Invalid rds mode");
+ pr_err("(fmdrv): Invalid rds mode\n");
return -EINVAL;
}
/* Set RDS operation mode */
- FM_STORE_LE16_TO_BE16(payload, (unsigned short)rds_mode);
- ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = (unsigned short)rds_mode;
+ ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
fmdev->rx.rds_mode = rds_mode;
+
return 0;
}
@@ -771,10 +849,12 @@ int fm_rx_get_rds_system(struct fmdrv_ops *fmdev,
return -EPERM;
if (rds_mode == NULL) {
- pr_err("(fmdrv): Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
+
*rds_mode = fmdev->rx.rds_mode;
+
return 0;
}
@@ -789,7 +869,7 @@ int fm_rx_set_af_switch(struct fmdrv_ops *fmdev, unsigned char af_mode)
if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
- pr_err("(fmdrv): Invalid af mode");
+ pr_err("(fmdrv): Invalid af mode\n");
return -EINVAL;
}
/* Enable/disable low RSSI interrupt based on af_mode */
@@ -798,12 +878,14 @@ int fm_rx_set_af_switch(struct fmdrv_ops *fmdev, unsigned char af_mode)
else
fmdev->irq_info.mask &= ~FM_LEV_EVENT;
- FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
- ret = fmc_send_cmd(fmdev, INT_MASK_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- FM_CHECK_SEND_CMD_STATUS(ret);
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
fmdev->rx.af_mode = af_mode;
+
return 0;
}
@@ -814,51 +896,11 @@ int fm_rx_get_af_switch(struct fmdrv_ops *fmdev, unsigned char *af_mode)
return -EPERM;
if (af_mode == NULL) {
- pr_err("(fmdrv): Invalid memory");
- return -ENOMEM;
- }
- *af_mode = fmdev->rx.af_mode;
- return 0;
-}
-
-/* Set desired channel spacing */
-int fm_rx_set_chanl_spacing(struct fmdrv_ops *fmdev, unsigned char spacing)
-{
- unsigned short payload;
- int ret;
-
- if (spacing != FM_CHANNEL_SPACING_50KHZ &&
- spacing != FM_CHANNEL_SPACING_100KHZ &&
- spacing != FM_CHANNEL_SPACING_200KHZ) {
- pr_err("Invalid channel spacing");
- return -EINVAL;
- }
-
- /* set channel spacing */
- FM_STORE_LE16_TO_BE16(payload, spacing);
-
- ret = fmc_send_cmd(fmdev, CHANL_BW_SET, &payload, sizeof(payload),
- &fmdev->maintask_completion, NULL, NULL);
- if (ret < 0)
- return ret;
-
- fmdev->rx.region.channel_spacing = spacing * FM_FREQ_MUL;
-
- return 0;
-}
-
-/* Get channel spacing */
-int fm_rx_get_chanl_spacing(struct fmdrv_ops *fmdev, unsigned char *spacing)
-{
- if (fmdev->curr_fmmode != FM_MODE_RX)
- return -EPERM;
-
- if (spacing == NULL) {
- pr_err("Invalid memory");
+ pr_err("(fmdrv): Invalid memory\n");
return -ENOMEM;
}
- *spacing = fmdev->rx.region.channel_spacing / FM_FREQ_MUL;
+ *af_mode = fmdev->rx.af_mode;
return 0;
}
diff --git a/drivers/staging/ti-st/fmdrv_rx.h b/drivers/staging/ti-st/fmdrv_rx.h
index a861a7f1e2c4..3b473724836e 100644
--- a/drivers/staging/ti-st/fmdrv_rx.h
+++ b/drivers/staging/ti-st/fmdrv_rx.h
@@ -22,14 +22,14 @@
#ifndef _FMDRV_RX_H
#define _FMDRV_RX_H
-int fm_rx_set_frequency(struct fmdrv_ops*, unsigned int);
-int fm_rx_set_mute_mode(struct fmdrv_ops*, unsigned char);
-int fm_rx_set_stereo_mono(struct fmdrv_ops*, unsigned short);
-int fm_rx_set_rds_mode(struct fmdrv_ops*, unsigned char);
+int fm_rx_set_frequency(struct fmdrv_ops *, unsigned int);
+int fm_rx_set_mute_mode(struct fmdrv_ops *, unsigned char);
+int fm_rx_set_stereo_mono(struct fmdrv_ops *, unsigned short);
+int fm_rx_set_rds_mode(struct fmdrv_ops *, unsigned char);
int fm_rx_set_rds_system(struct fmdrv_ops *, unsigned char);
-int fm_rx_set_volume(struct fmdrv_ops*, unsigned short);
-int fm_rx_set_rssi_threshold(struct fmdrv_ops*, short);
-int fm_rx_set_region(struct fmdrv_ops*, unsigned char);
+int fm_rx_set_volume(struct fmdrv_ops *, unsigned short);
+int fm_rx_set_rssi_threshold(struct fmdrv_ops *, short);
+int fm_rx_set_region(struct fmdrv_ops *, unsigned char);
int fm_rx_set_rfdepend_softmute(struct fmdrv_ops *, unsigned char);
int fm_rx_set_deemphasis_mode(struct fmdrv_ops *, unsigned short);
int fm_rx_set_af_switch(struct fmdrv_ops *, unsigned char);
@@ -37,22 +37,23 @@ int fm_rx_set_af_switch(struct fmdrv_ops *, unsigned char);
void fm_rx_reset_rds_cache(struct fmdrv_ops *);
void fm_rx_reset_curr_station_info(struct fmdrv_ops *);
-int fm_rx_seek(struct fmdrv_ops*, unsigned int, unsigned int);
+int fm_rx_seek(struct fmdrv_ops *, unsigned int, unsigned int);
-int fm_rx_get_rds_mode(struct fmdrv_ops*, unsigned char*);
-int fm_rx_get_rds_system(struct fmdrv_ops *, unsigned char*);
-int fm_rx_get_mute_mode(struct fmdrv_ops*, unsigned char*);
-int fm_rx_get_volume(struct fmdrv_ops*, unsigned short*);
-int fm_rx_get_currband_lowhigh_freq(struct fmdrv_ops*,
- unsigned int*, unsigned int*);
-int fm_rx_get_stereo_mono(struct fmdrv_ops *, unsigned short*);
-int fm_rx_get_rssi_level(struct fmdrv_ops *, unsigned short*);
-int fm_rx_get_rssi_threshold(struct fmdrv_ops *, short*);
-int fm_rx_get_rfdepend_softmute(struct fmdrv_ops *, unsigned char*);
-int fm_rx_get_deemphasis_mode(struct fmdrv_ops *, unsigned short*);
+int fm_rx_get_rds_mode(struct fmdrv_ops *, unsigned char *);
+int fm_rx_get_rds_system(struct fmdrv_ops *, unsigned char *);
+int fm_rx_get_mute_mode(struct fmdrv_ops *, unsigned char *);
+int fm_rx_get_volume(struct fmdrv_ops *, unsigned short *);
+int fm_rx_get_currband_freq_range(struct fmdrv_ops *,
+ unsigned int *, unsigned int *);
+int fm_rx_get_stereo_mono(struct fmdrv_ops *, unsigned short *);
+int fm_rx_get_rssi_level(struct fmdrv_ops *, unsigned short *);
+int fm_rx_get_rssi_threshold(struct fmdrv_ops *, short *);
+int fm_rx_get_rfdepend_softmute(struct fmdrv_ops *, unsigned char *);
+int fm_rx_get_deemphasis_mode(struct fmdrv_ops *, unsigned short *);
int fm_rx_get_af_switch(struct fmdrv_ops *, unsigned char *);
+void fm_rx_get_region(struct fmdrv_ops *, unsigned char *);
-int fm_rx_set_chanl_spacing(struct fmdrv_ops*, unsigned char);
-int fm_rx_get_chanl_spacing(struct fmdrv_ops*, unsigned char*);
+int fm_rx_set_chanl_spacing(struct fmdrv_ops *, unsigned char);
+int fm_rx_get_chanl_spacing(struct fmdrv_ops *, unsigned char *);
#endif
diff --git a/drivers/staging/ti-st/fmdrv_tx.c b/drivers/staging/ti-st/fmdrv_tx.c
new file mode 100644
index 000000000000..c9e738e26f83
--- /dev/null
+++ b/drivers/staging/ti-st/fmdrv_tx.c
@@ -0,0 +1,420 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * This sub-module of FM driver implements FM TX functionality.
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include "fmdrv.h"
+#include "fmdrv_common.h"
+#include "fmdrv_tx.h"
+
+int fm_tx_set_stereo_mono(struct fmdrv_ops *fmdev, unsigned short mode)
+{
+ unsigned short payload;
+ int ret = 0;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ if (fmdev->tx_data.aud_mode == mode)
+ return ret;
+
+ pr_debug("stereo mode: %d\n", mode);
+
+ /* Set Stereo/Mono mode */
+ payload = (1 - mode);
+ ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->tx_data.aud_mode = mode;
+
+ return ret;
+}
+
+static int __set_rds_text(struct fmdrv_ops *fmdev, unsigned char *rds_text)
+{
+ unsigned short payload;
+ int ret;
+
+ ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text,
+ strlen(rds_text), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Scroll mode */
+ payload = (unsigned short)0x1;
+ ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int __set_rds_data_mode(struct fmdrv_ops *fmdev, unsigned char mode)
+{
+ unsigned short payload;
+ int ret;
+
+ /* Setting unique PI TODO: how unique? */
+ payload = (unsigned short)0xcafe;
+ ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set decoder id */
+ payload = (unsigned short)0xa;
+ ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: RDS_MODE_GET? */
+ return 0;
+}
+
+static int __set_rds_len(struct fmdrv_ops *fmdev, unsigned char type,
+ unsigned short len)
+{
+ unsigned short payload;
+ int ret;
+
+ len |= type << 8;
+ payload = len;
+ ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: LENGTH_GET? */
+ return 0;
+}
+
+int fm_tx_set_rds_mode(struct fmdrv_ops *fmdev, unsigned char rds_en_dis)
+{
+ unsigned short payload;
+ int ret;
+ unsigned char rds_text[] = "Zoom2\n";
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ pr_debug("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis,
+ FM_RDS_ENABLE, FM_RDS_DISABLE);
+
+ if (rds_en_dis == FM_RDS_ENABLE) {
+ /* Set RDS length */
+ __set_rds_len(fmdev, 0, strlen(rds_text));
+
+ /* Set RDS text */
+ __set_rds_text(fmdev, rds_text);
+
+ /* Set RDS mode */
+ __set_rds_data_mode(fmdev, 0x0);
+ }
+
+ /* Send command to enable RDS */
+ if (rds_en_dis == FM_RDS_ENABLE)
+ payload = 0x01;
+ else
+ payload = 0x00;
+
+ ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ if (rds_en_dis == FM_RDS_ENABLE) {
+ /* Set RDS length */
+ __set_rds_len(fmdev, 0, strlen(rds_text));
+
+ /* Set RDS text */
+ __set_rds_text(fmdev, rds_text);
+ }
+ fmdev->tx_data.rds.flag = rds_en_dis;
+
+ return 0;
+}
+
+int fm_tx_set_radio_text(struct fmdrv_ops *fmdev,
+ unsigned char *rds_text,
+ unsigned char rds_type)
+{
+ unsigned short payload;
+ int ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ fm_tx_set_rds_mode(fmdev, 0);
+
+ /* Set RDS length */
+ __set_rds_len(fmdev, rds_type, strlen(rds_text));
+
+ /* Set RDS text */
+ __set_rds_text(fmdev, rds_text);
+
+ /* Set RDS mode */
+ __set_rds_data_mode(fmdev, 0x0);
+
+ payload = 1;
+ ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int fm_tx_set_af(struct fmdrv_ops *fmdev, unsigned int af)
+{
+ unsigned short payload;
+ int ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+ pr_debug("AF: %d\n", af);
+
+ af = (af - 87500) / 100;
+ payload = (unsigned short)af;
+ ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int fm_tx_set_region(struct fmdrv_ops *fmdev,
+ unsigned char region_to_set)
+{
+ unsigned short payload;
+ int ret;
+
+ if (region_to_set != FM_BAND_EUROPE_US &&
+ region_to_set != FM_BAND_JAPAN) {
+ pr_err("Invalid band\n");
+ return -EINVAL;
+ }
+
+ /* Send command to set the band */
+ payload = (unsigned short)region_to_set;
+ ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int fm_tx_set_mute_mode(struct fmdrv_ops *fmdev,
+ unsigned char mute_mode_toset)
+{
+ unsigned short payload;
+ int ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+ pr_debug("tx: mute mode %d\n", mute_mode_toset);
+
+ payload = mute_mode_toset;
+ ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Set TX Audio I/O */
+static int __set_audio_io(struct fmdrv_ops *fmdev)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned short payload;
+ int ret;
+
+ /* Set Audio I/O Enable */
+ payload = tx->audio_io;
+ ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: is audio set? */
+ return 0;
+}
+
+/* Start TX Transmission */
+static int __enable_xmit(struct fmdrv_ops *fmdev, unsigned char new_xmit_state)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned short payload;
+ unsigned long timeleft;
+ int ret;
+
+ /* Enable POWER_ENB interrupts */
+ payload = FM_POW_ENB_EVENT;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set Power Enable */
+ payload = new_xmit_state;
+ ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Wait for Power Enabled */
+ init_completion(&fmdev->maintask_completion);
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
+ FM_DRV_TX_TIMEOUT);
+ if (!timeleft) {
+ pr_err("Timeout(%d sec),didn't get tune ended interrupt\n",
+ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+ return -ETIMEDOUT;
+ }
+
+ set_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+ tx->xmit_state = new_xmit_state;
+
+ return 0;
+}
+
+/* Set TX power level */
+int fm_tx_set_pwr_lvl(struct fmdrv_ops *fmdev, unsigned char new_pwr_lvl)
+{
+ unsigned short payload;
+ struct fmtx_data *tx = &fmdev->tx_data;
+ int ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+ pr_debug("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl);
+
+ /* If the core isn't ready update global variable */
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ tx->pwr_lvl = new_pwr_lvl;
+ return 0;
+ }
+
+ /* Set power level */
+ payload = new_pwr_lvl;
+ ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: is the power level set? */
+ tx->pwr_lvl = new_pwr_lvl;
+
+ return 0;
+}
+
+/*
+ * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us)
+ * Convert V4L2 specified filter values to chip specific filter values.
+ */
+int fm_tx_set_preemph_filter(struct fmdrv_ops *fmdev, unsigned int filter)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned short payload;
+ int ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ payload = filter;
+ ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ tx->preemph = filter;
+
+ return ret;
+}
+
+/* Sets FM TX antenna impedance value */
+int fm_tx_set_ant_imp(struct fmdrv_ops *fmdev, unsigned char imp)
+{
+ unsigned short payload;
+ int ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ payload = imp;
+ ret = fmc_send_cmd(fmdev, RX_ANTENNA_SELECT, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+/* Set TX Frequency */
+int fm_tx_set_frequency(struct fmdrv_ops *fmdev, unsigned int freq_to_set)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned short payload, chanl_index;
+ int ret;
+
+ if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
+ __enable_xmit(fmdev, 0);
+ clear_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+ }
+
+ /* Enable FR, BL interrupts */
+ payload = (FM_FR_EVENT | FM_BL_EVENT);
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ tx->tx_frq = (unsigned long)freq_to_set;
+ pr_debug("tx: freq_to_set %ld\n", (long int)tx->tx_frq);
+
+ chanl_index = freq_to_set / 10;
+
+ /* Set current tuner channel */
+ payload = chanl_index;
+ ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl);
+ fm_tx_set_preemph_filter(fmdev, tx->preemph);
+
+ tx->audio_io = 0x01; /* I2S */
+ __set_audio_io(fmdev);
+
+ __enable_xmit(fmdev, 0x01); /* Enable transmission */
+
+ tx->aud_mode = FM_STEREO_MODE;
+ tx->rds.flag = FM_RDS_DISABLE;
+
+ return 0;
+}
+
diff --git a/drivers/staging/ti-st/fmdrv_tx.h b/drivers/staging/ti-st/fmdrv_tx.h
new file mode 100644
index 000000000000..dc98ed133034
--- /dev/null
+++ b/drivers/staging/ti-st/fmdrv_tx.h
@@ -0,0 +1,37 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * FM TX module header.
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FMDRV_TX_H
+#define _FMDRV_TX_H
+
+int fm_tx_set_frequency(struct fmdrv_ops *, unsigned int);
+int fm_tx_set_pwr_lvl(struct fmdrv_ops *, unsigned char);
+int fm_tx_set_region(struct fmdrv_ops *, unsigned char);
+int fm_tx_set_mute_mode(struct fmdrv_ops *, unsigned char);
+int fm_tx_set_stereo_mono(struct fmdrv_ops *, unsigned short);
+int fm_tx_set_rds_mode(struct fmdrv_ops *, unsigned char);
+int fm_tx_set_radio_text(struct fmdrv_ops *, unsigned char *, unsigned char);
+int fm_tx_set_af(struct fmdrv_ops *, unsigned int);
+int fm_tx_set_preemph_filter(struct fmdrv_ops *, unsigned int);
+int fm_tx_set_ant_imp(struct fmdrv_ops *, unsigned char);
+
+#endif
+
diff --git a/drivers/staging/ti-st/fmdrv_v4l2.c b/drivers/staging/ti-st/fmdrv_v4l2.c
index 643794d13e87..40f77fbba6a3 100644
--- a/drivers/staging/ti-st/fmdrv_v4l2.c
+++ b/drivers/staging/ti-st/fmdrv_v4l2.c
@@ -4,12 +4,13 @@
*
* This module registers with V4L2 subsystem as Radio
* data system interface (/dev/radio). During the registration,
- * it will expose two set of function pointers to V4L2 subsystem.
+ * it will expose two set of function pointers.
*
* 1) File operation related API (open, close, read, write, poll...etc).
* 2) Set of V4L2 IOCTL complaint API.
*
* Copyright (C) 2010 Texas Instruments
+ * Author: Raja Mani <raja_mani@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,15 +31,7 @@
#include "fmdrv_v4l2.h"
#include "fmdrv_common.h"
#include "fmdrv_rx.h"
-/* TODO: Enable when FM TX is supported */
-/* #include "fmdrv_tx.h" */
-
-#ifndef DEBUG
-#ifdef pr_info
-#undef pr_info
-#define pr_info(fmt, arg...)
-#endif
-#endif
+#include "fmdrv_tx.h"
static struct video_device *gradio_dev;
static unsigned char radio_disconnected;
@@ -82,6 +75,7 @@ static struct v4l2_queryctrl fmdrv_v4l2_queryctrl[] = {
};
/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */
+
/* Read RX RDS data */
static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
size_t count, loff_t *ppos)
@@ -94,34 +88,31 @@ static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
if (!radio_disconnected) {
pr_err("(fmdrv): FM device is already disconnected\n");
- ret = -EIO;
- goto exit;
+ return -EIO;
}
/* Turn on RDS mode , if it is disabled */
ret = fm_rx_get_rds_mode(fmdev, &rds_mode);
if (ret < 0) {
- pr_err("(fmdrv): Unable to read current rds mode");
- goto exit;
+ pr_err("(fmdrv): Unable to read current rds mode\n");
+ return ret;
}
+
if (rds_mode == FM_RDS_DISABLE) {
ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE);
if (ret < 0) {
- pr_err("(fmdrv): Failed to enable rds mode");
- goto exit;
+ pr_err("(fmdrv): Failed to enable rds mode\n");
+ return ret;
}
}
+
/* Copy RDS data from internal buffer to user buffer */
ret = fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
-exit:
return ret;
}
-/* Write RDS data.
- * TODO: When FM TX support is added, use "V4L2_CID_RDS_TX_XXXX" codes,
- * instead of write operation.
- */
+/* Write TX RDS data */
static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
size_t count, loff_t *ppos)
{
@@ -130,13 +121,12 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
struct fmdrv_ops *fmdev;
ret = copy_from_user(&rds, buf, sizeof(rds));
- pr_info("(fmdrv): (%d)type: %d, text %s, af %d",
+ pr_debug("(fmdrv): (%d)type: %d, text %s, af %d\n",
ret, rds.text_type, rds.text, rds.af_freq);
fmdev = video_drvdata(file);
- /* TODO: Enable when FM TX is supported */
- /* fm_tx_set_radio_text(fmdev, rds.text, rds.text_type); */
- /* fm_tx_set_af(fmdev, rds.af_freq); */
+ fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
+ fm_tx_set_af(fmdev, rds.af_freq);
return 0;
}
@@ -149,12 +139,14 @@ static unsigned int fm_v4l2_fops_poll(struct file *file,
fmdev = video_drvdata(file);
ret = fmc_is_rds_data_available(fmdev, file, pts);
- if (!ret)
+ if (ret < 0)
return POLLIN | POLLRDNORM;
+
return 0;
}
-/* Handle open request for "/dev/radioX" device.
+/*
+ * Handle open request for "/dev/radioX" device.
* Start with FM RX mode as default.
*/
static int fm_v4l2_fops_open(struct file *file)
@@ -165,26 +157,26 @@ static int fm_v4l2_fops_open(struct file *file)
/* Don't allow multiple open */
if (radio_disconnected) {
pr_err("(fmdrv): FM device is already opened\n");
- ret = -EBUSY;
- goto exit;
+ return -EBUSY;
}
fmdev = video_drvdata(file);
+
ret = fmc_prepare(fmdev);
if (ret < 0) {
- pr_err("(fmdrv): Unable to prepare FM CORE");
- goto exit;
+ pr_err("(fmdrv): Unable to prepare FM CORE\n");
+ return ret;
}
- pr_info("(fmdrv): Load FM RX firmware..");
+ pr_debug("(fmdrv): Load FM RX firmware..\n");
+
ret = fmc_set_mode(fmdev, FM_MODE_RX);
if (ret < 0) {
- pr_err("(fmdrv): Unable to load FM RX firmware");
- goto exit;
+ pr_err("(fmdrv): Unable to load FM RX firmware\n");
+ return ret;
}
radio_disconnected = 1;
-exit:
return ret;
}
@@ -195,22 +187,23 @@ static int fm_v4l2_fops_release(struct file *file)
fmdev = video_drvdata(file);
if (!radio_disconnected) {
- pr_info("(fmdrv):FM dev already closed, close called again?");
- goto exit;
+ pr_debug("(fmdrv): FM device is already closed\n");
+ return ret;
}
+
ret = fmc_set_mode(fmdev, FM_MODE_OFF);
if (ret < 0) {
- pr_err("(fmdrv): Unable to turn off the chip");
- goto exit;
+ pr_err("(fmdrv): Unable to turn off the chip\n");
+ return ret;
}
+
ret = fmc_release(fmdev);
if (ret < 0) {
- pr_err("(fmdrv): FM CORE release failed");
- goto exit;
+ pr_err("(fmdrv): FM CORE release failed\n");
+ return ret;
}
radio_disconnected = 0;
-exit:
return ret;
}
@@ -227,6 +220,7 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
V4L2_CAP_RDS_CAPTURE;
+
return 0;
}
@@ -257,8 +251,9 @@ static int fm_v4l2_vidioc_g_ctrl(struct file *file, void *priv,
int ret = -EINVAL;
unsigned short curr_vol;
unsigned char curr_mute_mode;
+ unsigned char afreq;
+ short threshold;
struct fmdrv_ops *fmdev;
- unsigned char chanl_spacing;
fmdev = video_drvdata(file);
@@ -266,51 +261,101 @@ static int fm_v4l2_vidioc_g_ctrl(struct file *file, void *priv,
case V4L2_CID_AUDIO_MUTE: /* get mute mode */
ret = fm_rx_get_mute_mode(fmdev, &curr_mute_mode);
if (ret < 0)
- goto exit;
+ return ret;
ctrl->value = curr_mute_mode;
break;
case V4L2_CID_AUDIO_VOLUME: /* get volume */
ret = fm_rx_get_volume(fmdev, &curr_vol);
if (ret < 0)
- goto exit;
+ return ret;
ctrl->value = curr_vol;
break;
- case V4L2_CID_CHANNEL_SPACING: /* channel spacing */
- ret = fm_rx_get_chanl_spacing(fmdev, &chanl_spacing);
- ctrl->value = chanl_spacing;
+ case V4L2_CID_RSSI_THRESHOLD:
+ ret = fm_rx_get_rssi_threshold(fmdev, &threshold);
+ if (ret == 0)
+ ctrl->value = threshold;
+ break;
+
+ case V4L2_CID_TUNE_AF:
+ ret = fm_rx_get_af_switch(fmdev, &afreq);
+ if (ret == 0)
+ ctrl->value = afreq;
+ break;
+
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ ctrl->value = fmdev->tx_data.preemph;
break;
}
-exit:
return ret;
}
+/*
+ * Change the value of specified control.
+ * V4L2_CID_TUNE_POWER_LEVEL: Application will specify power level value in
+ * units of dB/uV, whereas range and step are specific to FM chip. For TI's WL
+ * chips, convert application specified power level value to chip specific
+ * value by subtracting 122 from it. Refer to TI FM data sheet for details.
+ */
static int fm_v4l2_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
+ struct fmdrv_ops *fmdev = video_drvdata(file);
+ unsigned int emph_filter;
int ret = -EINVAL;
- struct fmdrv_ops *fmdev;
-
- fmdev = video_drvdata(file);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE: /* set mute */
ret = fmc_set_mute_mode(fmdev, (unsigned char)ctrl->value);
- if (ret < 0)
- goto exit;
break;
+
case V4L2_CID_AUDIO_VOLUME: /* set volume */
ret = fm_rx_set_volume(fmdev, (unsigned short)ctrl->value);
- if (ret < 0)
- goto exit;
break;
- case V4L2_CID_CHANNEL_SPACING: /* channel spacing */
- ret = fm_rx_set_chanl_spacing(fmdev, (unsigned int)ctrl->value);
+ case V4L2_CID_TUNE_POWER_LEVEL: /* set TX power level - ext control */
+ if (ctrl->value >= FM_PWR_LVL_LOW &&
+ ctrl->value <= FM_PWR_LVL_HIGH) {
+ ctrl->value = FM_PWR_LVL_HIGH - ctrl->value;
+ ret = fm_tx_set_pwr_lvl(fmdev,
+ (unsigned char)ctrl->value);
+ } else
+ ret = -ERANGE;
+ break;
+
+ case V4L2_CID_RSSI_THRESHOLD:
+ ret = fm_rx_set_rssi_threshold(fmdev, (short)ctrl->value);
+ break;
+
+ case V4L2_CID_TUNE_AF:
+ ret = fm_rx_set_af_switch(fmdev, (unsigned char)ctrl->value);
+ break;
+
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ if (ctrl->value < V4L2_PREEMPHASIS_DISABLED ||
+ ctrl->value > V4L2_PREEMPHASIS_75_uS) {
+ ret = -EINVAL;
+ break;
+ }
+ if (ctrl->value == V4L2_PREEMPHASIS_DISABLED)
+ emph_filter = FM_TX_PREEMPH_OFF;
+ else if (ctrl->value == V4L2_PREEMPHASIS_50_uS)
+ emph_filter = FM_TX_PREEMPH_50US;
+ else
+ emph_filter = FM_TX_PREEMPH_75US;
+ ret = fm_tx_set_preemph_filter(fmdev, emph_filter);
+ break;
+
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ if (ctrl->value == FM_TX_ANT_IMP_50 ||
+ ctrl->value == FM_TX_ANT_IMP_200 ||
+ ctrl->value == FM_TX_ANT_IMP_500)
+ ret = fm_tx_set_ant_imp(fmdev, ctrl->value);
+ else
+ ret = -EINVAL;
break;
}
-exit:
return ret;
}
@@ -330,45 +375,39 @@ static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv,
{
if (audio->index != 0)
return -EINVAL;
+
return 0;
}
-/* Get tuner attributes. If current mode is NOT RX, set to RX */
+/* Get tuner attributes. If current mode is NOT RX, return error */
static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
+ struct fmdrv_ops *fmdev = video_drvdata(file);
unsigned int bottom_frequency;
unsigned int top_frequency;
unsigned short stereo_mono_mode;
unsigned short rssilvl;
int ret = -EINVAL;
- struct fmdrv_ops *fmdev;
if (tuner->index != 0)
- goto exit;
+ return ret;
- fmdev = video_drvdata(file);
- if (fmdev->curr_fmmode != FM_MODE_RX) {
- ret = fmc_set_mode(fmdev, FM_MODE_RX);
- if (ret < 0) {
- pr_err("(fmdrv): Failed to set RX mode; unable to " \
- "read tuner attributes\n");
- goto exit;
- }
- }
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
- ret = fm_rx_get_currband_lowhigh_freq(fmdev, &bottom_frequency,
+ ret = fm_rx_get_currband_freq_range(fmdev, &bottom_frequency,
&top_frequency);
- if (ret < 0)
- goto exit;
+ if (ret != 0)
+ return ret;
ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode);
- if (ret < 0)
- goto exit;
+ if (ret != 0)
+ return ret;
ret = fm_rx_get_rssi_level(fmdev, &rssilvl);
- if (ret < 0)
- goto exit;
+ if (ret != 0)
+ return ret;
strcpy(tuner->name, "FM");
tuner->type = V4L2_TUNER_RADIO;
@@ -378,64 +417,66 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO |
((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0);
tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
- V4L2_TUNER_CAP_LOW;
+ V4L2_TUNER_CAP_LOW;
tuner->audmode = (stereo_mono_mode ?
V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
- /* Actual rssi value lies in between -128 to +127.
+ /*
+ * Actual rssi value lies in between -128 to +127.
* Convert this range from 0 to 255 by adding +128
*/
rssilvl += 128;
- /* Return signal strength value should be within 0 to 65535.
+ /*
+ * Return signal strength value should be within 0 to 65535.
* Find out correct signal radio by multiplying (65535/255) = 257
*/
tuner->signal = rssilvl * 257;
tuner->afc = 0;
-exit:
return ret;
}
-/* Set tuner attributes. If current mode is NOT RX, set to RX.
+/*
+ * Set tuner attributes. If current mode is NOT RX, set to RX.
* Currently, we set only audio mode (mono/stereo) and RDS state (on/off).
* Should we set other tuner attributes, too?
*/
static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
+ struct fmdrv_ops *fmdev = video_drvdata(file);
unsigned short aud_mode;
unsigned char rds_mode;
int ret = -EINVAL;
- struct fmdrv_ops *fmdev;
if (tuner->index != 0)
- goto exit;
+ return ret;
aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ?
- FM_STEREO_MODE : FM_MONO_MODE;
+ FM_STEREO_MODE : FM_MONO_MODE;
rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ?
FM_RDS_ENABLE : FM_RDS_DISABLE;
- fmdev = video_drvdata(file);
if (fmdev->curr_fmmode != FM_MODE_RX) {
ret = fmc_set_mode(fmdev, FM_MODE_RX);
if (ret < 0) {
- pr_err("(fmdrv): Failed to set RX mode; unable to" \
+ pr_err("(fmdrv): Failed to set RX mode; unable to "
"write tuner attributes\n");
- goto exit;
+ return ret;
}
}
ret = fmc_set_stereo_mono(fmdev, aud_mode);
- if (ret < 0)
- goto exit;
+ if (ret < 0) {
+ pr_err("(fmdrv): Failed to set RX stereo/mono mode\n");
+ return ret;
+ }
ret = fmc_set_rds_mode(fmdev, rds_mode);
if (ret < 0)
- goto exit;
+ pr_err("(fmdrv): Failed to set RX RDS mode\n");
-exit:
return ret;
}
@@ -444,14 +485,15 @@ static int fm_v4l2_vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
int ret;
- struct fmdrv_ops *fmdev;
+ struct fmdrv_ops *fmdev = video_drvdata(file);
- fmdev = video_drvdata(file);
ret = fmc_get_frequency(fmdev, &freq->frequency);
- if (ret < 0)
+ if (ret < 0) {
+ pr_err("(fmdrv): Failed to get frequency\n");
return ret;
+ }
- /* Convert the frequency from Khz to 62.5 Hz */
+ /* Frequency unit of 62.5 Hz*/
freq->frequency = (unsigned int) freq->frequency * 16;
return 0;
@@ -461,45 +503,144 @@ static int fm_v4l2_vidioc_g_frequency(struct file *file, void *priv,
static int fm_v4l2_vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
+ struct fmdrv_ops *fmdev = video_drvdata(file);
int ret;
- struct fmdrv_ops *fmdev;
- fmdev = video_drvdata(file);
-
- /* As tuner->capability is set to V4L2_TUNER_CAP_LOW, application sends
- * the frequency in units of 62.5 Hz but as FM chip accepts the frequency
- * in units of KHz convert the frequency from units of 62.5 Hz to KHz.
- */
+ /*
+ * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency
+ * in units of 62.5 Hz.
+ */
freq->frequency = (unsigned int)(freq->frequency / 16);
ret = fmc_set_frequency(fmdev, freq->frequency);
- if (ret < 0)
- return ret;
- return 0;
+
+ return ret;
}
/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */
static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv,
struct v4l2_hw_freq_seek *seek)
{
+ struct fmdrv_ops *fmdev = video_drvdata(file);
int ret;
- struct fmdrv_ops *fmdev;
- fmdev = video_drvdata(file);
if (fmdev->curr_fmmode != FM_MODE_RX) {
ret = fmc_set_mode(fmdev, FM_MODE_RX);
if (ret != 0) {
- pr_err("(fmdrv): Failed to set RX mode; unable to " \
+ pr_err("(fmdrv): Failed to set RX mode; unable to "
"start HW frequency seek\n");
- goto exit;
+ return ret;
}
}
ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around);
if (ret < 0)
- goto exit;
+ pr_err("(fmdrv): RX seek failed - %d\n", ret);
+
+ return ret;
+}
+
+static int fm_v4l2_vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ext_ctrls)
+{
+ struct v4l2_control ctrl;
+ int index;
+ int ret = -EINVAL;
+
+ if (V4L2_CTRL_CLASS_FM_TX == ext_ctrls->ctrl_class) {
+ for (index = 0; index < ext_ctrls->count; index++) {
+ ctrl.id = ext_ctrls->controls[index].id;
+ ctrl.value = ext_ctrls->controls[index].value;
+ ret = fm_v4l2_vidioc_g_ctrl(file, priv, &ctrl);
+ if (ret < 0) {
+ ext_ctrls->error_idx = index;
+ break;
+ }
+ ext_ctrls->controls[index].value = ctrl.value;
+ }
+ }
+
+ return ret;
+}
+
+static int fm_v4l2_vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ext_ctrls)
+{
+ struct v4l2_control ctrl;
+ int index;
+ int ret = -EINVAL;
+
+ if (V4L2_CTRL_CLASS_FM_TX == ext_ctrls->ctrl_class) {
+ for (index = 0; index < ext_ctrls->count; index++) {
+ ctrl.id = ext_ctrls->controls[index].id;
+ ctrl.value = ext_ctrls->controls[index].value;
+ ret = fm_v4l2_vidioc_s_ctrl(file, priv, &ctrl);
+ if (ret < 0) {
+ ext_ctrls->error_idx = index;
+ break;
+ }
+ ext_ctrls->controls[index].value = ctrl.value;
+ }
+ }
+
+ return ret;
+}
+
+/* Get modulator attributes. If mode is not TX, return no attributes. */
+static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *mod)
+{
+ struct fmdrv_ops *fmdev = video_drvdata(file);;
+
+ if (mod->index != 0)
+ return -EINVAL;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) |
+ ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0);
+
+ mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
+
+ return 0;
+}
+
+/* Set modulator attributes. If mode is not TX, set to TX. */
+static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *mod)
+{
+ struct fmdrv_ops *fmdev = video_drvdata(file);
+ unsigned char rds_mode;
+ unsigned short aud_mode;
+ int ret;
+
+ if (mod->index != 0)
+ return -EINVAL;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX) {
+ ret = fmc_set_mode(fmdev, FM_MODE_TX);
+ if (ret != 0) {
+ pr_err("(fmdrv): Failed to set TX mode; unable to "
+ "set modulator attributes\n");
+ return ret;
+ }
+ }
+
+ aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ?
+ FM_STEREO_MODE : FM_MONO_MODE;
+ rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ?
+ FM_RDS_ENABLE : FM_RDS_DISABLE;
+ ret = fm_tx_set_stereo_mono(fmdev, aud_mode);
+ if (ret < 0) {
+ pr_err("(fmdrv): Failed to set mono/stereo mode for TX\n");
+ return ret;
+ }
+ ret = fm_tx_set_rds_mode(fmdev, rds_mode);
+ if (ret < 0)
+ pr_err("(fmdrv): Failed to set rds mode for TX\n");
-exit:
return ret;
}
@@ -518,13 +659,17 @@ static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = {
.vidioc_queryctrl = fm_v4l2_vidioc_queryctrl,
.vidioc_g_ctrl = fm_v4l2_vidioc_g_ctrl,
.vidioc_s_ctrl = fm_v4l2_vidioc_s_ctrl,
+ .vidioc_g_ext_ctrls = fm_v4l2_vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = fm_v4l2_vidioc_s_ext_ctrls,
.vidioc_g_audio = fm_v4l2_vidioc_g_audio,
.vidioc_s_audio = fm_v4l2_vidioc_s_audio,
.vidioc_g_tuner = fm_v4l2_vidioc_g_tuner,
.vidioc_s_tuner = fm_v4l2_vidioc_s_tuner,
.vidioc_g_frequency = fm_v4l2_vidioc_g_frequency,
.vidioc_s_frequency = fm_v4l2_vidioc_s_frequency,
- .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek
+ .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek,
+ .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator,
+ .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator
};
/* V4L2 RADIO device parent structure */
@@ -537,14 +682,12 @@ static struct video_device fm_viddev_template = {
int fm_v4l2_init_video_device(struct fmdrv_ops *fmdev, int radio_nr)
{
- int ret = -ENOMEM;
- gradio_dev = NULL;
/* Allocate new video device */
gradio_dev = video_device_alloc();
if (NULL == gradio_dev) {
- pr_err("(fmdrv): Can't allocate video device");
- goto exit;
+ pr_err("(fmdrv): Can't allocate video device\n");
+ return -ENOMEM;
}
/* Setup FM driver's V4L2 properties */
@@ -555,15 +698,13 @@ int fm_v4l2_init_video_device(struct fmdrv_ops *fmdev, int radio_nr)
/* Register with V4L2 subsystem as RADIO device */
if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
video_device_release(gradio_dev);
- pr_err("(fmdrv): Could not register video device");
- goto exit;
+ pr_err("(fmdrv): Could not register video device\n");
+ return -ENOMEM;
}
fmdev->radio_dev = gradio_dev;
- ret = 0;
-exit:
- return ret;
+ return 0;
}
void *fm_v4l2_deinit_video_device(void)