Commit 6705a9cc52733cb5cbdbee72be66ab462d8fb46f
Committed by
Mauro Carvalho Chehab
1 parent
92ce52695c
Exists in
master
and in
7 other branches
[media] radio: wl128x: Update registration process with ST
As underlying ST driver registration API's have changed with latest 2.6.38-rc8 kernel this patch will update the FM driver accordingly. Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Showing 1 changed file with 13 additions and 3 deletions Inline Diff
drivers/media/radio/wl128x/fmdrv_common.c
1 | /* | 1 | /* |
2 | * FM Driver for Connectivity chip of Texas Instruments. | 2 | * FM Driver for Connectivity chip of Texas Instruments. |
3 | * | 3 | * |
4 | * This sub-module of FM driver is common for FM RX and TX | 4 | * This sub-module of FM driver is common for FM RX and TX |
5 | * functionality. This module is responsible for: | 5 | * functionality. This module is responsible for: |
6 | * 1) Forming group of Channel-8 commands to perform particular | 6 | * 1) Forming group of Channel-8 commands to perform particular |
7 | * functionality (eg., frequency set require more than | 7 | * functionality (eg., frequency set require more than |
8 | * one Channel-8 command to be sent to the chip). | 8 | * one Channel-8 command to be sent to the chip). |
9 | * 2) Sending each Channel-8 command to the chip and reading | 9 | * 2) Sending each Channel-8 command to the chip and reading |
10 | * response back over Shared Transport. | 10 | * response back over Shared Transport. |
11 | * 3) Managing TX and RX Queues and Tasklets. | 11 | * 3) Managing TX and RX Queues and Tasklets. |
12 | * 4) Handling FM Interrupt packet and taking appropriate action. | 12 | * 4) Handling FM Interrupt packet and taking appropriate action. |
13 | * 5) Loading FM firmware to the chip (common, FM TX, and FM RX | 13 | * 5) Loading FM firmware to the chip (common, FM TX, and FM RX |
14 | * firmware files based on mode selection) | 14 | * firmware files based on mode selection) |
15 | * | 15 | * |
16 | * Copyright (C) 2011 Texas Instruments | 16 | * Copyright (C) 2011 Texas Instruments |
17 | * Author: Raja Mani <raja_mani@ti.com> | 17 | * Author: Raja Mani <raja_mani@ti.com> |
18 | * Author: Manjunatha Halli <manjunatha_halli@ti.com> | 18 | * Author: Manjunatha Halli <manjunatha_halli@ti.com> |
19 | * | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | 20 | * This program is free software; you can redistribute it and/or modify |
21 | * it under the terms of the GNU General Public License version 2 as | 21 | * it under the terms of the GNU General Public License version 2 as |
22 | * published by the Free Software Foundation. | 22 | * published by the Free Software Foundation. |
23 | * | 23 | * |
24 | * This program is distributed in the hope that it will be useful, | 24 | * This program is distributed in the hope that it will be useful, |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
27 | * GNU General Public License for more details. | 27 | * GNU General Public License for more details. |
28 | * | 28 | * |
29 | * You should have received a copy of the GNU General Public License | 29 | * You should have received a copy of the GNU General Public License |
30 | * along with this program; if not, write to the Free Software | 30 | * along with this program; if not, write to the Free Software |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
32 | * | 32 | * |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/firmware.h> | 36 | #include <linux/firmware.h> |
37 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
38 | #include "fmdrv.h" | 38 | #include "fmdrv.h" |
39 | #include "fmdrv_v4l2.h" | 39 | #include "fmdrv_v4l2.h" |
40 | #include "fmdrv_common.h" | 40 | #include "fmdrv_common.h" |
41 | #include <linux/ti_wilink_st.h> | 41 | #include <linux/ti_wilink_st.h> |
42 | #include "fmdrv_rx.h" | 42 | #include "fmdrv_rx.h" |
43 | #include "fmdrv_tx.h" | 43 | #include "fmdrv_tx.h" |
44 | 44 | ||
45 | /* Region info */ | 45 | /* Region info */ |
46 | static struct region_info region_configs[] = { | 46 | static struct region_info region_configs[] = { |
47 | /* Europe/US */ | 47 | /* Europe/US */ |
48 | { | 48 | { |
49 | .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, | 49 | .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, |
50 | .bot_freq = 87500, /* 87.5 MHz */ | 50 | .bot_freq = 87500, /* 87.5 MHz */ |
51 | .top_freq = 108000, /* 108 MHz */ | 51 | .top_freq = 108000, /* 108 MHz */ |
52 | .fm_band = 0, | 52 | .fm_band = 0, |
53 | }, | 53 | }, |
54 | /* Japan */ | 54 | /* Japan */ |
55 | { | 55 | { |
56 | .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, | 56 | .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, |
57 | .bot_freq = 76000, /* 76 MHz */ | 57 | .bot_freq = 76000, /* 76 MHz */ |
58 | .top_freq = 90000, /* 90 MHz */ | 58 | .top_freq = 90000, /* 90 MHz */ |
59 | .fm_band = 1, | 59 | .fm_band = 1, |
60 | }, | 60 | }, |
61 | }; | 61 | }; |
62 | 62 | ||
63 | /* Band selection */ | 63 | /* Band selection */ |
64 | static u8 default_radio_region; /* Europe/US */ | 64 | static u8 default_radio_region; /* Europe/US */ |
65 | module_param(default_radio_region, byte, 0); | 65 | module_param(default_radio_region, byte, 0); |
66 | MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan"); | 66 | MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan"); |
67 | 67 | ||
68 | /* RDS buffer blocks */ | 68 | /* RDS buffer blocks */ |
69 | static u32 default_rds_buf = 300; | 69 | static u32 default_rds_buf = 300; |
70 | module_param(default_rds_buf, uint, 0444); | 70 | module_param(default_rds_buf, uint, 0444); |
71 | MODULE_PARM_DESC(rds_buf, "RDS buffer entries"); | 71 | MODULE_PARM_DESC(rds_buf, "RDS buffer entries"); |
72 | 72 | ||
73 | /* Radio Nr */ | 73 | /* Radio Nr */ |
74 | static u32 radio_nr = -1; | 74 | static u32 radio_nr = -1; |
75 | module_param(radio_nr, int, 0444); | 75 | module_param(radio_nr, int, 0444); |
76 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); | 76 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); |
77 | 77 | ||
78 | /* FM irq handlers forward declaration */ | 78 | /* FM irq handlers forward declaration */ |
79 | static void fm_irq_send_flag_getcmd(struct fmdev *); | 79 | static void fm_irq_send_flag_getcmd(struct fmdev *); |
80 | static void fm_irq_handle_flag_getcmd_resp(struct fmdev *); | 80 | static void fm_irq_handle_flag_getcmd_resp(struct fmdev *); |
81 | static void fm_irq_handle_hw_malfunction(struct fmdev *); | 81 | static void fm_irq_handle_hw_malfunction(struct fmdev *); |
82 | static void fm_irq_handle_rds_start(struct fmdev *); | 82 | static void fm_irq_handle_rds_start(struct fmdev *); |
83 | static void fm_irq_send_rdsdata_getcmd(struct fmdev *); | 83 | static void fm_irq_send_rdsdata_getcmd(struct fmdev *); |
84 | static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *); | 84 | static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *); |
85 | static void fm_irq_handle_rds_finish(struct fmdev *); | 85 | static void fm_irq_handle_rds_finish(struct fmdev *); |
86 | static void fm_irq_handle_tune_op_ended(struct fmdev *); | 86 | static void fm_irq_handle_tune_op_ended(struct fmdev *); |
87 | static void fm_irq_handle_power_enb(struct fmdev *); | 87 | static void fm_irq_handle_power_enb(struct fmdev *); |
88 | static void fm_irq_handle_low_rssi_start(struct fmdev *); | 88 | static void fm_irq_handle_low_rssi_start(struct fmdev *); |
89 | static void fm_irq_afjump_set_pi(struct fmdev *); | 89 | static void fm_irq_afjump_set_pi(struct fmdev *); |
90 | static void fm_irq_handle_set_pi_resp(struct fmdev *); | 90 | static void fm_irq_handle_set_pi_resp(struct fmdev *); |
91 | static void fm_irq_afjump_set_pimask(struct fmdev *); | 91 | static void fm_irq_afjump_set_pimask(struct fmdev *); |
92 | static void fm_irq_handle_set_pimask_resp(struct fmdev *); | 92 | static void fm_irq_handle_set_pimask_resp(struct fmdev *); |
93 | static void fm_irq_afjump_setfreq(struct fmdev *); | 93 | static void fm_irq_afjump_setfreq(struct fmdev *); |
94 | static void fm_irq_handle_setfreq_resp(struct fmdev *); | 94 | static void fm_irq_handle_setfreq_resp(struct fmdev *); |
95 | static void fm_irq_afjump_enableint(struct fmdev *); | 95 | static void fm_irq_afjump_enableint(struct fmdev *); |
96 | static void fm_irq_afjump_enableint_resp(struct fmdev *); | 96 | static void fm_irq_afjump_enableint_resp(struct fmdev *); |
97 | static void fm_irq_start_afjump(struct fmdev *); | 97 | static void fm_irq_start_afjump(struct fmdev *); |
98 | static void fm_irq_handle_start_afjump_resp(struct fmdev *); | 98 | static void fm_irq_handle_start_afjump_resp(struct fmdev *); |
99 | static void fm_irq_afjump_rd_freq(struct fmdev *); | 99 | static void fm_irq_afjump_rd_freq(struct fmdev *); |
100 | static void fm_irq_afjump_rd_freq_resp(struct fmdev *); | 100 | static void fm_irq_afjump_rd_freq_resp(struct fmdev *); |
101 | static void fm_irq_handle_low_rssi_finish(struct fmdev *); | 101 | static void fm_irq_handle_low_rssi_finish(struct fmdev *); |
102 | static void fm_irq_send_intmsk_cmd(struct fmdev *); | 102 | static void fm_irq_send_intmsk_cmd(struct fmdev *); |
103 | static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *); | 103 | static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *); |
104 | 104 | ||
105 | /* | 105 | /* |
106 | * When FM common module receives interrupt packet, following handlers | 106 | * When FM common module receives interrupt packet, following handlers |
107 | * will be executed one after another to service the interrupt(s) | 107 | * will be executed one after another to service the interrupt(s) |
108 | */ | 108 | */ |
109 | enum fmc_irq_handler_index { | 109 | enum fmc_irq_handler_index { |
110 | FM_SEND_FLAG_GETCMD_IDX, | 110 | FM_SEND_FLAG_GETCMD_IDX, |
111 | FM_HANDLE_FLAG_GETCMD_RESP_IDX, | 111 | FM_HANDLE_FLAG_GETCMD_RESP_IDX, |
112 | 112 | ||
113 | /* HW malfunction irq handler */ | 113 | /* HW malfunction irq handler */ |
114 | FM_HW_MAL_FUNC_IDX, | 114 | FM_HW_MAL_FUNC_IDX, |
115 | 115 | ||
116 | /* RDS threshold reached irq handler */ | 116 | /* RDS threshold reached irq handler */ |
117 | FM_RDS_START_IDX, | 117 | FM_RDS_START_IDX, |
118 | FM_RDS_SEND_RDS_GETCMD_IDX, | 118 | FM_RDS_SEND_RDS_GETCMD_IDX, |
119 | FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX, | 119 | FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX, |
120 | FM_RDS_FINISH_IDX, | 120 | FM_RDS_FINISH_IDX, |
121 | 121 | ||
122 | /* Tune operation ended irq handler */ | 122 | /* Tune operation ended irq handler */ |
123 | FM_HW_TUNE_OP_ENDED_IDX, | 123 | FM_HW_TUNE_OP_ENDED_IDX, |
124 | 124 | ||
125 | /* TX power enable irq handler */ | 125 | /* TX power enable irq handler */ |
126 | FM_HW_POWER_ENB_IDX, | 126 | FM_HW_POWER_ENB_IDX, |
127 | 127 | ||
128 | /* Low RSSI irq handler */ | 128 | /* Low RSSI irq handler */ |
129 | FM_LOW_RSSI_START_IDX, | 129 | FM_LOW_RSSI_START_IDX, |
130 | FM_AF_JUMP_SETPI_IDX, | 130 | FM_AF_JUMP_SETPI_IDX, |
131 | FM_AF_JUMP_HANDLE_SETPI_RESP_IDX, | 131 | FM_AF_JUMP_HANDLE_SETPI_RESP_IDX, |
132 | FM_AF_JUMP_SETPI_MASK_IDX, | 132 | FM_AF_JUMP_SETPI_MASK_IDX, |
133 | FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX, | 133 | FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX, |
134 | FM_AF_JUMP_SET_AF_FREQ_IDX, | 134 | FM_AF_JUMP_SET_AF_FREQ_IDX, |
135 | FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX, | 135 | FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX, |
136 | FM_AF_JUMP_ENABLE_INT_IDX, | 136 | FM_AF_JUMP_ENABLE_INT_IDX, |
137 | FM_AF_JUMP_ENABLE_INT_RESP_IDX, | 137 | FM_AF_JUMP_ENABLE_INT_RESP_IDX, |
138 | FM_AF_JUMP_START_AFJUMP_IDX, | 138 | FM_AF_JUMP_START_AFJUMP_IDX, |
139 | FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX, | 139 | FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX, |
140 | FM_AF_JUMP_RD_FREQ_IDX, | 140 | FM_AF_JUMP_RD_FREQ_IDX, |
141 | FM_AF_JUMP_RD_FREQ_RESP_IDX, | 141 | FM_AF_JUMP_RD_FREQ_RESP_IDX, |
142 | FM_LOW_RSSI_FINISH_IDX, | 142 | FM_LOW_RSSI_FINISH_IDX, |
143 | 143 | ||
144 | /* Interrupt process post action */ | 144 | /* Interrupt process post action */ |
145 | FM_SEND_INTMSK_CMD_IDX, | 145 | FM_SEND_INTMSK_CMD_IDX, |
146 | FM_HANDLE_INTMSK_CMD_RESP_IDX, | 146 | FM_HANDLE_INTMSK_CMD_RESP_IDX, |
147 | }; | 147 | }; |
148 | 148 | ||
149 | /* FM interrupt handler table */ | 149 | /* FM interrupt handler table */ |
150 | static int_handler_prototype int_handler_table[] = { | 150 | static int_handler_prototype int_handler_table[] = { |
151 | fm_irq_send_flag_getcmd, | 151 | fm_irq_send_flag_getcmd, |
152 | fm_irq_handle_flag_getcmd_resp, | 152 | fm_irq_handle_flag_getcmd_resp, |
153 | fm_irq_handle_hw_malfunction, | 153 | fm_irq_handle_hw_malfunction, |
154 | fm_irq_handle_rds_start, /* RDS threshold reached irq handler */ | 154 | fm_irq_handle_rds_start, /* RDS threshold reached irq handler */ |
155 | fm_irq_send_rdsdata_getcmd, | 155 | fm_irq_send_rdsdata_getcmd, |
156 | fm_irq_handle_rdsdata_getcmd_resp, | 156 | fm_irq_handle_rdsdata_getcmd_resp, |
157 | fm_irq_handle_rds_finish, | 157 | fm_irq_handle_rds_finish, |
158 | fm_irq_handle_tune_op_ended, | 158 | fm_irq_handle_tune_op_ended, |
159 | fm_irq_handle_power_enb, /* TX power enable irq handler */ | 159 | fm_irq_handle_power_enb, /* TX power enable irq handler */ |
160 | fm_irq_handle_low_rssi_start, | 160 | fm_irq_handle_low_rssi_start, |
161 | fm_irq_afjump_set_pi, | 161 | fm_irq_afjump_set_pi, |
162 | fm_irq_handle_set_pi_resp, | 162 | fm_irq_handle_set_pi_resp, |
163 | fm_irq_afjump_set_pimask, | 163 | fm_irq_afjump_set_pimask, |
164 | fm_irq_handle_set_pimask_resp, | 164 | fm_irq_handle_set_pimask_resp, |
165 | fm_irq_afjump_setfreq, | 165 | fm_irq_afjump_setfreq, |
166 | fm_irq_handle_setfreq_resp, | 166 | fm_irq_handle_setfreq_resp, |
167 | fm_irq_afjump_enableint, | 167 | fm_irq_afjump_enableint, |
168 | fm_irq_afjump_enableint_resp, | 168 | fm_irq_afjump_enableint_resp, |
169 | fm_irq_start_afjump, | 169 | fm_irq_start_afjump, |
170 | fm_irq_handle_start_afjump_resp, | 170 | fm_irq_handle_start_afjump_resp, |
171 | fm_irq_afjump_rd_freq, | 171 | fm_irq_afjump_rd_freq, |
172 | fm_irq_afjump_rd_freq_resp, | 172 | fm_irq_afjump_rd_freq_resp, |
173 | fm_irq_handle_low_rssi_finish, | 173 | fm_irq_handle_low_rssi_finish, |
174 | fm_irq_send_intmsk_cmd, /* Interrupt process post action */ | 174 | fm_irq_send_intmsk_cmd, /* Interrupt process post action */ |
175 | fm_irq_handle_intmsk_cmd_resp | 175 | fm_irq_handle_intmsk_cmd_resp |
176 | }; | 176 | }; |
177 | 177 | ||
178 | long (*g_st_write) (struct sk_buff *skb); | 178 | long (*g_st_write) (struct sk_buff *skb); |
179 | static struct completion wait_for_fmdrv_reg_comp; | 179 | static struct completion wait_for_fmdrv_reg_comp; |
180 | 180 | ||
181 | static inline void fm_irq_call(struct fmdev *fmdev) | 181 | static inline void fm_irq_call(struct fmdev *fmdev) |
182 | { | 182 | { |
183 | fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); | 183 | fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); |
184 | } | 184 | } |
185 | 185 | ||
186 | /* Continue next function in interrupt handler table */ | 186 | /* Continue next function in interrupt handler table */ |
187 | static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage) | 187 | static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage) |
188 | { | 188 | { |
189 | fmdev->irq_info.stage = stage; | 189 | fmdev->irq_info.stage = stage; |
190 | fm_irq_call(fmdev); | 190 | fm_irq_call(fmdev); |
191 | } | 191 | } |
192 | 192 | ||
193 | static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage) | 193 | static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage) |
194 | { | 194 | { |
195 | fmdev->irq_info.stage = stage; | 195 | fmdev->irq_info.stage = stage; |
196 | mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); | 196 | mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); |
197 | } | 197 | } |
198 | 198 | ||
199 | #ifdef FM_DUMP_TXRX_PKT | 199 | #ifdef FM_DUMP_TXRX_PKT |
200 | /* To dump outgoing FM Channel-8 packets */ | 200 | /* To dump outgoing FM Channel-8 packets */ |
201 | inline void dump_tx_skb_data(struct sk_buff *skb) | 201 | inline void dump_tx_skb_data(struct sk_buff *skb) |
202 | { | 202 | { |
203 | int len, len_org; | 203 | int len, len_org; |
204 | u8 index; | 204 | u8 index; |
205 | struct fm_cmd_msg_hdr *cmd_hdr; | 205 | struct fm_cmd_msg_hdr *cmd_hdr; |
206 | 206 | ||
207 | cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data; | 207 | cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data; |
208 | printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x", | 208 | printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x", |
209 | fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr, | 209 | fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr, |
210 | cmd_hdr->len, cmd_hdr->op, | 210 | cmd_hdr->len, cmd_hdr->op, |
211 | cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen); | 211 | cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen); |
212 | 212 | ||
213 | len_org = skb->len - FM_CMD_MSG_HDR_SIZE; | 213 | len_org = skb->len - FM_CMD_MSG_HDR_SIZE; |
214 | if (len_org > 0) { | 214 | if (len_org > 0) { |
215 | printk("\n data(%d): ", cmd_hdr->dlen); | 215 | printk("\n data(%d): ", cmd_hdr->dlen); |
216 | len = min(len_org, 14); | 216 | len = min(len_org, 14); |
217 | for (index = 0; index < len; index++) | 217 | for (index = 0; index < len; index++) |
218 | printk("%x ", | 218 | printk("%x ", |
219 | skb->data[FM_CMD_MSG_HDR_SIZE + index]); | 219 | skb->data[FM_CMD_MSG_HDR_SIZE + index]); |
220 | printk("%s", (len_org > 14) ? ".." : ""); | 220 | printk("%s", (len_org > 14) ? ".." : ""); |
221 | } | 221 | } |
222 | printk("\n"); | 222 | printk("\n"); |
223 | } | 223 | } |
224 | 224 | ||
225 | /* To dump incoming FM Channel-8 packets */ | 225 | /* To dump incoming FM Channel-8 packets */ |
226 | inline void dump_rx_skb_data(struct sk_buff *skb) | 226 | inline void dump_rx_skb_data(struct sk_buff *skb) |
227 | { | 227 | { |
228 | int len, len_org; | 228 | int len, len_org; |
229 | u8 index; | 229 | u8 index; |
230 | struct fm_event_msg_hdr *evt_hdr; | 230 | struct fm_event_msg_hdr *evt_hdr; |
231 | 231 | ||
232 | evt_hdr = (struct fm_event_msg_hdr *)skb->data; | 232 | evt_hdr = (struct fm_event_msg_hdr *)skb->data; |
233 | printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x " | 233 | printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x " |
234 | "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len, | 234 | "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len, |
235 | evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op, | 235 | evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op, |
236 | (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen); | 236 | (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen); |
237 | 237 | ||
238 | len_org = skb->len - FM_EVT_MSG_HDR_SIZE; | 238 | len_org = skb->len - FM_EVT_MSG_HDR_SIZE; |
239 | if (len_org > 0) { | 239 | if (len_org > 0) { |
240 | printk("\n data(%d): ", evt_hdr->dlen); | 240 | printk("\n data(%d): ", evt_hdr->dlen); |
241 | len = min(len_org, 14); | 241 | len = min(len_org, 14); |
242 | for (index = 0; index < len; index++) | 242 | for (index = 0; index < len; index++) |
243 | printk("%x ", | 243 | printk("%x ", |
244 | skb->data[FM_EVT_MSG_HDR_SIZE + index]); | 244 | skb->data[FM_EVT_MSG_HDR_SIZE + index]); |
245 | printk("%s", (len_org > 14) ? ".." : ""); | 245 | printk("%s", (len_org > 14) ? ".." : ""); |
246 | } | 246 | } |
247 | printk("\n"); | 247 | printk("\n"); |
248 | } | 248 | } |
249 | #endif | 249 | #endif |
250 | 250 | ||
251 | void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set) | 251 | void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set) |
252 | { | 252 | { |
253 | fmdev->rx.region = region_configs[region_to_set]; | 253 | fmdev->rx.region = region_configs[region_to_set]; |
254 | } | 254 | } |
255 | 255 | ||
256 | /* | 256 | /* |
257 | * FM common sub-module will schedule this tasklet whenever it receives | 257 | * FM common sub-module will schedule this tasklet whenever it receives |
258 | * FM packet from ST driver. | 258 | * FM packet from ST driver. |
259 | */ | 259 | */ |
260 | static void recv_tasklet(unsigned long arg) | 260 | static void recv_tasklet(unsigned long arg) |
261 | { | 261 | { |
262 | struct fmdev *fmdev; | 262 | struct fmdev *fmdev; |
263 | struct fm_irq *irq_info; | 263 | struct fm_irq *irq_info; |
264 | struct fm_event_msg_hdr *evt_hdr; | 264 | struct fm_event_msg_hdr *evt_hdr; |
265 | struct sk_buff *skb; | 265 | struct sk_buff *skb; |
266 | u8 num_fm_hci_cmds; | 266 | u8 num_fm_hci_cmds; |
267 | unsigned long flags; | 267 | unsigned long flags; |
268 | 268 | ||
269 | fmdev = (struct fmdev *)arg; | 269 | fmdev = (struct fmdev *)arg; |
270 | irq_info = &fmdev->irq_info; | 270 | irq_info = &fmdev->irq_info; |
271 | /* Process all packets in the RX queue */ | 271 | /* Process all packets in the RX queue */ |
272 | while ((skb = skb_dequeue(&fmdev->rx_q))) { | 272 | while ((skb = skb_dequeue(&fmdev->rx_q))) { |
273 | if (skb->len < sizeof(struct fm_event_msg_hdr)) { | 273 | if (skb->len < sizeof(struct fm_event_msg_hdr)) { |
274 | fmerr("skb(%p) has only %d bytes, " | 274 | fmerr("skb(%p) has only %d bytes, " |
275 | "at least need %zu bytes to decode\n", skb, | 275 | "at least need %zu bytes to decode\n", skb, |
276 | skb->len, sizeof(struct fm_event_msg_hdr)); | 276 | skb->len, sizeof(struct fm_event_msg_hdr)); |
277 | kfree_skb(skb); | 277 | kfree_skb(skb); |
278 | continue; | 278 | continue; |
279 | } | 279 | } |
280 | 280 | ||
281 | evt_hdr = (void *)skb->data; | 281 | evt_hdr = (void *)skb->data; |
282 | num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds; | 282 | num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds; |
283 | 283 | ||
284 | /* FM interrupt packet? */ | 284 | /* FM interrupt packet? */ |
285 | if (evt_hdr->op == FM_INTERRUPT) { | 285 | if (evt_hdr->op == FM_INTERRUPT) { |
286 | /* FM interrupt handler started already? */ | 286 | /* FM interrupt handler started already? */ |
287 | if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { | 287 | if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { |
288 | set_bit(FM_INTTASK_RUNNING, &fmdev->flag); | 288 | set_bit(FM_INTTASK_RUNNING, &fmdev->flag); |
289 | if (irq_info->stage != 0) { | 289 | if (irq_info->stage != 0) { |
290 | fmerr("Inval stage resetting to zero\n"); | 290 | fmerr("Inval stage resetting to zero\n"); |
291 | irq_info->stage = 0; | 291 | irq_info->stage = 0; |
292 | } | 292 | } |
293 | 293 | ||
294 | /* | 294 | /* |
295 | * Execute first function in interrupt handler | 295 | * Execute first function in interrupt handler |
296 | * table. | 296 | * table. |
297 | */ | 297 | */ |
298 | irq_info->handlers[irq_info->stage](fmdev); | 298 | irq_info->handlers[irq_info->stage](fmdev); |
299 | } else { | 299 | } else { |
300 | set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag); | 300 | set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag); |
301 | } | 301 | } |
302 | kfree_skb(skb); | 302 | kfree_skb(skb); |
303 | } | 303 | } |
304 | /* Anyone waiting for this with completion handler? */ | 304 | /* Anyone waiting for this with completion handler? */ |
305 | else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) { | 305 | else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) { |
306 | 306 | ||
307 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); | 307 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); |
308 | fmdev->resp_skb = skb; | 308 | fmdev->resp_skb = skb; |
309 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); | 309 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); |
310 | complete(fmdev->resp_comp); | 310 | complete(fmdev->resp_comp); |
311 | 311 | ||
312 | fmdev->resp_comp = NULL; | 312 | fmdev->resp_comp = NULL; |
313 | atomic_set(&fmdev->tx_cnt, 1); | 313 | atomic_set(&fmdev->tx_cnt, 1); |
314 | } | 314 | } |
315 | /* Is this for interrupt handler? */ | 315 | /* Is this for interrupt handler? */ |
316 | else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) { | 316 | else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) { |
317 | if (fmdev->resp_skb != NULL) | 317 | if (fmdev->resp_skb != NULL) |
318 | fmerr("Response SKB ptr not NULL\n"); | 318 | fmerr("Response SKB ptr not NULL\n"); |
319 | 319 | ||
320 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); | 320 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); |
321 | fmdev->resp_skb = skb; | 321 | fmdev->resp_skb = skb; |
322 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); | 322 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); |
323 | 323 | ||
324 | /* Execute interrupt handler where state index points */ | 324 | /* Execute interrupt handler where state index points */ |
325 | irq_info->handlers[irq_info->stage](fmdev); | 325 | irq_info->handlers[irq_info->stage](fmdev); |
326 | 326 | ||
327 | kfree_skb(skb); | 327 | kfree_skb(skb); |
328 | atomic_set(&fmdev->tx_cnt, 1); | 328 | atomic_set(&fmdev->tx_cnt, 1); |
329 | } else { | 329 | } else { |
330 | fmerr("Nobody claimed SKB(%p),purging\n", skb); | 330 | fmerr("Nobody claimed SKB(%p),purging\n", skb); |
331 | } | 331 | } |
332 | 332 | ||
333 | /* | 333 | /* |
334 | * Check flow control field. If Num_FM_HCI_Commands field is | 334 | * Check flow control field. If Num_FM_HCI_Commands field is |
335 | * not zero, schedule FM TX tasklet. | 335 | * not zero, schedule FM TX tasklet. |
336 | */ | 336 | */ |
337 | if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) | 337 | if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) |
338 | if (!skb_queue_empty(&fmdev->tx_q)) | 338 | if (!skb_queue_empty(&fmdev->tx_q)) |
339 | tasklet_schedule(&fmdev->tx_task); | 339 | tasklet_schedule(&fmdev->tx_task); |
340 | } | 340 | } |
341 | } | 341 | } |
342 | 342 | ||
343 | /* FM send tasklet: is scheduled when FM packet has to be sent to chip */ | 343 | /* FM send tasklet: is scheduled when FM packet has to be sent to chip */ |
344 | static void send_tasklet(unsigned long arg) | 344 | static void send_tasklet(unsigned long arg) |
345 | { | 345 | { |
346 | struct fmdev *fmdev; | 346 | struct fmdev *fmdev; |
347 | struct sk_buff *skb; | 347 | struct sk_buff *skb; |
348 | int len; | 348 | int len; |
349 | 349 | ||
350 | fmdev = (struct fmdev *)arg; | 350 | fmdev = (struct fmdev *)arg; |
351 | 351 | ||
352 | if (!atomic_read(&fmdev->tx_cnt)) | 352 | if (!atomic_read(&fmdev->tx_cnt)) |
353 | return; | 353 | return; |
354 | 354 | ||
355 | /* Check, is there any timeout happenned to last transmitted packet */ | 355 | /* Check, is there any timeout happenned to last transmitted packet */ |
356 | if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) { | 356 | if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) { |
357 | fmerr("TX timeout occurred\n"); | 357 | fmerr("TX timeout occurred\n"); |
358 | atomic_set(&fmdev->tx_cnt, 1); | 358 | atomic_set(&fmdev->tx_cnt, 1); |
359 | } | 359 | } |
360 | 360 | ||
361 | /* Send queued FM TX packets */ | 361 | /* Send queued FM TX packets */ |
362 | skb = skb_dequeue(&fmdev->tx_q); | 362 | skb = skb_dequeue(&fmdev->tx_q); |
363 | if (!skb) | 363 | if (!skb) |
364 | return; | 364 | return; |
365 | 365 | ||
366 | atomic_dec(&fmdev->tx_cnt); | 366 | atomic_dec(&fmdev->tx_cnt); |
367 | fmdev->pre_op = fm_cb(skb)->fm_op; | 367 | fmdev->pre_op = fm_cb(skb)->fm_op; |
368 | 368 | ||
369 | if (fmdev->resp_comp != NULL) | 369 | if (fmdev->resp_comp != NULL) |
370 | fmerr("Response completion handler is not NULL\n"); | 370 | fmerr("Response completion handler is not NULL\n"); |
371 | 371 | ||
372 | fmdev->resp_comp = fm_cb(skb)->completion; | 372 | fmdev->resp_comp = fm_cb(skb)->completion; |
373 | 373 | ||
374 | /* Write FM packet to ST driver */ | 374 | /* Write FM packet to ST driver */ |
375 | len = g_st_write(skb); | 375 | len = g_st_write(skb); |
376 | if (len < 0) { | 376 | if (len < 0) { |
377 | kfree_skb(skb); | 377 | kfree_skb(skb); |
378 | fmdev->resp_comp = NULL; | 378 | fmdev->resp_comp = NULL; |
379 | fmerr("TX tasklet failed to send skb(%p)\n", skb); | 379 | fmerr("TX tasklet failed to send skb(%p)\n", skb); |
380 | atomic_set(&fmdev->tx_cnt, 1); | 380 | atomic_set(&fmdev->tx_cnt, 1); |
381 | } else { | 381 | } else { |
382 | fmdev->last_tx_jiffies = jiffies; | 382 | fmdev->last_tx_jiffies = jiffies; |
383 | } | 383 | } |
384 | } | 384 | } |
385 | 385 | ||
386 | /* | 386 | /* |
387 | * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for | 387 | * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for |
388 | * transmission | 388 | * transmission |
389 | */ | 389 | */ |
390 | static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, | 390 | static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, |
391 | int payload_len, struct completion *wait_completion) | 391 | int payload_len, struct completion *wait_completion) |
392 | { | 392 | { |
393 | struct sk_buff *skb; | 393 | struct sk_buff *skb; |
394 | struct fm_cmd_msg_hdr *hdr; | 394 | struct fm_cmd_msg_hdr *hdr; |
395 | int size; | 395 | int size; |
396 | 396 | ||
397 | if (fm_op >= FM_INTERRUPT) { | 397 | if (fm_op >= FM_INTERRUPT) { |
398 | fmerr("Invalid fm opcode - %d\n", fm_op); | 398 | fmerr("Invalid fm opcode - %d\n", fm_op); |
399 | return -EINVAL; | 399 | return -EINVAL; |
400 | } | 400 | } |
401 | if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) { | 401 | if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) { |
402 | fmerr("Payload data is NULL during fw download\n"); | 402 | fmerr("Payload data is NULL during fw download\n"); |
403 | return -EINVAL; | 403 | return -EINVAL; |
404 | } | 404 | } |
405 | if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag)) | 405 | if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag)) |
406 | size = | 406 | size = |
407 | FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len); | 407 | FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len); |
408 | else | 408 | else |
409 | size = payload_len; | 409 | size = payload_len; |
410 | 410 | ||
411 | skb = alloc_skb(size, GFP_ATOMIC); | 411 | skb = alloc_skb(size, GFP_ATOMIC); |
412 | if (!skb) { | 412 | if (!skb) { |
413 | fmerr("No memory to create new SKB\n"); | 413 | fmerr("No memory to create new SKB\n"); |
414 | return -ENOMEM; | 414 | return -ENOMEM; |
415 | } | 415 | } |
416 | /* | 416 | /* |
417 | * Don't fill FM header info for the commands which come from | 417 | * Don't fill FM header info for the commands which come from |
418 | * FM firmware file. | 418 | * FM firmware file. |
419 | */ | 419 | */ |
420 | if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) || | 420 | if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) || |
421 | test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { | 421 | test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { |
422 | /* Fill command header info */ | 422 | /* Fill command header info */ |
423 | hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE); | 423 | hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE); |
424 | hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */ | 424 | hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */ |
425 | 425 | ||
426 | /* 3 (fm_opcode,rd_wr,dlen) + payload len) */ | 426 | /* 3 (fm_opcode,rd_wr,dlen) + payload len) */ |
427 | hdr->len = ((payload == NULL) ? 0 : payload_len) + 3; | 427 | hdr->len = ((payload == NULL) ? 0 : payload_len) + 3; |
428 | 428 | ||
429 | /* FM opcode */ | 429 | /* FM opcode */ |
430 | hdr->op = fm_op; | 430 | hdr->op = fm_op; |
431 | 431 | ||
432 | /* read/write type */ | 432 | /* read/write type */ |
433 | hdr->rd_wr = type; | 433 | hdr->rd_wr = type; |
434 | hdr->dlen = payload_len; | 434 | hdr->dlen = payload_len; |
435 | fm_cb(skb)->fm_op = fm_op; | 435 | fm_cb(skb)->fm_op = fm_op; |
436 | 436 | ||
437 | /* | 437 | /* |
438 | * If firmware download has finished and the command is | 438 | * If firmware download has finished and the command is |
439 | * not a read command then payload is != NULL - a write | 439 | * not a read command then payload is != NULL - a write |
440 | * command with u16 payload - convert to be16 | 440 | * command with u16 payload - convert to be16 |
441 | */ | 441 | */ |
442 | if (payload != NULL) | 442 | if (payload != NULL) |
443 | *(u16 *)payload = cpu_to_be16(*(u16 *)payload); | 443 | *(u16 *)payload = cpu_to_be16(*(u16 *)payload); |
444 | 444 | ||
445 | } else if (payload != NULL) { | 445 | } else if (payload != NULL) { |
446 | fm_cb(skb)->fm_op = *((u8 *)payload + 2); | 446 | fm_cb(skb)->fm_op = *((u8 *)payload + 2); |
447 | } | 447 | } |
448 | if (payload != NULL) | 448 | if (payload != NULL) |
449 | memcpy(skb_put(skb, payload_len), payload, payload_len); | 449 | memcpy(skb_put(skb, payload_len), payload, payload_len); |
450 | 450 | ||
451 | fm_cb(skb)->completion = wait_completion; | 451 | fm_cb(skb)->completion = wait_completion; |
452 | skb_queue_tail(&fmdev->tx_q, skb); | 452 | skb_queue_tail(&fmdev->tx_q, skb); |
453 | tasklet_schedule(&fmdev->tx_task); | 453 | tasklet_schedule(&fmdev->tx_task); |
454 | 454 | ||
455 | return 0; | 455 | return 0; |
456 | } | 456 | } |
457 | 457 | ||
458 | /* Sends FM Channel-8 command to the chip and waits for the response */ | 458 | /* Sends FM Channel-8 command to the chip and waits for the response */ |
459 | u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, | 459 | u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, |
460 | unsigned int payload_len, void *response, int *response_len) | 460 | unsigned int payload_len, void *response, int *response_len) |
461 | { | 461 | { |
462 | struct sk_buff *skb; | 462 | struct sk_buff *skb; |
463 | struct fm_event_msg_hdr *evt_hdr; | 463 | struct fm_event_msg_hdr *evt_hdr; |
464 | unsigned long flags; | 464 | unsigned long flags; |
465 | u32 ret; | 465 | u32 ret; |
466 | 466 | ||
467 | init_completion(&fmdev->maintask_comp); | 467 | init_completion(&fmdev->maintask_comp); |
468 | ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, | 468 | ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, |
469 | &fmdev->maintask_comp); | 469 | &fmdev->maintask_comp); |
470 | if (ret) | 470 | if (ret) |
471 | return ret; | 471 | return ret; |
472 | 472 | ||
473 | ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); | 473 | ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); |
474 | if (!ret) { | 474 | if (!ret) { |
475 | fmerr("Timeout(%d sec),didn't get reg" | 475 | fmerr("Timeout(%d sec),didn't get reg" |
476 | "completion signal from RX tasklet\n", | 476 | "completion signal from RX tasklet\n", |
477 | jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); | 477 | jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); |
478 | return -ETIMEDOUT; | 478 | return -ETIMEDOUT; |
479 | } | 479 | } |
480 | if (!fmdev->resp_skb) { | 480 | if (!fmdev->resp_skb) { |
481 | fmerr("Reponse SKB is missing\n"); | 481 | fmerr("Reponse SKB is missing\n"); |
482 | return -EFAULT; | 482 | return -EFAULT; |
483 | } | 483 | } |
484 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); | 484 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); |
485 | skb = fmdev->resp_skb; | 485 | skb = fmdev->resp_skb; |
486 | fmdev->resp_skb = NULL; | 486 | fmdev->resp_skb = NULL; |
487 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); | 487 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); |
488 | 488 | ||
489 | evt_hdr = (void *)skb->data; | 489 | evt_hdr = (void *)skb->data; |
490 | if (evt_hdr->status != 0) { | 490 | if (evt_hdr->status != 0) { |
491 | fmerr("Received event pkt status(%d) is not zero\n", | 491 | fmerr("Received event pkt status(%d) is not zero\n", |
492 | evt_hdr->status); | 492 | evt_hdr->status); |
493 | kfree_skb(skb); | 493 | kfree_skb(skb); |
494 | return -EIO; | 494 | return -EIO; |
495 | } | 495 | } |
496 | /* Send response data to caller */ | 496 | /* Send response data to caller */ |
497 | if (response != NULL && response_len != NULL && evt_hdr->dlen) { | 497 | if (response != NULL && response_len != NULL && evt_hdr->dlen) { |
498 | /* Skip header info and copy only response data */ | 498 | /* Skip header info and copy only response data */ |
499 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); | 499 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); |
500 | memcpy(response, skb->data, evt_hdr->dlen); | 500 | memcpy(response, skb->data, evt_hdr->dlen); |
501 | *response_len = evt_hdr->dlen; | 501 | *response_len = evt_hdr->dlen; |
502 | } else if (response_len != NULL && evt_hdr->dlen == 0) { | 502 | } else if (response_len != NULL && evt_hdr->dlen == 0) { |
503 | *response_len = 0; | 503 | *response_len = 0; |
504 | } | 504 | } |
505 | kfree_skb(skb); | 505 | kfree_skb(skb); |
506 | 506 | ||
507 | return 0; | 507 | return 0; |
508 | } | 508 | } |
509 | 509 | ||
510 | /* --- Helper functions used in FM interrupt handlers ---*/ | 510 | /* --- Helper functions used in FM interrupt handlers ---*/ |
511 | static inline u32 check_cmdresp_status(struct fmdev *fmdev, | 511 | static inline u32 check_cmdresp_status(struct fmdev *fmdev, |
512 | struct sk_buff **skb) | 512 | struct sk_buff **skb) |
513 | { | 513 | { |
514 | struct fm_event_msg_hdr *fm_evt_hdr; | 514 | struct fm_event_msg_hdr *fm_evt_hdr; |
515 | unsigned long flags; | 515 | unsigned long flags; |
516 | 516 | ||
517 | del_timer(&fmdev->irq_info.timer); | 517 | del_timer(&fmdev->irq_info.timer); |
518 | 518 | ||
519 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); | 519 | spin_lock_irqsave(&fmdev->resp_skb_lock, flags); |
520 | *skb = fmdev->resp_skb; | 520 | *skb = fmdev->resp_skb; |
521 | fmdev->resp_skb = NULL; | 521 | fmdev->resp_skb = NULL; |
522 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); | 522 | spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); |
523 | 523 | ||
524 | fm_evt_hdr = (void *)(*skb)->data; | 524 | fm_evt_hdr = (void *)(*skb)->data; |
525 | if (fm_evt_hdr->status != 0) { | 525 | if (fm_evt_hdr->status != 0) { |
526 | fmerr("irq: opcode %x response status is not zero " | 526 | fmerr("irq: opcode %x response status is not zero " |
527 | "Initiating irq recovery process\n", | 527 | "Initiating irq recovery process\n", |
528 | fm_evt_hdr->op); | 528 | fm_evt_hdr->op); |
529 | 529 | ||
530 | mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); | 530 | mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); |
531 | return -1; | 531 | return -1; |
532 | } | 532 | } |
533 | 533 | ||
534 | return 0; | 534 | return 0; |
535 | } | 535 | } |
536 | 536 | ||
537 | static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage) | 537 | static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage) |
538 | { | 538 | { |
539 | struct sk_buff *skb; | 539 | struct sk_buff *skb; |
540 | 540 | ||
541 | if (!check_cmdresp_status(fmdev, &skb)) | 541 | if (!check_cmdresp_status(fmdev, &skb)) |
542 | fm_irq_call_stage(fmdev, stage); | 542 | fm_irq_call_stage(fmdev, stage); |
543 | } | 543 | } |
544 | 544 | ||
545 | /* | 545 | /* |
546 | * Interrupt process timeout handler. | 546 | * Interrupt process timeout handler. |
547 | * One of the irq handler did not get proper response from the chip. So take | 547 | * One of the irq handler did not get proper response from the chip. So take |
548 | * recovery action here. FM interrupts are disabled in the beginning of | 548 | * recovery action here. FM interrupts are disabled in the beginning of |
549 | * interrupt process. Therefore reset stage index to re-enable default | 549 | * interrupt process. Therefore reset stage index to re-enable default |
550 | * interrupts. So that next interrupt will be processed as usual. | 550 | * interrupts. So that next interrupt will be processed as usual. |
551 | */ | 551 | */ |
552 | static void int_timeout_handler(unsigned long data) | 552 | static void int_timeout_handler(unsigned long data) |
553 | { | 553 | { |
554 | struct fmdev *fmdev; | 554 | struct fmdev *fmdev; |
555 | struct fm_irq *fmirq; | 555 | struct fm_irq *fmirq; |
556 | 556 | ||
557 | fmdbg("irq: timeout,trying to re-enable fm interrupts\n"); | 557 | fmdbg("irq: timeout,trying to re-enable fm interrupts\n"); |
558 | fmdev = (struct fmdev *)data; | 558 | fmdev = (struct fmdev *)data; |
559 | fmirq = &fmdev->irq_info; | 559 | fmirq = &fmdev->irq_info; |
560 | fmirq->retry++; | 560 | fmirq->retry++; |
561 | 561 | ||
562 | if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) { | 562 | if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) { |
563 | /* Stop recovery action (interrupt reenable process) and | 563 | /* Stop recovery action (interrupt reenable process) and |
564 | * reset stage index & retry count values */ | 564 | * reset stage index & retry count values */ |
565 | fmirq->stage = 0; | 565 | fmirq->stage = 0; |
566 | fmirq->retry = 0; | 566 | fmirq->retry = 0; |
567 | fmerr("Recovery action failed during" | 567 | fmerr("Recovery action failed during" |
568 | "irq processing, max retry reached\n"); | 568 | "irq processing, max retry reached\n"); |
569 | return; | 569 | return; |
570 | } | 570 | } |
571 | fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); | 571 | fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); |
572 | } | 572 | } |
573 | 573 | ||
574 | /* --------- FM interrupt handlers ------------*/ | 574 | /* --------- FM interrupt handlers ------------*/ |
575 | static void fm_irq_send_flag_getcmd(struct fmdev *fmdev) | 575 | static void fm_irq_send_flag_getcmd(struct fmdev *fmdev) |
576 | { | 576 | { |
577 | u16 flag; | 577 | u16 flag; |
578 | 578 | ||
579 | /* Send FLAG_GET command , to know the source of interrupt */ | 579 | /* Send FLAG_GET command , to know the source of interrupt */ |
580 | if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL)) | 580 | if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL)) |
581 | fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX); | 581 | fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX); |
582 | } | 582 | } |
583 | 583 | ||
584 | static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) | 584 | static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) |
585 | { | 585 | { |
586 | struct sk_buff *skb; | 586 | struct sk_buff *skb; |
587 | struct fm_event_msg_hdr *fm_evt_hdr; | 587 | struct fm_event_msg_hdr *fm_evt_hdr; |
588 | 588 | ||
589 | if (check_cmdresp_status(fmdev, &skb)) | 589 | if (check_cmdresp_status(fmdev, &skb)) |
590 | return; | 590 | return; |
591 | 591 | ||
592 | fm_evt_hdr = (void *)skb->data; | 592 | fm_evt_hdr = (void *)skb->data; |
593 | 593 | ||
594 | /* Skip header info and copy only response data */ | 594 | /* Skip header info and copy only response data */ |
595 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); | 595 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); |
596 | memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen); | 596 | memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen); |
597 | 597 | ||
598 | fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag); | 598 | fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag); |
599 | fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag); | 599 | fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag); |
600 | 600 | ||
601 | /* Continue next function in interrupt handler table */ | 601 | /* Continue next function in interrupt handler table */ |
602 | fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX); | 602 | fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX); |
603 | } | 603 | } |
604 | 604 | ||
605 | static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev) | 605 | static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev) |
606 | { | 606 | { |
607 | if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask) | 607 | if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask) |
608 | fmerr("irq: HW MAL int received - do nothing\n"); | 608 | fmerr("irq: HW MAL int received - do nothing\n"); |
609 | 609 | ||
610 | /* Continue next function in interrupt handler table */ | 610 | /* Continue next function in interrupt handler table */ |
611 | fm_irq_call_stage(fmdev, FM_RDS_START_IDX); | 611 | fm_irq_call_stage(fmdev, FM_RDS_START_IDX); |
612 | } | 612 | } |
613 | 613 | ||
614 | static void fm_irq_handle_rds_start(struct fmdev *fmdev) | 614 | static void fm_irq_handle_rds_start(struct fmdev *fmdev) |
615 | { | 615 | { |
616 | if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) { | 616 | if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) { |
617 | fmdbg("irq: rds threshold reached\n"); | 617 | fmdbg("irq: rds threshold reached\n"); |
618 | fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX; | 618 | fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX; |
619 | } else { | 619 | } else { |
620 | /* Continue next function in interrupt handler table */ | 620 | /* Continue next function in interrupt handler table */ |
621 | fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX; | 621 | fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX; |
622 | } | 622 | } |
623 | 623 | ||
624 | fm_irq_call(fmdev); | 624 | fm_irq_call(fmdev); |
625 | } | 625 | } |
626 | 626 | ||
627 | static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev) | 627 | static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev) |
628 | { | 628 | { |
629 | /* Send the command to read RDS data from the chip */ | 629 | /* Send the command to read RDS data from the chip */ |
630 | if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL, | 630 | if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL, |
631 | (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL)) | 631 | (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL)) |
632 | fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX); | 632 | fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX); |
633 | } | 633 | } |
634 | 634 | ||
635 | /* Keeps track of current RX channel AF (Alternate Frequency) */ | 635 | /* Keeps track of current RX channel AF (Alternate Frequency) */ |
636 | static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) | 636 | static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) |
637 | { | 637 | { |
638 | struct tuned_station_info *stat_info = &fmdev->rx.stat_info; | 638 | struct tuned_station_info *stat_info = &fmdev->rx.stat_info; |
639 | u8 reg_idx = fmdev->rx.region.fm_band; | 639 | u8 reg_idx = fmdev->rx.region.fm_band; |
640 | u8 index; | 640 | u8 index; |
641 | u32 freq; | 641 | u32 freq; |
642 | 642 | ||
643 | /* First AF indicates the number of AF follows. Reset the list */ | 643 | /* First AF indicates the number of AF follows. Reset the list */ |
644 | if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) { | 644 | if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) { |
645 | fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1); | 645 | fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1); |
646 | fmdev->rx.stat_info.afcache_size = 0; | 646 | fmdev->rx.stat_info.afcache_size = 0; |
647 | fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max); | 647 | fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max); |
648 | return; | 648 | return; |
649 | } | 649 | } |
650 | 650 | ||
651 | if (af < FM_RDS_MIN_AF) | 651 | if (af < FM_RDS_MIN_AF) |
652 | return; | 652 | return; |
653 | if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF) | 653 | if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF) |
654 | return; | 654 | return; |
655 | if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN) | 655 | if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN) |
656 | return; | 656 | return; |
657 | 657 | ||
658 | freq = fmdev->rx.region.bot_freq + (af * 100); | 658 | freq = fmdev->rx.region.bot_freq + (af * 100); |
659 | if (freq == fmdev->rx.freq) { | 659 | if (freq == fmdev->rx.freq) { |
660 | fmdbg("Current freq(%d) is matching with received AF(%d)\n", | 660 | fmdbg("Current freq(%d) is matching with received AF(%d)\n", |
661 | fmdev->rx.freq, freq); | 661 | fmdev->rx.freq, freq); |
662 | return; | 662 | return; |
663 | } | 663 | } |
664 | /* Do check in AF cache */ | 664 | /* Do check in AF cache */ |
665 | for (index = 0; index < stat_info->afcache_size; index++) { | 665 | for (index = 0; index < stat_info->afcache_size; index++) { |
666 | if (stat_info->af_cache[index] == freq) | 666 | if (stat_info->af_cache[index] == freq) |
667 | break; | 667 | break; |
668 | } | 668 | } |
669 | /* Reached the limit of the list - ignore the next AF */ | 669 | /* Reached the limit of the list - ignore the next AF */ |
670 | if (index == stat_info->af_list_max) { | 670 | if (index == stat_info->af_list_max) { |
671 | fmdbg("AF cache is full\n"); | 671 | fmdbg("AF cache is full\n"); |
672 | return; | 672 | return; |
673 | } | 673 | } |
674 | /* | 674 | /* |
675 | * If we reached the end of the list then this AF is not | 675 | * If we reached the end of the list then this AF is not |
676 | * in the list - add it. | 676 | * in the list - add it. |
677 | */ | 677 | */ |
678 | if (index == stat_info->afcache_size) { | 678 | if (index == stat_info->afcache_size) { |
679 | fmdbg("Storing AF %d to cache index %d\n", freq, index); | 679 | fmdbg("Storing AF %d to cache index %d\n", freq, index); |
680 | stat_info->af_cache[index] = freq; | 680 | stat_info->af_cache[index] = freq; |
681 | stat_info->afcache_size++; | 681 | stat_info->afcache_size++; |
682 | } | 682 | } |
683 | } | 683 | } |
684 | 684 | ||
685 | /* | 685 | /* |
686 | * Converts RDS buffer data from big endian format | 686 | * Converts RDS buffer data from big endian format |
687 | * to little endian format. | 687 | * to little endian format. |
688 | */ | 688 | */ |
689 | static void fm_rdsparse_swapbytes(struct fmdev *fmdev, | 689 | static void fm_rdsparse_swapbytes(struct fmdev *fmdev, |
690 | struct fm_rdsdata_format *rds_format) | 690 | struct fm_rdsdata_format *rds_format) |
691 | { | 691 | { |
692 | u8 byte1; | 692 | u8 byte1; |
693 | u8 index = 0; | 693 | u8 index = 0; |
694 | u8 *rds_buff; | 694 | u8 *rds_buff; |
695 | 695 | ||
696 | /* | 696 | /* |
697 | * Since in Orca the 2 RDS Data bytes are in little endian and | 697 | * Since in Orca the 2 RDS Data bytes are in little endian and |
698 | * in Dolphin they are in big endian, the parsing of the RDS data | 698 | * in Dolphin they are in big endian, the parsing of the RDS data |
699 | * is chip dependent | 699 | * is chip dependent |
700 | */ | 700 | */ |
701 | if (fmdev->asci_id != 0x6350) { | 701 | if (fmdev->asci_id != 0x6350) { |
702 | rds_buff = &rds_format->data.groupdatabuff.buff[0]; | 702 | rds_buff = &rds_format->data.groupdatabuff.buff[0]; |
703 | while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { | 703 | while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { |
704 | byte1 = rds_buff[index]; | 704 | byte1 = rds_buff[index]; |
705 | rds_buff[index] = rds_buff[index + 1]; | 705 | rds_buff[index] = rds_buff[index + 1]; |
706 | rds_buff[index + 1] = byte1; | 706 | rds_buff[index + 1] = byte1; |
707 | index += 2; | 707 | index += 2; |
708 | } | 708 | } |
709 | } | 709 | } |
710 | } | 710 | } |
711 | 711 | ||
712 | static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) | 712 | static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) |
713 | { | 713 | { |
714 | struct sk_buff *skb; | 714 | struct sk_buff *skb; |
715 | struct fm_rdsdata_format rds_fmt; | 715 | struct fm_rdsdata_format rds_fmt; |
716 | struct fm_rds *rds = &fmdev->rx.rds; | 716 | struct fm_rds *rds = &fmdev->rx.rds; |
717 | unsigned long group_idx, flags; | 717 | unsigned long group_idx, flags; |
718 | u8 *rds_data, meta_data, tmpbuf[3]; | 718 | u8 *rds_data, meta_data, tmpbuf[3]; |
719 | u8 type, blk_idx; | 719 | u8 type, blk_idx; |
720 | u16 cur_picode; | 720 | u16 cur_picode; |
721 | u32 rds_len; | 721 | u32 rds_len; |
722 | 722 | ||
723 | if (check_cmdresp_status(fmdev, &skb)) | 723 | if (check_cmdresp_status(fmdev, &skb)) |
724 | return; | 724 | return; |
725 | 725 | ||
726 | /* Skip header info */ | 726 | /* Skip header info */ |
727 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); | 727 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); |
728 | rds_data = skb->data; | 728 | rds_data = skb->data; |
729 | rds_len = skb->len; | 729 | rds_len = skb->len; |
730 | 730 | ||
731 | /* Parse the RDS data */ | 731 | /* Parse the RDS data */ |
732 | while (rds_len >= FM_RDS_BLK_SIZE) { | 732 | while (rds_len >= FM_RDS_BLK_SIZE) { |
733 | meta_data = rds_data[2]; | 733 | meta_data = rds_data[2]; |
734 | /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */ | 734 | /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */ |
735 | type = (meta_data & 0x07); | 735 | type = (meta_data & 0x07); |
736 | 736 | ||
737 | /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */ | 737 | /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */ |
738 | blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); | 738 | blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); |
739 | fmdbg("Block index:%d(%s)\n", blk_idx, | 739 | fmdbg("Block index:%d(%s)\n", blk_idx, |
740 | (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok"); | 740 | (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok"); |
741 | 741 | ||
742 | if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0) | 742 | if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0) |
743 | break; | 743 | break; |
744 | 744 | ||
745 | if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) { | 745 | if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) { |
746 | fmdbg("Block sequence mismatch\n"); | 746 | fmdbg("Block sequence mismatch\n"); |
747 | rds->last_blk_idx = -1; | 747 | rds->last_blk_idx = -1; |
748 | break; | 748 | break; |
749 | } | 749 | } |
750 | 750 | ||
751 | /* Skip checkword (control) byte and copy only data byte */ | 751 | /* Skip checkword (control) byte and copy only data byte */ |
752 | memcpy(&rds_fmt.data.groupdatabuff. | 752 | memcpy(&rds_fmt.data.groupdatabuff. |
753 | buff[blk_idx * (FM_RDS_BLK_SIZE - 1)], | 753 | buff[blk_idx * (FM_RDS_BLK_SIZE - 1)], |
754 | rds_data, (FM_RDS_BLK_SIZE - 1)); | 754 | rds_data, (FM_RDS_BLK_SIZE - 1)); |
755 | 755 | ||
756 | rds->last_blk_idx = blk_idx; | 756 | rds->last_blk_idx = blk_idx; |
757 | 757 | ||
758 | /* If completed a whole group then handle it */ | 758 | /* If completed a whole group then handle it */ |
759 | if (blk_idx == FM_RDS_BLK_IDX_D) { | 759 | if (blk_idx == FM_RDS_BLK_IDX_D) { |
760 | fmdbg("Good block received\n"); | 760 | fmdbg("Good block received\n"); |
761 | fm_rdsparse_swapbytes(fmdev, &rds_fmt); | 761 | fm_rdsparse_swapbytes(fmdev, &rds_fmt); |
762 | 762 | ||
763 | /* | 763 | /* |
764 | * Extract PI code and store in local cache. | 764 | * Extract PI code and store in local cache. |
765 | * We need this during AF switch processing. | 765 | * We need this during AF switch processing. |
766 | */ | 766 | */ |
767 | cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata); | 767 | cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata); |
768 | if (fmdev->rx.stat_info.picode != cur_picode) | 768 | if (fmdev->rx.stat_info.picode != cur_picode) |
769 | fmdev->rx.stat_info.picode = cur_picode; | 769 | fmdev->rx.stat_info.picode = cur_picode; |
770 | 770 | ||
771 | fmdbg("picode:%d\n", cur_picode); | 771 | fmdbg("picode:%d\n", cur_picode); |
772 | 772 | ||
773 | group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3); | 773 | group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3); |
774 | fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2, | 774 | fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2, |
775 | (group_idx % 2) ? "B" : "A"); | 775 | (group_idx % 2) ? "B" : "A"); |
776 | 776 | ||
777 | group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3); | 777 | group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3); |
778 | if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) { | 778 | if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) { |
779 | fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]); | 779 | fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]); |
780 | fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]); | 780 | fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]); |
781 | } | 781 | } |
782 | } | 782 | } |
783 | rds_len -= FM_RDS_BLK_SIZE; | 783 | rds_len -= FM_RDS_BLK_SIZE; |
784 | rds_data += FM_RDS_BLK_SIZE; | 784 | rds_data += FM_RDS_BLK_SIZE; |
785 | } | 785 | } |
786 | 786 | ||
787 | /* Copy raw rds data to internal rds buffer */ | 787 | /* Copy raw rds data to internal rds buffer */ |
788 | rds_data = skb->data; | 788 | rds_data = skb->data; |
789 | rds_len = skb->len; | 789 | rds_len = skb->len; |
790 | 790 | ||
791 | spin_lock_irqsave(&fmdev->rds_buff_lock, flags); | 791 | spin_lock_irqsave(&fmdev->rds_buff_lock, flags); |
792 | while (rds_len > 0) { | 792 | while (rds_len > 0) { |
793 | /* | 793 | /* |
794 | * Fill RDS buffer as per V4L2 specification. | 794 | * Fill RDS buffer as per V4L2 specification. |
795 | * Store control byte | 795 | * Store control byte |
796 | */ | 796 | */ |
797 | type = (rds_data[2] & 0x07); | 797 | type = (rds_data[2] & 0x07); |
798 | blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); | 798 | blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); |
799 | tmpbuf[2] = blk_idx; /* Offset name */ | 799 | tmpbuf[2] = blk_idx; /* Offset name */ |
800 | tmpbuf[2] |= blk_idx << 3; /* Received offset */ | 800 | tmpbuf[2] |= blk_idx << 3; /* Received offset */ |
801 | 801 | ||
802 | /* Store data byte */ | 802 | /* Store data byte */ |
803 | tmpbuf[0] = rds_data[0]; | 803 | tmpbuf[0] = rds_data[0]; |
804 | tmpbuf[1] = rds_data[1]; | 804 | tmpbuf[1] = rds_data[1]; |
805 | 805 | ||
806 | memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE); | 806 | memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE); |
807 | rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size; | 807 | rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size; |
808 | 808 | ||
809 | /* Check for overflow & start over */ | 809 | /* Check for overflow & start over */ |
810 | if (rds->wr_idx == rds->rd_idx) { | 810 | if (rds->wr_idx == rds->rd_idx) { |
811 | fmdbg("RDS buffer overflow\n"); | 811 | fmdbg("RDS buffer overflow\n"); |
812 | rds->wr_idx = 0; | 812 | rds->wr_idx = 0; |
813 | rds->rd_idx = 0; | 813 | rds->rd_idx = 0; |
814 | break; | 814 | break; |
815 | } | 815 | } |
816 | rds_len -= FM_RDS_BLK_SIZE; | 816 | rds_len -= FM_RDS_BLK_SIZE; |
817 | rds_data += FM_RDS_BLK_SIZE; | 817 | rds_data += FM_RDS_BLK_SIZE; |
818 | } | 818 | } |
819 | spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); | 819 | spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); |
820 | 820 | ||
821 | /* Wakeup read queue */ | 821 | /* Wakeup read queue */ |
822 | if (rds->wr_idx != rds->rd_idx) | 822 | if (rds->wr_idx != rds->rd_idx) |
823 | wake_up_interruptible(&rds->read_queue); | 823 | wake_up_interruptible(&rds->read_queue); |
824 | 824 | ||
825 | fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX); | 825 | fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX); |
826 | } | 826 | } |
827 | 827 | ||
828 | static void fm_irq_handle_rds_finish(struct fmdev *fmdev) | 828 | static void fm_irq_handle_rds_finish(struct fmdev *fmdev) |
829 | { | 829 | { |
830 | fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX); | 830 | fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX); |
831 | } | 831 | } |
832 | 832 | ||
833 | static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev) | 833 | static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev) |
834 | { | 834 | { |
835 | if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev-> | 835 | if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev-> |
836 | irq_info.mask) { | 836 | irq_info.mask) { |
837 | fmdbg("irq: tune ended/bandlimit reached\n"); | 837 | fmdbg("irq: tune ended/bandlimit reached\n"); |
838 | if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) { | 838 | if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) { |
839 | fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX; | 839 | fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX; |
840 | } else { | 840 | } else { |
841 | complete(&fmdev->maintask_comp); | 841 | complete(&fmdev->maintask_comp); |
842 | fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; | 842 | fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; |
843 | } | 843 | } |
844 | } else | 844 | } else |
845 | fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; | 845 | fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; |
846 | 846 | ||
847 | fm_irq_call(fmdev); | 847 | fm_irq_call(fmdev); |
848 | } | 848 | } |
849 | 849 | ||
850 | static void fm_irq_handle_power_enb(struct fmdev *fmdev) | 850 | static void fm_irq_handle_power_enb(struct fmdev *fmdev) |
851 | { | 851 | { |
852 | if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) { | 852 | if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) { |
853 | fmdbg("irq: Power Enabled/Disabled\n"); | 853 | fmdbg("irq: Power Enabled/Disabled\n"); |
854 | complete(&fmdev->maintask_comp); | 854 | complete(&fmdev->maintask_comp); |
855 | } | 855 | } |
856 | 856 | ||
857 | fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX); | 857 | fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX); |
858 | } | 858 | } |
859 | 859 | ||
860 | static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev) | 860 | static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev) |
861 | { | 861 | { |
862 | if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) && | 862 | if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) && |
863 | (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) && | 863 | (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) && |
864 | (fmdev->rx.freq != FM_UNDEFINED_FREQ) && | 864 | (fmdev->rx.freq != FM_UNDEFINED_FREQ) && |
865 | (fmdev->rx.stat_info.afcache_size != 0)) { | 865 | (fmdev->rx.stat_info.afcache_size != 0)) { |
866 | fmdbg("irq: rssi level has fallen below threshold level\n"); | 866 | fmdbg("irq: rssi level has fallen below threshold level\n"); |
867 | 867 | ||
868 | /* Disable further low RSSI interrupts */ | 868 | /* Disable further low RSSI interrupts */ |
869 | fmdev->irq_info.mask &= ~FM_LEV_EVENT; | 869 | fmdev->irq_info.mask &= ~FM_LEV_EVENT; |
870 | 870 | ||
871 | fmdev->rx.afjump_idx = 0; | 871 | fmdev->rx.afjump_idx = 0; |
872 | fmdev->rx.freq_before_jump = fmdev->rx.freq; | 872 | fmdev->rx.freq_before_jump = fmdev->rx.freq; |
873 | fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; | 873 | fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; |
874 | } else { | 874 | } else { |
875 | /* Continue next function in interrupt handler table */ | 875 | /* Continue next function in interrupt handler table */ |
876 | fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX; | 876 | fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX; |
877 | } | 877 | } |
878 | 878 | ||
879 | fm_irq_call(fmdev); | 879 | fm_irq_call(fmdev); |
880 | } | 880 | } |
881 | 881 | ||
882 | static void fm_irq_afjump_set_pi(struct fmdev *fmdev) | 882 | static void fm_irq_afjump_set_pi(struct fmdev *fmdev) |
883 | { | 883 | { |
884 | u16 payload; | 884 | u16 payload; |
885 | 885 | ||
886 | /* Set PI code - must be updated if the AF list is not empty */ | 886 | /* Set PI code - must be updated if the AF list is not empty */ |
887 | payload = fmdev->rx.stat_info.picode; | 887 | payload = fmdev->rx.stat_info.picode; |
888 | if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL)) | 888 | if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL)) |
889 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX); | 889 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX); |
890 | } | 890 | } |
891 | 891 | ||
892 | static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev) | 892 | static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev) |
893 | { | 893 | { |
894 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX); | 894 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX); |
895 | } | 895 | } |
896 | 896 | ||
897 | /* | 897 | /* |
898 | * Set PI mask. | 898 | * Set PI mask. |
899 | * 0xFFFF = Enable PI code matching | 899 | * 0xFFFF = Enable PI code matching |
900 | * 0x0000 = Disable PI code matching | 900 | * 0x0000 = Disable PI code matching |
901 | */ | 901 | */ |
902 | static void fm_irq_afjump_set_pimask(struct fmdev *fmdev) | 902 | static void fm_irq_afjump_set_pimask(struct fmdev *fmdev) |
903 | { | 903 | { |
904 | u16 payload; | 904 | u16 payload; |
905 | 905 | ||
906 | payload = 0x0000; | 906 | payload = 0x0000; |
907 | if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) | 907 | if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) |
908 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX); | 908 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX); |
909 | } | 909 | } |
910 | 910 | ||
911 | static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev) | 911 | static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev) |
912 | { | 912 | { |
913 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX); | 913 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX); |
914 | } | 914 | } |
915 | 915 | ||
916 | static void fm_irq_afjump_setfreq(struct fmdev *fmdev) | 916 | static void fm_irq_afjump_setfreq(struct fmdev *fmdev) |
917 | { | 917 | { |
918 | u16 frq_index; | 918 | u16 frq_index; |
919 | u16 payload; | 919 | u16 payload; |
920 | 920 | ||
921 | fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]); | 921 | fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]); |
922 | frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] - | 922 | frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] - |
923 | fmdev->rx.region.bot_freq) / FM_FREQ_MUL; | 923 | fmdev->rx.region.bot_freq) / FM_FREQ_MUL; |
924 | 924 | ||
925 | payload = frq_index; | 925 | payload = frq_index; |
926 | if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL)) | 926 | if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL)) |
927 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX); | 927 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX); |
928 | } | 928 | } |
929 | 929 | ||
930 | static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev) | 930 | static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev) |
931 | { | 931 | { |
932 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX); | 932 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX); |
933 | } | 933 | } |
934 | 934 | ||
935 | static void fm_irq_afjump_enableint(struct fmdev *fmdev) | 935 | static void fm_irq_afjump_enableint(struct fmdev *fmdev) |
936 | { | 936 | { |
937 | u16 payload; | 937 | u16 payload; |
938 | 938 | ||
939 | /* Enable FR (tuning operation ended) interrupt */ | 939 | /* Enable FR (tuning operation ended) interrupt */ |
940 | payload = FM_FR_EVENT; | 940 | payload = FM_FR_EVENT; |
941 | if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) | 941 | if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) |
942 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX); | 942 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX); |
943 | } | 943 | } |
944 | 944 | ||
945 | static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev) | 945 | static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev) |
946 | { | 946 | { |
947 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX); | 947 | fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX); |
948 | } | 948 | } |
949 | 949 | ||
950 | static void fm_irq_start_afjump(struct fmdev *fmdev) | 950 | static void fm_irq_start_afjump(struct fmdev *fmdev) |
951 | { | 951 | { |
952 | u16 payload; | 952 | u16 payload; |
953 | 953 | ||
954 | payload = FM_TUNER_AF_JUMP_MODE; | 954 | payload = FM_TUNER_AF_JUMP_MODE; |
955 | if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, | 955 | if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, |
956 | sizeof(payload), NULL)) | 956 | sizeof(payload), NULL)) |
957 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX); | 957 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX); |
958 | } | 958 | } |
959 | 959 | ||
960 | static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev) | 960 | static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev) |
961 | { | 961 | { |
962 | struct sk_buff *skb; | 962 | struct sk_buff *skb; |
963 | 963 | ||
964 | if (check_cmdresp_status(fmdev, &skb)) | 964 | if (check_cmdresp_status(fmdev, &skb)) |
965 | return; | 965 | return; |
966 | 966 | ||
967 | fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; | 967 | fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; |
968 | set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag); | 968 | set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag); |
969 | clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); | 969 | clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); |
970 | } | 970 | } |
971 | 971 | ||
972 | static void fm_irq_afjump_rd_freq(struct fmdev *fmdev) | 972 | static void fm_irq_afjump_rd_freq(struct fmdev *fmdev) |
973 | { | 973 | { |
974 | u16 payload; | 974 | u16 payload; |
975 | 975 | ||
976 | if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL)) | 976 | if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL)) |
977 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX); | 977 | fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX); |
978 | } | 978 | } |
979 | 979 | ||
980 | static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev) | 980 | static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev) |
981 | { | 981 | { |
982 | struct sk_buff *skb; | 982 | struct sk_buff *skb; |
983 | u16 read_freq; | 983 | u16 read_freq; |
984 | u32 curr_freq, jumped_freq; | 984 | u32 curr_freq, jumped_freq; |
985 | 985 | ||
986 | if (check_cmdresp_status(fmdev, &skb)) | 986 | if (check_cmdresp_status(fmdev, &skb)) |
987 | return; | 987 | return; |
988 | 988 | ||
989 | /* Skip header info and copy only response data */ | 989 | /* Skip header info and copy only response data */ |
990 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); | 990 | skb_pull(skb, sizeof(struct fm_event_msg_hdr)); |
991 | memcpy(&read_freq, skb->data, sizeof(read_freq)); | 991 | memcpy(&read_freq, skb->data, sizeof(read_freq)); |
992 | read_freq = be16_to_cpu(read_freq); | 992 | read_freq = be16_to_cpu(read_freq); |
993 | curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL); | 993 | curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL); |
994 | 994 | ||
995 | jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]; | 995 | jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]; |
996 | 996 | ||
997 | /* If the frequency was changed the jump succeeded */ | 997 | /* If the frequency was changed the jump succeeded */ |
998 | if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) { | 998 | if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) { |
999 | fmdbg("Successfully switched to alternate freq %d\n", curr_freq); | 999 | fmdbg("Successfully switched to alternate freq %d\n", curr_freq); |
1000 | fmdev->rx.freq = curr_freq; | 1000 | fmdev->rx.freq = curr_freq; |
1001 | fm_rx_reset_rds_cache(fmdev); | 1001 | fm_rx_reset_rds_cache(fmdev); |
1002 | 1002 | ||
1003 | /* AF feature is on, enable low level RSSI interrupt */ | 1003 | /* AF feature is on, enable low level RSSI interrupt */ |
1004 | if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) | 1004 | if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) |
1005 | fmdev->irq_info.mask |= FM_LEV_EVENT; | 1005 | fmdev->irq_info.mask |= FM_LEV_EVENT; |
1006 | 1006 | ||
1007 | fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; | 1007 | fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; |
1008 | } else { /* jump to the next freq in the AF list */ | 1008 | } else { /* jump to the next freq in the AF list */ |
1009 | fmdev->rx.afjump_idx++; | 1009 | fmdev->rx.afjump_idx++; |
1010 | 1010 | ||
1011 | /* If we reached the end of the list - stop searching */ | 1011 | /* If we reached the end of the list - stop searching */ |
1012 | if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) { | 1012 | if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) { |
1013 | fmdbg("AF switch processing failed\n"); | 1013 | fmdbg("AF switch processing failed\n"); |
1014 | fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; | 1014 | fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; |
1015 | } else { /* AF List is not over - try next one */ | 1015 | } else { /* AF List is not over - try next one */ |
1016 | 1016 | ||
1017 | fmdbg("Trying next freq in AF cache\n"); | 1017 | fmdbg("Trying next freq in AF cache\n"); |
1018 | fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; | 1018 | fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; |
1019 | } | 1019 | } |
1020 | } | 1020 | } |
1021 | fm_irq_call(fmdev); | 1021 | fm_irq_call(fmdev); |
1022 | } | 1022 | } |
1023 | 1023 | ||
1024 | static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev) | 1024 | static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev) |
1025 | { | 1025 | { |
1026 | fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); | 1026 | fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev) | 1029 | static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev) |
1030 | { | 1030 | { |
1031 | u16 payload; | 1031 | u16 payload; |
1032 | 1032 | ||
1033 | /* Re-enable FM interrupts */ | 1033 | /* Re-enable FM interrupts */ |
1034 | payload = fmdev->irq_info.mask; | 1034 | payload = fmdev->irq_info.mask; |
1035 | 1035 | ||
1036 | if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, | 1036 | if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, |
1037 | sizeof(payload), NULL)) | 1037 | sizeof(payload), NULL)) |
1038 | fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX); | 1038 | fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX); |
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) | 1041 | static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) |
1042 | { | 1042 | { |
1043 | struct sk_buff *skb; | 1043 | struct sk_buff *skb; |
1044 | 1044 | ||
1045 | if (check_cmdresp_status(fmdev, &skb)) | 1045 | if (check_cmdresp_status(fmdev, &skb)) |
1046 | return; | 1046 | return; |
1047 | /* | 1047 | /* |
1048 | * This is last function in interrupt table to be executed. | 1048 | * This is last function in interrupt table to be executed. |
1049 | * So, reset stage index to 0. | 1049 | * So, reset stage index to 0. |
1050 | */ | 1050 | */ |
1051 | fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; | 1051 | fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; |
1052 | 1052 | ||
1053 | /* Start processing any pending interrupt */ | 1053 | /* Start processing any pending interrupt */ |
1054 | if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag)) | 1054 | if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag)) |
1055 | fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); | 1055 | fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); |
1056 | else | 1056 | else |
1057 | clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); | 1057 | clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); |
1058 | } | 1058 | } |
1059 | 1059 | ||
1060 | /* Returns availability of RDS data in internel buffer */ | 1060 | /* Returns availability of RDS data in internel buffer */ |
1061 | u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, | 1061 | u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, |
1062 | struct poll_table_struct *pts) | 1062 | struct poll_table_struct *pts) |
1063 | { | 1063 | { |
1064 | poll_wait(file, &fmdev->rx.rds.read_queue, pts); | 1064 | poll_wait(file, &fmdev->rx.rds.read_queue, pts); |
1065 | if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx) | 1065 | if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx) |
1066 | return 0; | 1066 | return 0; |
1067 | 1067 | ||
1068 | return -EAGAIN; | 1068 | return -EAGAIN; |
1069 | } | 1069 | } |
1070 | 1070 | ||
1071 | /* Copies RDS data from internal buffer to user buffer */ | 1071 | /* Copies RDS data from internal buffer to user buffer */ |
1072 | u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, | 1072 | u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, |
1073 | u8 __user *buf, size_t count) | 1073 | u8 __user *buf, size_t count) |
1074 | { | 1074 | { |
1075 | u32 block_count; | 1075 | u32 block_count; |
1076 | unsigned long flags; | 1076 | unsigned long flags; |
1077 | int ret; | 1077 | int ret; |
1078 | 1078 | ||
1079 | if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { | 1079 | if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { |
1080 | if (file->f_flags & O_NONBLOCK) | 1080 | if (file->f_flags & O_NONBLOCK) |
1081 | return -EWOULDBLOCK; | 1081 | return -EWOULDBLOCK; |
1082 | 1082 | ||
1083 | ret = wait_event_interruptible(fmdev->rx.rds.read_queue, | 1083 | ret = wait_event_interruptible(fmdev->rx.rds.read_queue, |
1084 | (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx)); | 1084 | (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx)); |
1085 | if (ret) | 1085 | if (ret) |
1086 | return -EINTR; | 1086 | return -EINTR; |
1087 | } | 1087 | } |
1088 | 1088 | ||
1089 | /* Calculate block count from byte count */ | 1089 | /* Calculate block count from byte count */ |
1090 | count /= 3; | 1090 | count /= 3; |
1091 | block_count = 0; | 1091 | block_count = 0; |
1092 | ret = 0; | 1092 | ret = 0; |
1093 | 1093 | ||
1094 | spin_lock_irqsave(&fmdev->rds_buff_lock, flags); | 1094 | spin_lock_irqsave(&fmdev->rds_buff_lock, flags); |
1095 | 1095 | ||
1096 | while (block_count < count) { | 1096 | while (block_count < count) { |
1097 | if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) | 1097 | if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) |
1098 | break; | 1098 | break; |
1099 | 1099 | ||
1100 | if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], | 1100 | if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], |
1101 | FM_RDS_BLK_SIZE)) | 1101 | FM_RDS_BLK_SIZE)) |
1102 | break; | 1102 | break; |
1103 | 1103 | ||
1104 | fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; | 1104 | fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; |
1105 | if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) | 1105 | if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) |
1106 | fmdev->rx.rds.rd_idx = 0; | 1106 | fmdev->rx.rds.rd_idx = 0; |
1107 | 1107 | ||
1108 | block_count++; | 1108 | block_count++; |
1109 | buf += FM_RDS_BLK_SIZE; | 1109 | buf += FM_RDS_BLK_SIZE; |
1110 | ret += FM_RDS_BLK_SIZE; | 1110 | ret += FM_RDS_BLK_SIZE; |
1111 | } | 1111 | } |
1112 | spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); | 1112 | spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); |
1113 | return ret; | 1113 | return ret; |
1114 | } | 1114 | } |
1115 | 1115 | ||
1116 | u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) | 1116 | u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) |
1117 | { | 1117 | { |
1118 | switch (fmdev->curr_fmmode) { | 1118 | switch (fmdev->curr_fmmode) { |
1119 | case FM_MODE_RX: | 1119 | case FM_MODE_RX: |
1120 | return fm_rx_set_freq(fmdev, freq_to_set); | 1120 | return fm_rx_set_freq(fmdev, freq_to_set); |
1121 | 1121 | ||
1122 | case FM_MODE_TX: | 1122 | case FM_MODE_TX: |
1123 | return fm_tx_set_freq(fmdev, freq_to_set); | 1123 | return fm_tx_set_freq(fmdev, freq_to_set); |
1124 | 1124 | ||
1125 | default: | 1125 | default: |
1126 | return -EINVAL; | 1126 | return -EINVAL; |
1127 | } | 1127 | } |
1128 | } | 1128 | } |
1129 | 1129 | ||
1130 | u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) | 1130 | u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) |
1131 | { | 1131 | { |
1132 | if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { | 1132 | if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { |
1133 | fmerr("RX frequency is not set\n"); | 1133 | fmerr("RX frequency is not set\n"); |
1134 | return -EPERM; | 1134 | return -EPERM; |
1135 | } | 1135 | } |
1136 | if (cur_tuned_frq == NULL) { | 1136 | if (cur_tuned_frq == NULL) { |
1137 | fmerr("Invalid memory\n"); | 1137 | fmerr("Invalid memory\n"); |
1138 | return -ENOMEM; | 1138 | return -ENOMEM; |
1139 | } | 1139 | } |
1140 | 1140 | ||
1141 | switch (fmdev->curr_fmmode) { | 1141 | switch (fmdev->curr_fmmode) { |
1142 | case FM_MODE_RX: | 1142 | case FM_MODE_RX: |
1143 | *cur_tuned_frq = fmdev->rx.freq; | 1143 | *cur_tuned_frq = fmdev->rx.freq; |
1144 | return 0; | 1144 | return 0; |
1145 | 1145 | ||
1146 | case FM_MODE_TX: | 1146 | case FM_MODE_TX: |
1147 | *cur_tuned_frq = 0; /* TODO : Change this later */ | 1147 | *cur_tuned_frq = 0; /* TODO : Change this later */ |
1148 | return 0; | 1148 | return 0; |
1149 | 1149 | ||
1150 | default: | 1150 | default: |
1151 | return -EINVAL; | 1151 | return -EINVAL; |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | } | 1154 | } |
1155 | 1155 | ||
1156 | u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) | 1156 | u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) |
1157 | { | 1157 | { |
1158 | switch (fmdev->curr_fmmode) { | 1158 | switch (fmdev->curr_fmmode) { |
1159 | case FM_MODE_RX: | 1159 | case FM_MODE_RX: |
1160 | return fm_rx_set_region(fmdev, region_to_set); | 1160 | return fm_rx_set_region(fmdev, region_to_set); |
1161 | 1161 | ||
1162 | case FM_MODE_TX: | 1162 | case FM_MODE_TX: |
1163 | return fm_tx_set_region(fmdev, region_to_set); | 1163 | return fm_tx_set_region(fmdev, region_to_set); |
1164 | 1164 | ||
1165 | default: | 1165 | default: |
1166 | return -EINVAL; | 1166 | return -EINVAL; |
1167 | } | 1167 | } |
1168 | } | 1168 | } |
1169 | 1169 | ||
1170 | u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) | 1170 | u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) |
1171 | { | 1171 | { |
1172 | switch (fmdev->curr_fmmode) { | 1172 | switch (fmdev->curr_fmmode) { |
1173 | case FM_MODE_RX: | 1173 | case FM_MODE_RX: |
1174 | return fm_rx_set_mute_mode(fmdev, mute_mode_toset); | 1174 | return fm_rx_set_mute_mode(fmdev, mute_mode_toset); |
1175 | 1175 | ||
1176 | case FM_MODE_TX: | 1176 | case FM_MODE_TX: |
1177 | return fm_tx_set_mute_mode(fmdev, mute_mode_toset); | 1177 | return fm_tx_set_mute_mode(fmdev, mute_mode_toset); |
1178 | 1178 | ||
1179 | default: | 1179 | default: |
1180 | return -EINVAL; | 1180 | return -EINVAL; |
1181 | } | 1181 | } |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) | 1184 | u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) |
1185 | { | 1185 | { |
1186 | switch (fmdev->curr_fmmode) { | 1186 | switch (fmdev->curr_fmmode) { |
1187 | case FM_MODE_RX: | 1187 | case FM_MODE_RX: |
1188 | return fm_rx_set_stereo_mono(fmdev, mode); | 1188 | return fm_rx_set_stereo_mono(fmdev, mode); |
1189 | 1189 | ||
1190 | case FM_MODE_TX: | 1190 | case FM_MODE_TX: |
1191 | return fm_tx_set_stereo_mono(fmdev, mode); | 1191 | return fm_tx_set_stereo_mono(fmdev, mode); |
1192 | 1192 | ||
1193 | default: | 1193 | default: |
1194 | return -EINVAL; | 1194 | return -EINVAL; |
1195 | } | 1195 | } |
1196 | } | 1196 | } |
1197 | 1197 | ||
1198 | u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) | 1198 | u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) |
1199 | { | 1199 | { |
1200 | switch (fmdev->curr_fmmode) { | 1200 | switch (fmdev->curr_fmmode) { |
1201 | case FM_MODE_RX: | 1201 | case FM_MODE_RX: |
1202 | return fm_rx_set_rds_mode(fmdev, rds_en_dis); | 1202 | return fm_rx_set_rds_mode(fmdev, rds_en_dis); |
1203 | 1203 | ||
1204 | case FM_MODE_TX: | 1204 | case FM_MODE_TX: |
1205 | return fm_tx_set_rds_mode(fmdev, rds_en_dis); | 1205 | return fm_tx_set_rds_mode(fmdev, rds_en_dis); |
1206 | 1206 | ||
1207 | default: | 1207 | default: |
1208 | return -EINVAL; | 1208 | return -EINVAL; |
1209 | } | 1209 | } |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | /* Sends power off command to the chip */ | 1212 | /* Sends power off command to the chip */ |
1213 | static u32 fm_power_down(struct fmdev *fmdev) | 1213 | static u32 fm_power_down(struct fmdev *fmdev) |
1214 | { | 1214 | { |
1215 | u16 payload; | 1215 | u16 payload; |
1216 | u32 ret; | 1216 | u32 ret; |
1217 | 1217 | ||
1218 | if (!test_bit(FM_CORE_READY, &fmdev->flag)) { | 1218 | if (!test_bit(FM_CORE_READY, &fmdev->flag)) { |
1219 | fmerr("FM core is not ready\n"); | 1219 | fmerr("FM core is not ready\n"); |
1220 | return -EPERM; | 1220 | return -EPERM; |
1221 | } | 1221 | } |
1222 | if (fmdev->curr_fmmode == FM_MODE_OFF) { | 1222 | if (fmdev->curr_fmmode == FM_MODE_OFF) { |
1223 | fmdbg("FM chip is already in OFF state\n"); | 1223 | fmdbg("FM chip is already in OFF state\n"); |
1224 | return 0; | 1224 | return 0; |
1225 | } | 1225 | } |
1226 | 1226 | ||
1227 | payload = 0x0; | 1227 | payload = 0x0; |
1228 | ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, | 1228 | ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, |
1229 | sizeof(payload), NULL, NULL); | 1229 | sizeof(payload), NULL, NULL); |
1230 | if (ret < 0) | 1230 | if (ret < 0) |
1231 | return ret; | 1231 | return ret; |
1232 | 1232 | ||
1233 | return fmc_release(fmdev); | 1233 | return fmc_release(fmdev); |
1234 | } | 1234 | } |
1235 | 1235 | ||
1236 | /* Reads init command from FM firmware file and loads to the chip */ | 1236 | /* Reads init command from FM firmware file and loads to the chip */ |
1237 | static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) | 1237 | static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) |
1238 | { | 1238 | { |
1239 | const struct firmware *fw_entry; | 1239 | const struct firmware *fw_entry; |
1240 | struct bts_header *fw_header; | 1240 | struct bts_header *fw_header; |
1241 | struct bts_action *action; | 1241 | struct bts_action *action; |
1242 | struct bts_action_delay *delay; | 1242 | struct bts_action_delay *delay; |
1243 | u8 *fw_data; | 1243 | u8 *fw_data; |
1244 | int ret, fw_len, cmd_cnt; | 1244 | int ret, fw_len, cmd_cnt; |
1245 | 1245 | ||
1246 | cmd_cnt = 0; | 1246 | cmd_cnt = 0; |
1247 | set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); | 1247 | set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); |
1248 | 1248 | ||
1249 | ret = request_firmware(&fw_entry, fw_name, | 1249 | ret = request_firmware(&fw_entry, fw_name, |
1250 | &fmdev->radio_dev->dev); | 1250 | &fmdev->radio_dev->dev); |
1251 | if (ret < 0) { | 1251 | if (ret < 0) { |
1252 | fmerr("Unable to read firmware(%s) content\n", fw_name); | 1252 | fmerr("Unable to read firmware(%s) content\n", fw_name); |
1253 | return ret; | 1253 | return ret; |
1254 | } | 1254 | } |
1255 | fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size); | 1255 | fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size); |
1256 | 1256 | ||
1257 | fw_data = (void *)fw_entry->data; | 1257 | fw_data = (void *)fw_entry->data; |
1258 | fw_len = fw_entry->size; | 1258 | fw_len = fw_entry->size; |
1259 | 1259 | ||
1260 | fw_header = (struct bts_header *)fw_data; | 1260 | fw_header = (struct bts_header *)fw_data; |
1261 | if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) { | 1261 | if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) { |
1262 | fmerr("%s not a legal TI firmware file\n", fw_name); | 1262 | fmerr("%s not a legal TI firmware file\n", fw_name); |
1263 | ret = -EINVAL; | 1263 | ret = -EINVAL; |
1264 | goto rel_fw; | 1264 | goto rel_fw; |
1265 | } | 1265 | } |
1266 | fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic); | 1266 | fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic); |
1267 | 1267 | ||
1268 | /* Skip file header info , we already verified it */ | 1268 | /* Skip file header info , we already verified it */ |
1269 | fw_data += sizeof(struct bts_header); | 1269 | fw_data += sizeof(struct bts_header); |
1270 | fw_len -= sizeof(struct bts_header); | 1270 | fw_len -= sizeof(struct bts_header); |
1271 | 1271 | ||
1272 | while (fw_data && fw_len > 0) { | 1272 | while (fw_data && fw_len > 0) { |
1273 | action = (struct bts_action *)fw_data; | 1273 | action = (struct bts_action *)fw_data; |
1274 | 1274 | ||
1275 | switch (action->type) { | 1275 | switch (action->type) { |
1276 | case ACTION_SEND_COMMAND: /* Send */ | 1276 | case ACTION_SEND_COMMAND: /* Send */ |
1277 | if (fmc_send_cmd(fmdev, 0, 0, action->data, | 1277 | if (fmc_send_cmd(fmdev, 0, 0, action->data, |
1278 | action->size, NULL, NULL)) | 1278 | action->size, NULL, NULL)) |
1279 | goto rel_fw; | 1279 | goto rel_fw; |
1280 | 1280 | ||
1281 | cmd_cnt++; | 1281 | cmd_cnt++; |
1282 | break; | 1282 | break; |
1283 | 1283 | ||
1284 | case ACTION_DELAY: /* Delay */ | 1284 | case ACTION_DELAY: /* Delay */ |
1285 | delay = (struct bts_action_delay *)action->data; | 1285 | delay = (struct bts_action_delay *)action->data; |
1286 | mdelay(delay->msec); | 1286 | mdelay(delay->msec); |
1287 | break; | 1287 | break; |
1288 | } | 1288 | } |
1289 | 1289 | ||
1290 | fw_data += (sizeof(struct bts_action) + (action->size)); | 1290 | fw_data += (sizeof(struct bts_action) + (action->size)); |
1291 | fw_len -= (sizeof(struct bts_action) + (action->size)); | 1291 | fw_len -= (sizeof(struct bts_action) + (action->size)); |
1292 | } | 1292 | } |
1293 | fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt); | 1293 | fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt); |
1294 | rel_fw: | 1294 | rel_fw: |
1295 | release_firmware(fw_entry); | 1295 | release_firmware(fw_entry); |
1296 | clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); | 1296 | clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); |
1297 | 1297 | ||
1298 | return ret; | 1298 | return ret; |
1299 | } | 1299 | } |
1300 | 1300 | ||
1301 | /* Loads default RX configuration to the chip */ | 1301 | /* Loads default RX configuration to the chip */ |
1302 | static u32 load_default_rx_configuration(struct fmdev *fmdev) | 1302 | static u32 load_default_rx_configuration(struct fmdev *fmdev) |
1303 | { | 1303 | { |
1304 | int ret; | 1304 | int ret; |
1305 | 1305 | ||
1306 | ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME); | 1306 | ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME); |
1307 | if (ret < 0) | 1307 | if (ret < 0) |
1308 | return ret; | 1308 | return ret; |
1309 | 1309 | ||
1310 | return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD); | 1310 | return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD); |
1311 | } | 1311 | } |
1312 | 1312 | ||
1313 | /* Does FM power on sequence */ | 1313 | /* Does FM power on sequence */ |
1314 | static u32 fm_power_up(struct fmdev *fmdev, u8 mode) | 1314 | static u32 fm_power_up(struct fmdev *fmdev, u8 mode) |
1315 | { | 1315 | { |
1316 | u16 payload, asic_id, asic_ver; | 1316 | u16 payload, asic_id, asic_ver; |
1317 | int resp_len, ret; | 1317 | int resp_len, ret; |
1318 | u8 fw_name[50]; | 1318 | u8 fw_name[50]; |
1319 | 1319 | ||
1320 | if (mode >= FM_MODE_ENTRY_MAX) { | 1320 | if (mode >= FM_MODE_ENTRY_MAX) { |
1321 | fmerr("Invalid firmware download option\n"); | 1321 | fmerr("Invalid firmware download option\n"); |
1322 | return -EINVAL; | 1322 | return -EINVAL; |
1323 | } | 1323 | } |
1324 | 1324 | ||
1325 | /* | 1325 | /* |
1326 | * Initialize FM common module. FM GPIO toggling is | 1326 | * Initialize FM common module. FM GPIO toggling is |
1327 | * taken care in Shared Transport driver. | 1327 | * taken care in Shared Transport driver. |
1328 | */ | 1328 | */ |
1329 | ret = fmc_prepare(fmdev); | 1329 | ret = fmc_prepare(fmdev); |
1330 | if (ret < 0) { | 1330 | if (ret < 0) { |
1331 | fmerr("Unable to prepare FM Common\n"); | 1331 | fmerr("Unable to prepare FM Common\n"); |
1332 | return ret; | 1332 | return ret; |
1333 | } | 1333 | } |
1334 | 1334 | ||
1335 | payload = FM_ENABLE; | 1335 | payload = FM_ENABLE; |
1336 | if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, | 1336 | if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, |
1337 | sizeof(payload), NULL, NULL)) | 1337 | sizeof(payload), NULL, NULL)) |
1338 | goto rel; | 1338 | goto rel; |
1339 | 1339 | ||
1340 | /* Allow the chip to settle down in Channel-8 mode */ | 1340 | /* Allow the chip to settle down in Channel-8 mode */ |
1341 | msleep(20); | 1341 | msleep(20); |
1342 | 1342 | ||
1343 | if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL, | 1343 | if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL, |
1344 | sizeof(asic_id), &asic_id, &resp_len)) | 1344 | sizeof(asic_id), &asic_id, &resp_len)) |
1345 | goto rel; | 1345 | goto rel; |
1346 | 1346 | ||
1347 | if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL, | 1347 | if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL, |
1348 | sizeof(asic_ver), &asic_ver, &resp_len)) | 1348 | sizeof(asic_ver), &asic_ver, &resp_len)) |
1349 | goto rel; | 1349 | goto rel; |
1350 | 1350 | ||
1351 | fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n", | 1351 | fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n", |
1352 | be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); | 1352 | be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); |
1353 | 1353 | ||
1354 | sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START, | 1354 | sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START, |
1355 | be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); | 1355 | be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); |
1356 | 1356 | ||
1357 | ret = fm_download_firmware(fmdev, fw_name); | 1357 | ret = fm_download_firmware(fmdev, fw_name); |
1358 | if (ret < 0) { | 1358 | if (ret < 0) { |
1359 | fmdbg("Failed to download firmware file %s\n", fw_name); | 1359 | fmdbg("Failed to download firmware file %s\n", fw_name); |
1360 | goto rel; | 1360 | goto rel; |
1361 | } | 1361 | } |
1362 | sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ? | 1362 | sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ? |
1363 | FM_RX_FW_FILE_START : FM_TX_FW_FILE_START, | 1363 | FM_RX_FW_FILE_START : FM_TX_FW_FILE_START, |
1364 | be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); | 1364 | be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); |
1365 | 1365 | ||
1366 | ret = fm_download_firmware(fmdev, fw_name); | 1366 | ret = fm_download_firmware(fmdev, fw_name); |
1367 | if (ret < 0) { | 1367 | if (ret < 0) { |
1368 | fmdbg("Failed to download firmware file %s\n", fw_name); | 1368 | fmdbg("Failed to download firmware file %s\n", fw_name); |
1369 | goto rel; | 1369 | goto rel; |
1370 | } else | 1370 | } else |
1371 | return ret; | 1371 | return ret; |
1372 | rel: | 1372 | rel: |
1373 | return fmc_release(fmdev); | 1373 | return fmc_release(fmdev); |
1374 | } | 1374 | } |
1375 | 1375 | ||
1376 | /* Set FM Modes(TX, RX, OFF) */ | 1376 | /* Set FM Modes(TX, RX, OFF) */ |
1377 | u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) | 1377 | u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) |
1378 | { | 1378 | { |
1379 | int ret = 0; | 1379 | int ret = 0; |
1380 | 1380 | ||
1381 | if (fm_mode >= FM_MODE_ENTRY_MAX) { | 1381 | if (fm_mode >= FM_MODE_ENTRY_MAX) { |
1382 | fmerr("Invalid FM mode\n"); | 1382 | fmerr("Invalid FM mode\n"); |
1383 | return -EINVAL; | 1383 | return -EINVAL; |
1384 | } | 1384 | } |
1385 | if (fmdev->curr_fmmode == fm_mode) { | 1385 | if (fmdev->curr_fmmode == fm_mode) { |
1386 | fmdbg("Already fm is in mode(%d)\n", fm_mode); | 1386 | fmdbg("Already fm is in mode(%d)\n", fm_mode); |
1387 | return ret; | 1387 | return ret; |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | switch (fm_mode) { | 1390 | switch (fm_mode) { |
1391 | case FM_MODE_OFF: /* OFF Mode */ | 1391 | case FM_MODE_OFF: /* OFF Mode */ |
1392 | ret = fm_power_down(fmdev); | 1392 | ret = fm_power_down(fmdev); |
1393 | if (ret < 0) { | 1393 | if (ret < 0) { |
1394 | fmerr("Failed to set OFF mode\n"); | 1394 | fmerr("Failed to set OFF mode\n"); |
1395 | return ret; | 1395 | return ret; |
1396 | } | 1396 | } |
1397 | break; | 1397 | break; |
1398 | 1398 | ||
1399 | case FM_MODE_TX: /* TX Mode */ | 1399 | case FM_MODE_TX: /* TX Mode */ |
1400 | case FM_MODE_RX: /* RX Mode */ | 1400 | case FM_MODE_RX: /* RX Mode */ |
1401 | /* Power down before switching to TX or RX mode */ | 1401 | /* Power down before switching to TX or RX mode */ |
1402 | if (fmdev->curr_fmmode != FM_MODE_OFF) { | 1402 | if (fmdev->curr_fmmode != FM_MODE_OFF) { |
1403 | ret = fm_power_down(fmdev); | 1403 | ret = fm_power_down(fmdev); |
1404 | if (ret < 0) { | 1404 | if (ret < 0) { |
1405 | fmerr("Failed to set OFF mode\n"); | 1405 | fmerr("Failed to set OFF mode\n"); |
1406 | return ret; | 1406 | return ret; |
1407 | } | 1407 | } |
1408 | msleep(30); | 1408 | msleep(30); |
1409 | } | 1409 | } |
1410 | ret = fm_power_up(fmdev, fm_mode); | 1410 | ret = fm_power_up(fmdev, fm_mode); |
1411 | if (ret < 0) { | 1411 | if (ret < 0) { |
1412 | fmerr("Failed to load firmware\n"); | 1412 | fmerr("Failed to load firmware\n"); |
1413 | return ret; | 1413 | return ret; |
1414 | } | 1414 | } |
1415 | } | 1415 | } |
1416 | fmdev->curr_fmmode = fm_mode; | 1416 | fmdev->curr_fmmode = fm_mode; |
1417 | 1417 | ||
1418 | /* Set default configuration */ | 1418 | /* Set default configuration */ |
1419 | if (fmdev->curr_fmmode == FM_MODE_RX) { | 1419 | if (fmdev->curr_fmmode == FM_MODE_RX) { |
1420 | fmdbg("Loading default rx configuration..\n"); | 1420 | fmdbg("Loading default rx configuration..\n"); |
1421 | ret = load_default_rx_configuration(fmdev); | 1421 | ret = load_default_rx_configuration(fmdev); |
1422 | if (ret < 0) | 1422 | if (ret < 0) |
1423 | fmerr("Failed to load default values\n"); | 1423 | fmerr("Failed to load default values\n"); |
1424 | } | 1424 | } |
1425 | 1425 | ||
1426 | return ret; | 1426 | return ret; |
1427 | } | 1427 | } |
1428 | 1428 | ||
1429 | /* Returns current FM mode (TX, RX, OFF) */ | 1429 | /* Returns current FM mode (TX, RX, OFF) */ |
1430 | u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) | 1430 | u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) |
1431 | { | 1431 | { |
1432 | if (!test_bit(FM_CORE_READY, &fmdev->flag)) { | 1432 | if (!test_bit(FM_CORE_READY, &fmdev->flag)) { |
1433 | fmerr("FM core is not ready\n"); | 1433 | fmerr("FM core is not ready\n"); |
1434 | return -EPERM; | 1434 | return -EPERM; |
1435 | } | 1435 | } |
1436 | if (fmmode == NULL) { | 1436 | if (fmmode == NULL) { |
1437 | fmerr("Invalid memory\n"); | 1437 | fmerr("Invalid memory\n"); |
1438 | return -ENOMEM; | 1438 | return -ENOMEM; |
1439 | } | 1439 | } |
1440 | 1440 | ||
1441 | *fmmode = fmdev->curr_fmmode; | 1441 | *fmmode = fmdev->curr_fmmode; |
1442 | return 0; | 1442 | return 0; |
1443 | } | 1443 | } |
1444 | 1444 | ||
1445 | /* Called by ST layer when FM packet is available */ | 1445 | /* Called by ST layer when FM packet is available */ |
1446 | static long fm_st_receive(void *arg, struct sk_buff *skb) | 1446 | static long fm_st_receive(void *arg, struct sk_buff *skb) |
1447 | { | 1447 | { |
1448 | struct fmdev *fmdev; | 1448 | struct fmdev *fmdev; |
1449 | 1449 | ||
1450 | fmdev = (struct fmdev *)arg; | 1450 | fmdev = (struct fmdev *)arg; |
1451 | 1451 | ||
1452 | if (skb == NULL) { | 1452 | if (skb == NULL) { |
1453 | fmerr("Invalid SKB received from ST\n"); | 1453 | fmerr("Invalid SKB received from ST\n"); |
1454 | return -EFAULT; | 1454 | return -EFAULT; |
1455 | } | 1455 | } |
1456 | 1456 | ||
1457 | if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) { | 1457 | if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) { |
1458 | fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb); | 1458 | fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb); |
1459 | return -EINVAL; | 1459 | return -EINVAL; |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | memcpy(skb_push(skb, 1), &skb->cb[0], 1); | 1462 | memcpy(skb_push(skb, 1), &skb->cb[0], 1); |
1463 | skb_queue_tail(&fmdev->rx_q, skb); | 1463 | skb_queue_tail(&fmdev->rx_q, skb); |
1464 | tasklet_schedule(&fmdev->rx_task); | 1464 | tasklet_schedule(&fmdev->rx_task); |
1465 | 1465 | ||
1466 | return 0; | 1466 | return 0; |
1467 | } | 1467 | } |
1468 | 1468 | ||
1469 | /* | 1469 | /* |
1470 | * Called by ST layer to indicate protocol registration completion | 1470 | * Called by ST layer to indicate protocol registration completion |
1471 | * status. | 1471 | * status. |
1472 | */ | 1472 | */ |
1473 | static void fm_st_reg_comp_cb(void *arg, char data) | 1473 | static void fm_st_reg_comp_cb(void *arg, char data) |
1474 | { | 1474 | { |
1475 | struct fmdev *fmdev; | 1475 | struct fmdev *fmdev; |
1476 | 1476 | ||
1477 | fmdev = (struct fmdev *)arg; | 1477 | fmdev = (struct fmdev *)arg; |
1478 | fmdev->streg_cbdata = data; | 1478 | fmdev->streg_cbdata = data; |
1479 | complete(&wait_for_fmdrv_reg_comp); | 1479 | complete(&wait_for_fmdrv_reg_comp); |
1480 | } | 1480 | } |
1481 | 1481 | ||
1482 | /* | 1482 | /* |
1483 | * This function will be called from FM V4L2 open function. | 1483 | * This function will be called from FM V4L2 open function. |
1484 | * Register with ST driver and initialize driver data. | 1484 | * Register with ST driver and initialize driver data. |
1485 | */ | 1485 | */ |
1486 | u32 fmc_prepare(struct fmdev *fmdev) | 1486 | u32 fmc_prepare(struct fmdev *fmdev) |
1487 | { | 1487 | { |
1488 | static struct st_proto_s fm_st_proto; | 1488 | static struct st_proto_s fm_st_proto; |
1489 | u32 ret; | 1489 | u32 ret; |
1490 | 1490 | ||
1491 | if (test_bit(FM_CORE_READY, &fmdev->flag)) { | 1491 | if (test_bit(FM_CORE_READY, &fmdev->flag)) { |
1492 | fmdbg("FM Core is already up\n"); | 1492 | fmdbg("FM Core is already up\n"); |
1493 | return 0; | 1493 | return 0; |
1494 | } | 1494 | } |
1495 | 1495 | ||
1496 | memset(&fm_st_proto, 0, sizeof(fm_st_proto)); | 1496 | memset(&fm_st_proto, 0, sizeof(fm_st_proto)); |
1497 | fm_st_proto.type = ST_FM; | ||
1498 | fm_st_proto.recv = fm_st_receive; | 1497 | fm_st_proto.recv = fm_st_receive; |
1499 | fm_st_proto.match_packet = NULL; | 1498 | fm_st_proto.match_packet = NULL; |
1500 | fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb; | 1499 | fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb; |
1501 | fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */ | 1500 | fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */ |
1502 | fm_st_proto.priv_data = fmdev; | 1501 | fm_st_proto.priv_data = fmdev; |
1502 | fm_st_proto.chnl_id = 0x08; | ||
1503 | fm_st_proto.max_frame_size = 0xff; | ||
1504 | fm_st_proto.hdr_len = 1; | ||
1505 | fm_st_proto.offset_len_in_hdr = 0; | ||
1506 | fm_st_proto.len_size = 1; | ||
1507 | fm_st_proto.reserve = 1; | ||
1503 | 1508 | ||
1504 | ret = st_register(&fm_st_proto); | 1509 | ret = st_register(&fm_st_proto); |
1505 | if (ret == -EINPROGRESS) { | 1510 | if (ret == -EINPROGRESS) { |
1506 | init_completion(&wait_for_fmdrv_reg_comp); | 1511 | init_completion(&wait_for_fmdrv_reg_comp); |
1507 | fmdev->streg_cbdata = -EINPROGRESS; | 1512 | fmdev->streg_cbdata = -EINPROGRESS; |
1508 | fmdbg("%s waiting for ST reg completion signal\n", __func__); | 1513 | fmdbg("%s waiting for ST reg completion signal\n", __func__); |
1509 | 1514 | ||
1510 | ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, | 1515 | ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, |
1511 | FM_ST_REG_TIMEOUT); | 1516 | FM_ST_REG_TIMEOUT); |
1512 | 1517 | ||
1513 | if (!ret) { | 1518 | if (!ret) { |
1514 | fmerr("Timeout(%d sec), didn't get reg " | 1519 | fmerr("Timeout(%d sec), didn't get reg " |
1515 | "completion signal from ST\n", | 1520 | "completion signal from ST\n", |
1516 | jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); | 1521 | jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); |
1517 | return -ETIMEDOUT; | 1522 | return -ETIMEDOUT; |
1518 | } | 1523 | } |
1519 | if (fmdev->streg_cbdata != 0) { | 1524 | if (fmdev->streg_cbdata != 0) { |
1520 | fmerr("ST reg comp CB called with error " | 1525 | fmerr("ST reg comp CB called with error " |
1521 | "status %d\n", fmdev->streg_cbdata); | 1526 | "status %d\n", fmdev->streg_cbdata); |
1522 | return -EAGAIN; | 1527 | return -EAGAIN; |
1523 | } | 1528 | } |
1524 | 1529 | ||
1525 | ret = 0; | 1530 | ret = 0; |
1526 | } else if (ret == -1) { | 1531 | } else if (ret == -1) { |
1527 | fmerr("st_register failed %d\n", ret); | 1532 | fmerr("st_register failed %d\n", ret); |
1528 | return -EAGAIN; | 1533 | return -EAGAIN; |
1529 | } | 1534 | } |
1530 | 1535 | ||
1531 | if (fm_st_proto.write != NULL) { | 1536 | if (fm_st_proto.write != NULL) { |
1532 | g_st_write = fm_st_proto.write; | 1537 | g_st_write = fm_st_proto.write; |
1533 | } else { | 1538 | } else { |
1534 | fmerr("Failed to get ST write func pointer\n"); | 1539 | fmerr("Failed to get ST write func pointer\n"); |
1535 | ret = st_unregister(ST_FM); | 1540 | ret = st_unregister(&fm_st_proto); |
1536 | if (ret < 0) | 1541 | if (ret < 0) |
1537 | fmerr("st_unregister failed %d\n", ret); | 1542 | fmerr("st_unregister failed %d\n", ret); |
1538 | return -EAGAIN; | 1543 | return -EAGAIN; |
1539 | } | 1544 | } |
1540 | 1545 | ||
1541 | spin_lock_init(&fmdev->rds_buff_lock); | 1546 | spin_lock_init(&fmdev->rds_buff_lock); |
1542 | spin_lock_init(&fmdev->resp_skb_lock); | 1547 | spin_lock_init(&fmdev->resp_skb_lock); |
1543 | 1548 | ||
1544 | /* Initialize TX queue and TX tasklet */ | 1549 | /* Initialize TX queue and TX tasklet */ |
1545 | skb_queue_head_init(&fmdev->tx_q); | 1550 | skb_queue_head_init(&fmdev->tx_q); |
1546 | tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev); | 1551 | tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev); |
1547 | 1552 | ||
1548 | /* Initialize RX Queue and RX tasklet */ | 1553 | /* Initialize RX Queue and RX tasklet */ |
1549 | skb_queue_head_init(&fmdev->rx_q); | 1554 | skb_queue_head_init(&fmdev->rx_q); |
1550 | tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev); | 1555 | tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev); |
1551 | 1556 | ||
1552 | fmdev->irq_info.stage = 0; | 1557 | fmdev->irq_info.stage = 0; |
1553 | atomic_set(&fmdev->tx_cnt, 1); | 1558 | atomic_set(&fmdev->tx_cnt, 1); |
1554 | fmdev->resp_comp = NULL; | 1559 | fmdev->resp_comp = NULL; |
1555 | 1560 | ||
1556 | init_timer(&fmdev->irq_info.timer); | 1561 | init_timer(&fmdev->irq_info.timer); |
1557 | fmdev->irq_info.timer.function = &int_timeout_handler; | 1562 | fmdev->irq_info.timer.function = &int_timeout_handler; |
1558 | fmdev->irq_info.timer.data = (unsigned long)fmdev; | 1563 | fmdev->irq_info.timer.data = (unsigned long)fmdev; |
1559 | /*TODO: add FM_STIC_EVENT later */ | 1564 | /*TODO: add FM_STIC_EVENT later */ |
1560 | fmdev->irq_info.mask = FM_MAL_EVENT; | 1565 | fmdev->irq_info.mask = FM_MAL_EVENT; |
1561 | 1566 | ||
1562 | /* Region info */ | 1567 | /* Region info */ |
1563 | memcpy(&fmdev->rx.region, ®ion_configs[default_radio_region], | 1568 | memcpy(&fmdev->rx.region, ®ion_configs[default_radio_region], |
1564 | sizeof(struct region_info)); | 1569 | sizeof(struct region_info)); |
1565 | 1570 | ||
1566 | fmdev->rx.mute_mode = FM_MUTE_OFF; | 1571 | fmdev->rx.mute_mode = FM_MUTE_OFF; |
1567 | fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF; | 1572 | fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF; |
1568 | fmdev->rx.rds.flag = FM_RDS_DISABLE; | 1573 | fmdev->rx.rds.flag = FM_RDS_DISABLE; |
1569 | fmdev->rx.freq = FM_UNDEFINED_FREQ; | 1574 | fmdev->rx.freq = FM_UNDEFINED_FREQ; |
1570 | fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS; | 1575 | fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS; |
1571 | fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF; | 1576 | fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF; |
1572 | fmdev->irq_info.retry = 0; | 1577 | fmdev->irq_info.retry = 0; |
1573 | 1578 | ||
1574 | fm_rx_reset_rds_cache(fmdev); | 1579 | fm_rx_reset_rds_cache(fmdev); |
1575 | init_waitqueue_head(&fmdev->rx.rds.read_queue); | 1580 | init_waitqueue_head(&fmdev->rx.rds.read_queue); |
1576 | 1581 | ||
1577 | fm_rx_reset_station_info(fmdev); | 1582 | fm_rx_reset_station_info(fmdev); |
1578 | set_bit(FM_CORE_READY, &fmdev->flag); | 1583 | set_bit(FM_CORE_READY, &fmdev->flag); |
1579 | 1584 | ||
1580 | return ret; | 1585 | return ret; |
1581 | } | 1586 | } |
1582 | 1587 | ||
1583 | /* | 1588 | /* |
1584 | * This function will be called from FM V4L2 release function. | 1589 | * This function will be called from FM V4L2 release function. |
1585 | * Unregister from ST driver. | 1590 | * Unregister from ST driver. |
1586 | */ | 1591 | */ |
1587 | u32 fmc_release(struct fmdev *fmdev) | 1592 | u32 fmc_release(struct fmdev *fmdev) |
1588 | { | 1593 | { |
1594 | static struct st_proto_s fm_st_proto; | ||
1589 | u32 ret; | 1595 | u32 ret; |
1590 | 1596 | ||
1591 | if (!test_bit(FM_CORE_READY, &fmdev->flag)) { | 1597 | if (!test_bit(FM_CORE_READY, &fmdev->flag)) { |
1592 | fmdbg("FM Core is already down\n"); | 1598 | fmdbg("FM Core is already down\n"); |
1593 | return 0; | 1599 | return 0; |
1594 | } | 1600 | } |
1595 | /* Sevice pending read */ | 1601 | /* Sevice pending read */ |
1596 | wake_up_interruptible(&fmdev->rx.rds.read_queue); | 1602 | wake_up_interruptible(&fmdev->rx.rds.read_queue); |
1597 | 1603 | ||
1598 | tasklet_kill(&fmdev->tx_task); | 1604 | tasklet_kill(&fmdev->tx_task); |
1599 | tasklet_kill(&fmdev->rx_task); | 1605 | tasklet_kill(&fmdev->rx_task); |
1600 | 1606 | ||
1601 | skb_queue_purge(&fmdev->tx_q); | 1607 | skb_queue_purge(&fmdev->tx_q); |
1602 | skb_queue_purge(&fmdev->rx_q); | 1608 | skb_queue_purge(&fmdev->rx_q); |
1603 | 1609 | ||
1604 | fmdev->resp_comp = NULL; | 1610 | fmdev->resp_comp = NULL; |
1605 | fmdev->rx.freq = 0; | 1611 | fmdev->rx.freq = 0; |
1606 | 1612 | ||
1607 | ret = st_unregister(ST_FM); | 1613 | memset(&fm_st_proto, 0, sizeof(fm_st_proto)); |
1614 | fm_st_proto.chnl_id = 0x08; | ||
1615 | |||
1616 | ret = st_unregister(&fm_st_proto); | ||
1617 | |||
1608 | if (ret < 0) | 1618 | if (ret < 0) |
1609 | fmerr("Failed to de-register FM from ST %d\n", ret); | 1619 | fmerr("Failed to de-register FM from ST %d\n", ret); |
1610 | else | 1620 | else |
1611 | fmdbg("Successfully unregistered from ST\n"); | 1621 | fmdbg("Successfully unregistered from ST\n"); |
1612 | 1622 | ||
1613 | clear_bit(FM_CORE_READY, &fmdev->flag); | 1623 | clear_bit(FM_CORE_READY, &fmdev->flag); |
1614 | return ret; | 1624 | return ret; |
1615 | } | 1625 | } |
1616 | 1626 | ||
1617 | /* | 1627 | /* |
1618 | * Module init function. Ask FM V4L module to register video device. | 1628 | * Module init function. Ask FM V4L module to register video device. |
1619 | * Allocate memory for FM driver context and RX RDS buffer. | 1629 | * Allocate memory for FM driver context and RX RDS buffer. |
1620 | */ | 1630 | */ |
1621 | static int __init fm_drv_init(void) | 1631 | static int __init fm_drv_init(void) |
1622 | { | 1632 | { |
1623 | struct fmdev *fmdev = NULL; | 1633 | struct fmdev *fmdev = NULL; |
1624 | u32 ret = -ENOMEM; | 1634 | u32 ret = -ENOMEM; |
1625 | 1635 | ||
1626 | fmdbg("FM driver version %s\n", FM_DRV_VERSION); | 1636 | fmdbg("FM driver version %s\n", FM_DRV_VERSION); |
1627 | 1637 | ||
1628 | fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL); | 1638 | fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL); |
1629 | if (NULL == fmdev) { | 1639 | if (NULL == fmdev) { |
1630 | fmerr("Can't allocate operation structure memory\n"); | 1640 | fmerr("Can't allocate operation structure memory\n"); |
1631 | return ret; | 1641 | return ret; |
1632 | } | 1642 | } |
1633 | fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE; | 1643 | fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE; |
1634 | fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL); | 1644 | fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL); |
1635 | if (NULL == fmdev->rx.rds.buff) { | 1645 | if (NULL == fmdev->rx.rds.buff) { |
1636 | fmerr("Can't allocate rds ring buffer\n"); | 1646 | fmerr("Can't allocate rds ring buffer\n"); |
1637 | goto rel_dev; | 1647 | goto rel_dev; |
1638 | } | 1648 | } |
1639 | 1649 | ||
1640 | ret = fm_v4l2_init_video_device(fmdev, radio_nr); | 1650 | ret = fm_v4l2_init_video_device(fmdev, radio_nr); |
1641 | if (ret < 0) | 1651 | if (ret < 0) |
1642 | goto rel_rdsbuf; | 1652 | goto rel_rdsbuf; |
1643 | 1653 | ||
1644 | fmdev->irq_info.handlers = int_handler_table; | 1654 | fmdev->irq_info.handlers = int_handler_table; |
1645 | fmdev->curr_fmmode = FM_MODE_OFF; | 1655 | fmdev->curr_fmmode = FM_MODE_OFF; |
1646 | fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF; | 1656 | fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF; |
1647 | fmdev->tx_data.preemph = FM_TX_PREEMPH_50US; | 1657 | fmdev->tx_data.preemph = FM_TX_PREEMPH_50US; |
1648 | return ret; | 1658 | return ret; |
1649 | 1659 | ||
1650 | rel_rdsbuf: | 1660 | rel_rdsbuf: |
1651 | kfree(fmdev->rx.rds.buff); | 1661 | kfree(fmdev->rx.rds.buff); |
1652 | rel_dev: | 1662 | rel_dev: |
1653 | kfree(fmdev); | 1663 | kfree(fmdev); |
1654 | 1664 | ||
1655 | return ret; | 1665 | return ret; |
1656 | } | 1666 | } |
1657 | 1667 | ||
1658 | /* Module exit function. Ask FM V4L module to unregister video device */ | 1668 | /* Module exit function. Ask FM V4L module to unregister video device */ |
1659 | static void __exit fm_drv_exit(void) | 1669 | static void __exit fm_drv_exit(void) |
1660 | { | 1670 | { |
1661 | struct fmdev *fmdev = NULL; | 1671 | struct fmdev *fmdev = NULL; |
1662 | 1672 | ||
1663 | fmdev = fm_v4l2_deinit_video_device(); | 1673 | fmdev = fm_v4l2_deinit_video_device(); |
1664 | if (fmdev != NULL) { | 1674 | if (fmdev != NULL) { |
1665 | kfree(fmdev->rx.rds.buff); | 1675 | kfree(fmdev->rx.rds.buff); |
1666 | kfree(fmdev); | 1676 | kfree(fmdev); |
1667 | } | 1677 | } |
1668 | } | 1678 | } |
1669 | 1679 | ||
1670 | module_init(fm_drv_init); | 1680 | module_init(fm_drv_init); |
1671 | module_exit(fm_drv_exit); | 1681 | module_exit(fm_drv_exit); |
1672 | 1682 | ||
1673 | /* ------------- Module Info ------------- */ | 1683 | /* ------------- Module Info ------------- */ |
1674 | MODULE_AUTHOR("Manjunatha Halli <manjunatha_halli@ti.com>"); | 1684 | MODULE_AUTHOR("Manjunatha Halli <manjunatha_halli@ti.com>"); |
1675 | MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION); | 1685 | MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION); |
1676 | MODULE_VERSION(FM_DRV_VERSION); | 1686 | MODULE_VERSION(FM_DRV_VERSION); |
1677 | MODULE_LICENSE("GPL"); | 1687 | MODULE_LICENSE("GPL"); |