diff options
Diffstat (limited to 'drivers/staging/ti-st')
-rw-r--r-- | drivers/staging/ti-st/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv.h | 33 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv_common.c | 728 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv_common.h | 319 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv_rx.c | 634 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv_rx.h | 43 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv_tx.c | 420 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv_tx.h | 37 | ||||
-rw-r--r-- | drivers/staging/ti-st/fmdrv_v4l2.c | 387 |
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) |