mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
radio: iris: Add support for RT Plus, eRT feature.
- Allow Soc to interrupt host for RT Plus, eRT data - Parse the RDS group for RT Plus, eRT - Queue the parsed data and event for RT Plus, eRT to upper layer CRs-fixed: 419248 Signed-off-by: Ayaz Ahmad <aahmad@codeaurora.org> (cherry picked from commit 89265111440674132f59c3aa2938a0aefbfc84fb) Change-Id: I44010cebd5d7de7ae3a4b076971d24d65aa4fb91 Signed-off-by: Sudhir Sharma <sudsha@codeaurora.org>
This commit is contained in:
parent
8d0d063173
commit
124d6f7020
3 changed files with 339 additions and 8 deletions
|
@ -39,6 +39,17 @@
|
|||
#include <asm/unaligned.h>
|
||||
|
||||
static unsigned int rds_buf = 100;
|
||||
static int oda_agt;
|
||||
static int grp_mask;
|
||||
static int rt_plus_carrier = -1;
|
||||
static int ert_carrier = -1;
|
||||
static unsigned char ert_buf[256];
|
||||
static unsigned char ert_len;
|
||||
static unsigned char c_byt_pair_index;
|
||||
static char utf_8_flag;
|
||||
static char rt_ert_flag;
|
||||
static char formatting_dir;
|
||||
|
||||
module_param(rds_buf, uint, 0);
|
||||
MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
|
||||
|
||||
|
@ -108,7 +119,11 @@ struct iris_device {
|
|||
|
||||
static struct video_device *priv_videodev;
|
||||
static int iris_do_calibration(struct iris_device *radio);
|
||||
|
||||
static void hci_buff_ert(struct iris_device *radio,
|
||||
struct rds_grp_data *rds_buf);
|
||||
static void hci_ev_rt_plus(struct iris_device *radio,
|
||||
struct rds_grp_data rds_buf);
|
||||
static void hci_ev_ert(struct iris_device *radio);
|
||||
static int update_spur_table(struct iris_device *radio);
|
||||
static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
|
||||
{
|
||||
|
@ -921,6 +936,20 @@ static int hci_fm_cancel_search_req(struct radio_hci_dev *hdev,
|
|||
return radio_hci_send_cmd(hdev, opcode, 0, NULL);
|
||||
}
|
||||
|
||||
static int hci_fm_rds_grp_mask_req(struct radio_hci_dev *hdev,
|
||||
unsigned long param)
|
||||
{
|
||||
__u16 opcode = 0;
|
||||
|
||||
struct hci_fm_rds_grp_req *fm_grp_mask =
|
||||
(struct hci_fm_rds_grp_req *)param;
|
||||
|
||||
opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
|
||||
HCI_OCF_FM_RDS_GRP);
|
||||
return radio_hci_send_cmd(hdev, opcode, sizeof(*fm_grp_mask),
|
||||
fm_grp_mask);
|
||||
}
|
||||
|
||||
static int hci_fm_rds_grp_process_req(struct radio_hci_dev *hdev,
|
||||
unsigned long param)
|
||||
{
|
||||
|
@ -1313,7 +1342,13 @@ static int hci_fm_search_station_list
|
|||
static int hci_fm_rds_grp(struct hci_fm_rds_grp_req *arg,
|
||||
struct radio_hci_dev *hdev)
|
||||
{
|
||||
return 0;
|
||||
int ret = 0;
|
||||
struct hci_fm_rds_grp_req *fm_grp_mask = arg;
|
||||
|
||||
ret = radio_hci_request(hdev, hci_fm_rds_grp_mask_req, (unsigned
|
||||
long)fm_grp_mask, RADIO_HCI_TIMEOUT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
|
||||
|
@ -2078,6 +2113,234 @@ static inline void hci_ev_stereo_status(struct radio_hci_dev *hdev,
|
|||
iris_q_event(radio, IRIS_EVT_MONO);
|
||||
}
|
||||
|
||||
static void hci_ev_raw_rds_group_data(struct radio_hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct iris_device *radio;
|
||||
unsigned char blocknum, index;
|
||||
struct rds_grp_data temp;
|
||||
unsigned int mask_bit;
|
||||
unsigned short int aid, agt, gtc;
|
||||
unsigned short int carrier;
|
||||
|
||||
radio = video_get_drvdata(video_get_dev());
|
||||
index = RDSGRP_DATA_OFFSET;
|
||||
|
||||
for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
|
||||
temp.rdsBlk[blocknum].rdsLsb =
|
||||
(skb->data[index]);
|
||||
temp.rdsBlk[blocknum].rdsMsb =
|
||||
(skb->data[index+1]);
|
||||
index = index + 2;
|
||||
}
|
||||
|
||||
aid = AID(temp.rdsBlk[3].rdsLsb, temp.rdsBlk[3].rdsMsb);
|
||||
gtc = GTC(temp.rdsBlk[1].rdsMsb);
|
||||
agt = AGT(temp.rdsBlk[1].rdsLsb);
|
||||
|
||||
if (gtc == GRP_3A) {
|
||||
switch (aid) {
|
||||
case ERT_AID:
|
||||
/* calculate the grp mask for RDS grp
|
||||
* which will contain actual eRT text
|
||||
*
|
||||
* Bit Pos 0 1 2 3 4 5 6 7
|
||||
* Grp Type 0A 0B 1A 1B 2A 2B 3A 3B
|
||||
*
|
||||
* similary for rest grps
|
||||
*/
|
||||
mask_bit = (((agt >> 1) << 1) + (agt & 1));
|
||||
oda_agt = (1 << mask_bit);
|
||||
utf_8_flag = (temp.rdsBlk[2].rdsLsb & 1);
|
||||
formatting_dir = EXTRACT_BIT(temp.rdsBlk[2].rdsLsb,
|
||||
ERT_FORMAT_DIR_BIT);
|
||||
if (ert_carrier != agt)
|
||||
iris_q_event(radio, IRIS_EVT_NEW_ODA);
|
||||
ert_carrier = agt;
|
||||
break;
|
||||
case RT_PLUS_AID:
|
||||
/* calculate the grp mask for RDS grp
|
||||
* which will contain actual eRT text
|
||||
*
|
||||
* Bit Pos 0 1 2 3 4 5 6 7
|
||||
* Grp Type 0A 0B 1A 1B 2A 2B 3A 3B
|
||||
*
|
||||
* similary for rest grps
|
||||
*/
|
||||
mask_bit = (((agt >> 1) << 1) + (agt & 1));
|
||||
oda_agt = (1 << mask_bit);
|
||||
/*Extract 5th bit of MSB (b7b6b5b4b3b2b1b0)*/
|
||||
rt_ert_flag = EXTRACT_BIT(temp.rdsBlk[2].rdsMsb,
|
||||
RT_ERT_FLAG_BIT);
|
||||
if (rt_plus_carrier != agt)
|
||||
iris_q_event(radio, IRIS_EVT_NEW_ODA);
|
||||
rt_plus_carrier = agt;
|
||||
break;
|
||||
default:
|
||||
oda_agt = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
carrier = gtc;
|
||||
if ((carrier == rt_plus_carrier))
|
||||
hci_ev_rt_plus(radio, temp);
|
||||
else if (carrier == ert_carrier)
|
||||
hci_buff_ert(radio, &temp);
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_buff_ert(struct iris_device *radio,
|
||||
struct rds_grp_data *rds_buf)
|
||||
{
|
||||
int i;
|
||||
unsigned short int info_byte = 0;
|
||||
unsigned short int byte_pair_index;
|
||||
|
||||
byte_pair_index = AGT(rds_buf->rdsBlk[1].rdsLsb);
|
||||
if (byte_pair_index == 0) {
|
||||
c_byt_pair_index = 0;
|
||||
ert_len = 0;
|
||||
}
|
||||
if (c_byt_pair_index == byte_pair_index) {
|
||||
c_byt_pair_index++;
|
||||
for (i = 2; i <= 3; i++) {
|
||||
info_byte = rds_buf->rdsBlk[i].rdsLsb;
|
||||
info_byte |= (rds_buf->rdsBlk[i].rdsMsb << 8);
|
||||
ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsMsb;
|
||||
ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsLsb;
|
||||
if ((utf_8_flag == 0)
|
||||
&& (info_byte == CARRIAGE_RETURN)) {
|
||||
ert_len -= 2;
|
||||
break;
|
||||
} else if ((utf_8_flag == 1)
|
||||
&&
|
||||
(rds_buf->rdsBlk[i].rdsMsb
|
||||
== CARRIAGE_RETURN)) {
|
||||
info_byte = CARRIAGE_RETURN;
|
||||
ert_len -= 2;
|
||||
break;
|
||||
} else if ((utf_8_flag == 1)
|
||||
&&
|
||||
(rds_buf->rdsBlk[i].rdsLsb
|
||||
== CARRIAGE_RETURN)) {
|
||||
info_byte = CARRIAGE_RETURN;
|
||||
ert_len--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((byte_pair_index == MAX_ERT_SEGMENT) ||
|
||||
(info_byte == CARRIAGE_RETURN)) {
|
||||
hci_ev_ert(radio);
|
||||
c_byt_pair_index = 0;
|
||||
ert_len = 0;
|
||||
}
|
||||
} else {
|
||||
ert_len = 0;
|
||||
c_byt_pair_index = 0;
|
||||
}
|
||||
}
|
||||
static void hci_ev_ert(struct iris_device *radio)
|
||||
|
||||
{
|
||||
char *data = NULL;
|
||||
|
||||
if (ert_len <= 0)
|
||||
return;
|
||||
data = kmalloc((ert_len + 3), GFP_ATOMIC);
|
||||
if (data != NULL) {
|
||||
data[0] = ert_len;
|
||||
data[1] = utf_8_flag;
|
||||
data[2] = formatting_dir;
|
||||
memcpy((data + 3), ert_buf, ert_len);
|
||||
iris_q_evt_data(radio, data, (ert_len + 3), IRIS_BUF_ERT);
|
||||
iris_q_event(radio, IRIS_EVT_NEW_ERT);
|
||||
kfree(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_ev_rt_plus(struct iris_device *radio,
|
||||
struct rds_grp_data rds_buf)
|
||||
{
|
||||
char tag_type1, tag_type2;
|
||||
char *data = NULL;
|
||||
int len = 0;
|
||||
unsigned short int agt;
|
||||
|
||||
agt = AGT(rds_buf.rdsBlk[1].rdsLsb);
|
||||
/*right most 3 bits of Lsb of block 2
|
||||
* and left most 3 bits of Msb of block 3
|
||||
*/
|
||||
tag_type1 = (((agt & TAG1_MSB_MASK) << TAG1_MSB_OFFSET) |
|
||||
(rds_buf.rdsBlk[2].rdsMsb >> TAG1_LSB_OFFSET));
|
||||
|
||||
/*right most 1 bit of lsb of 3rd block
|
||||
* and left most 5 bits of Msb of 4th block
|
||||
*/
|
||||
tag_type2 = (((rds_buf.rdsBlk[2].rdsLsb & TAG2_MSB_MASK)
|
||||
<< TAG2_MSB_OFFSET) |
|
||||
(rds_buf.rdsBlk[3].rdsMsb >> TAG2_LSB_OFFSET));
|
||||
|
||||
if (tag_type1 != DUMMY_CLASS)
|
||||
len += RT_PLUS_LEN_1_TAG;
|
||||
if (tag_type2 != DUMMY_CLASS)
|
||||
len += RT_PLUS_LEN_1_TAG;
|
||||
|
||||
if (len != 0) {
|
||||
len += 2;
|
||||
data = kmalloc(len, GFP_ATOMIC);
|
||||
} else {
|
||||
FMDERR("Len is zero\n");
|
||||
return ;
|
||||
}
|
||||
if (data != NULL) {
|
||||
data[0] = len;
|
||||
len = 1;
|
||||
data[len++] = rt_ert_flag;
|
||||
if (tag_type1 != DUMMY_CLASS) {
|
||||
data[len++] = tag_type1;
|
||||
/*start position of tag1
|
||||
*right most 5 bits of msb of 3rd block
|
||||
*and left most bit of lsb of 3rd block
|
||||
*/
|
||||
data[len++] = (((rds_buf.rdsBlk[2].rdsMsb &
|
||||
TAG1_POS_MSB_MASK)
|
||||
<< TAG1_POS_MSB_OFFSET)
|
||||
|
|
||||
(rds_buf.rdsBlk[2].rdsLsb >>
|
||||
TAG1_POS_LSB_OFFSET));
|
||||
/*length of tag1
|
||||
*left most 6 bits of lsb of 3rd block
|
||||
*/
|
||||
data[len++] = ((rds_buf.rdsBlk[2].rdsLsb
|
||||
>> TAG1_LEN_OFFSET)
|
||||
&
|
||||
TAG1_LEN_MASK) + 1;
|
||||
}
|
||||
if (tag_type2 != DUMMY_CLASS) {
|
||||
data[len++] = tag_type2;
|
||||
/*start position of tag2
|
||||
*right most 3 bit of msb of 4th block
|
||||
*and left most 3 bits of lsb of 4th block
|
||||
*/
|
||||
data[len++] = (((rds_buf.rdsBlk[3].rdsMsb
|
||||
& TAG2_POS_MSB_MASK)
|
||||
<< TAG2_POS_MSB_OFFSET)
|
||||
|
|
||||
(rds_buf.rdsBlk[3].rdsLsb
|
||||
>> TAG2_POS_LSB_OFFSET));
|
||||
/*length of tag2
|
||||
*right most 5 bits of lsb of 4th block
|
||||
*/
|
||||
data[len++] = (rds_buf.rdsBlk[3].rdsLsb
|
||||
& TAG2_LEN_MASK) + 1;
|
||||
}
|
||||
iris_q_evt_data(radio, data, len, IRIS_BUF_RT_PLUS);
|
||||
iris_q_event(radio, IRIS_EVT_NEW_RT_PLUS);
|
||||
kfree(data);
|
||||
} else {
|
||||
FMDERR("memory allocation failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hci_ev_program_service(struct radio_hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
|
@ -2217,6 +2480,7 @@ void radio_hci_event_packet(struct radio_hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_ev_service_available(hdev, skb);
|
||||
break;
|
||||
case HCI_EV_RDS_RX_DATA:
|
||||
hci_ev_raw_rds_group_data(hdev, skb);
|
||||
break;
|
||||
case HCI_EV_PROGRAM_SERVICE:
|
||||
hci_ev_program_service(hdev, skb);
|
||||
|
@ -2984,8 +3248,13 @@ static int iris_vidioc_s_ctrl(struct file *file, void *priv,
|
|||
}
|
||||
break;
|
||||
case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
|
||||
radio->rds_grp.rds_grp_enable_mask = ctrl->value;
|
||||
grp_mask = (grp_mask | oda_agt | ctrl->value);
|
||||
radio->rds_grp.rds_grp_enable_mask = grp_mask;
|
||||
radio->rds_grp.rds_buf_size = 1;
|
||||
radio->rds_grp.en_rds_change_filter = 0;
|
||||
retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
|
||||
if (retval < 0)
|
||||
FMDERR("error in setting group mask\n");
|
||||
break;
|
||||
case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
|
||||
rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
|
||||
|
|
|
@ -363,6 +363,53 @@ struct hci_fm_ch_det_threshold {
|
|||
#define HCI_REQ_CANCELED 2
|
||||
#define HCI_REQ_STATUS 3
|
||||
|
||||
#define MAX_RAW_RDS_GRPS 21
|
||||
|
||||
#define RDSGRP_DATA_OFFSET 0x1
|
||||
|
||||
/*RT PLUS*/
|
||||
#define DUMMY_CLASS 0
|
||||
#define RT_PLUS_LEN_1_TAG 3
|
||||
#define RT_ERT_FLAG_BIT 5
|
||||
|
||||
/*TAG1*/
|
||||
#define TAG1_MSB_OFFSET 3
|
||||
#define TAG1_MSB_MASK 7
|
||||
#define TAG1_LSB_OFFSET 5
|
||||
#define TAG1_POS_MSB_MASK 31
|
||||
#define TAG1_POS_MSB_OFFSET 1
|
||||
#define TAG1_POS_LSB_OFFSET 7
|
||||
#define TAG1_LEN_OFFSET 1
|
||||
#define TAG1_LEN_MASK 63
|
||||
|
||||
/*TAG2*/
|
||||
#define TAG2_MSB_OFFSET 5
|
||||
#define TAG2_MSB_MASK 1
|
||||
#define TAG2_LSB_OFFSET 3
|
||||
#define TAG2_POS_MSB_MASK 7
|
||||
#define TAG2_POS_MSB_OFFSET 3
|
||||
#define TAG2_POS_LSB_OFFSET 5
|
||||
#define TAG2_LEN_MASK 31
|
||||
|
||||
#define AGT_MASK 31
|
||||
/*Extract 5 left most bits of lsb of 2nd block*/
|
||||
#define AGT(x) (x & AGT_MASK)
|
||||
/*16 bits of 4th block*/
|
||||
#define AID(lsb, msb) ((msb << 8) | (lsb))
|
||||
/*Extract 5 right most bits of msb of 2nd block*/
|
||||
#define GTC(blk2msb) (blk2msb >> 3)
|
||||
|
||||
#define GRP_3A 0x6
|
||||
#define RT_PLUS_AID 0x4bd7
|
||||
|
||||
/*ERT*/
|
||||
#define ERT_AID 0x6552
|
||||
#define CARRIAGE_RETURN 0x000D
|
||||
#define MAX_ERT_SEGMENT 31
|
||||
#define ERT_FORMAT_DIR_BIT 1
|
||||
|
||||
#define EXTRACT_BIT(data, bit_pos) ((data & (1 << bit_pos)) >> bit_pos)
|
||||
|
||||
struct hci_ev_tune_status {
|
||||
__u8 sub_event;
|
||||
__le32 station_freq;
|
||||
|
@ -375,9 +422,19 @@ struct hci_ev_tune_status {
|
|||
__u8 intf_det_th;
|
||||
} __packed;
|
||||
|
||||
struct rds_blk_data {
|
||||
__u8 rdsMsb;
|
||||
__u8 rdsLsb;
|
||||
__u8 blockStatus;
|
||||
} __packed;
|
||||
|
||||
struct rds_grp_data {
|
||||
struct rds_blk_data rdsBlk[4];
|
||||
} __packed;
|
||||
|
||||
struct hci_ev_rds_rx_data {
|
||||
__u8 num_rds_grps;
|
||||
__u8 rds_grp_data[12];
|
||||
struct rds_grp_data rds_grp_data[MAX_RAW_RDS_GRPS];
|
||||
} __packed;
|
||||
|
||||
struct hci_ev_prg_service {
|
||||
|
@ -628,7 +685,10 @@ enum iris_evt_t {
|
|||
IRIS_EVT_NEW_AF_LIST,
|
||||
IRIS_EVT_TXRDSDAT,
|
||||
IRIS_EVT_TXRDSDONE,
|
||||
IRIS_EVT_RADIO_DISABLED
|
||||
IRIS_EVT_RADIO_DISABLED,
|
||||
IRIS_EVT_NEW_ODA,
|
||||
IRIS_EVT_NEW_RT_PLUS,
|
||||
IRIS_EVT_NEW_ERT,
|
||||
};
|
||||
enum emphasis_type {
|
||||
FM_RX_EMP75 = 0x0,
|
||||
|
@ -660,7 +720,7 @@ enum iris_region_t {
|
|||
IRIS_REGION_OTHER
|
||||
};
|
||||
|
||||
#define STD_BUF_SIZE (128)
|
||||
#define STD_BUF_SIZE (256)
|
||||
|
||||
enum iris_buf_t {
|
||||
IRIS_BUF_SRCH_LIST,
|
||||
|
@ -674,7 +734,9 @@ enum iris_buf_t {
|
|||
IRIS_BUF_RDS_CNTRS,
|
||||
IRIS_BUF_RD_DEFAULT,
|
||||
IRIS_BUF_CAL_DATA,
|
||||
IRIS_BUF_MAX
|
||||
IRIS_BUF_RT_PLUS,
|
||||
IRIS_BUF_ERT,
|
||||
IRIS_BUF_MAX,
|
||||
};
|
||||
|
||||
enum iris_xfr_t {
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
#define SRCH_MASK (1 << SRCH200KHZ_OFFSET)
|
||||
|
||||
/* Standard buffer size */
|
||||
#define STD_BUF_SIZE (128)
|
||||
#define STD_BUF_SIZE (256)
|
||||
/* Search direction */
|
||||
#define SRCH_DIR_UP (0)
|
||||
#define SRCH_DIR_DOWN (1)
|
||||
|
|
Loading…
Reference in a new issue