iap: pass length and data pointer to iap_handlepkt functions, this prepares for iap...
[kugel-rb.git] / firmware / drivers / tuner / ipod_remote_tuner.c
blobad84cb9890b44a932d4af996e62b8386a3e8f61c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * tuner for the ipod fm remote and other ipod remote tuners
11 * Copyright (C) 2009 Laurent Gautier
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include "kernel.h"
28 #include "iap.h"
29 #include "tuner.h" /* tuner abstraction interface */
30 #include "adc.h"
31 #include "settings.h"
32 #include "power.h"
34 static bool powered = false;
36 static unsigned char tuner_param = 0x00, old_tuner_param = 0xFF;
37 /* temp var for tests to avoid looping execution in submenus settings*/
38 static int mono_mode = -1, old_region = -1;
40 int radio_present = 0;
42 static int tuner_frequency = 0;
43 static int tuner_signal_power = 0;
44 static bool radio_tuned = false;
45 static bool rds_event = false;
47 static char rds_radioname[9];
48 static char rds_radioinfo[65];
50 static void rmt_tuner_signal_power(unsigned char value)
52 tuner_signal_power = (int)(value);
55 void rmt_tuner_freq(unsigned int len, const unsigned char *buf)
57 /* length currently unused */
58 (void)len;
60 unsigned int khz = (buf[2] << 24) | (buf[3] << 16) |
61 (buf[4] << 8) | buf[5];
62 tuner_frequency = khz *1000 ;
63 radio_tuned = true;
64 rmt_tuner_signal_power(buf[6]);
67 static void rmt_tuner_set_freq(int curr_freq)
69 if (curr_freq != tuner_frequency)
71 radio_tuned = false;
72 tuner_signal_power = 0;
73 /* clear rds name and info */
74 memset(rds_radioname,' ',sizeof(rds_radioname));
75 memset(rds_radioinfo,' ',sizeof(rds_radioinfo));
76 /* ex: 00 01 63 14 = 90.9MHz */
77 unsigned char data[] = {0x07, 0x0B, 0x00, 0x01, 0x63, 0x14};
79 if (curr_freq != 0)
81 unsigned int khz = curr_freq / 1000;
82 data[2] = (khz >> 24) & 0xFF;
83 data[3] = (khz >> 16) & 0xFF;
84 data[4] = (khz >> 8) & 0xFF;
85 data[5] = (khz >> 0) & 0xFF;
86 iap_send_pkt(data, sizeof(data));
91 static void rmt_tuner_sleep(int state)
93 if (state == 0)
95 tuner_param = 0x00;
96 old_tuner_param = 0xFF;
97 mono_mode = -1;
98 old_region = -1;
99 tuner_frequency = 0;
100 radio_tuned = false;
102 /* tuner HW on */
103 const unsigned char data[] = {0x07, 0x05, 0x01};
104 iap_send_pkt(data, sizeof(data));
105 /* boost gain */
106 const unsigned char data1[] = {0x07, 0x24, 0x06 };
107 iap_send_pkt(data1, sizeof(data1));
108 /* set volume */
109 unsigned char data2[] = {0x03, 0x09, 0x04, 0x00, 0x00 };
110 data2[4] = (char)((global_settings.volume+58) * 4);
111 iap_send_pkt(data2, sizeof(data2));
112 /* set rds on */
113 const unsigned char data3[] = {0x07, 0x20, 0x40, 0x00, 0x00, 0x10 };
114 iap_send_pkt(data3, sizeof(data3));
116 else
118 /* unbooste gain */
119 const unsigned char data[] = {0x07, 0x24, 0x00};
120 iap_send_pkt(data, sizeof(data));
121 /* set rds off */
122 const unsigned char data1[] = {0x07, 0x20, 0x00, 0x00, 0x00, 0x00 };
123 iap_send_pkt(data1, sizeof(data1));
124 /* stop tuner HW */
125 const unsigned char data2[] = {0x07, 0x05, 0x00};
126 iap_send_pkt(data2, sizeof(data2));
130 static void rmt_tuner_scan(int param)
132 const unsigned char data[] = {0x07, 0x11, 0x08}; /* RSSI level */
133 unsigned char updown = 0x00;
134 radio_tuned = false;
135 iap_send_pkt(data, sizeof(data));
137 if (param == 1)
139 updown = 0x07; /* scan up */
141 else if (param == -1)
143 updown = 0x08; /* scan down */
145 else if (param == 10)
147 updown = 0x01; /* scan up starting from beginning of the band */
149 unsigned char data1[] = {0x07, 0x12, updown};
150 iap_send_pkt(data1, sizeof(data1));
153 #if 0 /* function is not used */
154 static void rmt_tuner_mute(int value)
156 /* mute flag off (play) */
157 unsigned char data[] = {0x03, 0x09, 0x03, 0x01};
158 if (value)
160 /* mute flag on (pause) */
161 data[3] = 0x02;
163 iap_send_pkt(data, sizeof(data));
165 #endif
167 static void rmt_tuner_region(int region)
169 if (region != old_region)
171 const struct fm_region_data *rd = &fm_region_data[region];
172 unsigned char data[] = {0x07, 0x08, 0x00};
173 if (rd->freq_min == 76000000)
175 data[2] = 0x02; /* japan band */
177 else
179 data[2] = 0x01; /* us eur band */
181 iap_send_pkt(data, sizeof(data));
182 sleep(HZ/100);
183 old_region = region;
187 /* set stereo/mono, deemphasis, delta freq... */
188 static void rmt_tuner_set_param(unsigned char tuner_param)
190 if(tuner_param != old_tuner_param)
192 unsigned char data[] = {0x07, 0x0E, 0x00};
194 data[2] = tuner_param;
195 iap_send_pkt(data, sizeof(data));
196 old_tuner_param = tuner_param;
200 static void set_deltafreq(int delta)
202 tuner_param &= 0xFC;
203 switch (delta)
205 case 1:
207 /* 100KHz */
208 tuner_param |= 0x01;
209 break;
211 case 2:
213 /* 50KHz */
214 tuner_param |= 0x02;
215 break;
218 default:
220 /* 200KHz */
221 tuner_param |= 0x00;
222 break;
227 static void set_deemphasis(int deemphasis)
229 tuner_param &= 0xBF;
230 switch (deemphasis)
232 case 1:
234 tuner_param |= 0x40;
235 break;
237 default:
239 tuner_param |= 0x00;
240 break;
245 static void set_mono(int value)
247 tuner_param &= 0xEF;
249 if (value != mono_mode)
251 tuner_param &= 0xEF;
252 if (value == 1)
253 tuner_param |= 0x10;
254 rmt_tuner_set_param(tuner_param);
255 sleep(HZ/100);
256 mono_mode = value;
260 static bool reply_timeout(void)
262 int timeout = 0;
264 sleep(HZ/50);
267 iap_handlepkt();
268 sleep(HZ/50);
269 timeout++;
271 while((ipod_rmt_tuner_get(RADIO_TUNED) == 0) && (timeout < TIMEOUT_VALUE));
273 return (timeout >= TIMEOUT_VALUE);
276 void rmt_tuner_rds_data(unsigned int len, const unsigned char *buf)
278 if (buf[2] == 0x1E)
280 strlcpy(rds_radioname,buf+4,8);
282 else if(buf[2] == 0x04)
284 strlcpy(rds_radioinfo,buf+4,len-4);
286 rds_event = true;
289 /* tuner abstraction layer: set something to the tuner */
290 int ipod_rmt_tuner_set(int setting, int value)
292 switch(setting)
294 case RADIO_SLEEP:
296 rmt_tuner_sleep(value);
297 sleep(HZ/10);
298 if(value)
300 tuner_frequency = 0;
302 break;
305 case RADIO_FREQUENCY:
307 rmt_tuner_set_freq(value);
308 if (reply_timeout())
309 return 0;
310 break;
313 case RADIO_SCAN_FREQUENCY:
315 const struct fm_region_data * const fmr =
316 &fm_region_data[global_settings.fm_region];
318 /* case: scan for presets, back to beginning of the band */
319 if (radio_tuned && (value == fmr->freq_min))
321 tuner_set(RADIO_FREQUENCY,value);
324 /* scan through frequencies */
325 if (radio_tuned)
327 if ((tuner_frequency <= fmr->freq_min)
328 && (tuner_frequency >= fmr->freq_max))
330 tuner_set(RADIO_FREQUENCY,value);
332 /* scan down */
333 if(value < tuner_frequency)
334 rmt_tuner_scan(-1);
335 /* scan up */
336 else
337 rmt_tuner_scan(1);
339 sleep(HZ/10);
340 if (reply_timeout())
342 tuner_set(RADIO_FREQUENCY,value);
343 rmt_tuner_scan(1);
344 if (reply_timeout() == true)
345 return 0;
347 radio_tuned = false;
350 if (tuner_frequency == value)
352 radio_tuned = true;
353 return 1;
355 else
357 radio_tuned = false;
358 return 0;
362 case RADIO_MUTE:
364 /* mute flag sent to accessory */
365 /* rmt_tuner_mute(value); */
366 break;
369 case RADIO_REGION:
371 const struct fm_region_data *rd = &fm_region_data[value];
372 int band = (rd->freq_min == 76000000) ? 2 : 0;
373 int spacing = (100000 / rd->freq_step);
374 int deemphasis = (rd->deemphasis == 50) ? 1 : 0;
376 rmt_tuner_region(band);
377 set_deltafreq(spacing);
378 set_deemphasis(deemphasis);
379 rmt_tuner_set_param(tuner_param);
380 break;
383 case RADIO_FORCE_MONO:
385 set_mono(value);
386 break;
389 default:
390 return -1;
392 return 1;
395 /* tuner abstraction layer: read something from the tuner */
396 int ipod_rmt_tuner_get(int setting)
398 int val = -1; /* default for unsupported query */
400 switch(setting)
402 case RADIO_PRESENT:
403 val = radio_present;
404 if (val)
406 /* if accessory disconnected */
407 if(adc_read(ADC_ACCESSORY) >= 10)
409 radio_present = 0;
410 val = 0;
413 break;
415 /* radio tuned: yes no */
416 case RADIO_TUNED:
417 val = 0;
418 if (radio_tuned)
419 val = 1;
420 break;
422 /* radio is always stereo */
423 /* we can't know when it's in mono mode, depending of signal quality */
424 /* except if it is forced in mono mode */
425 case RADIO_STEREO:
426 val = true;
427 break;
429 case RADIO_EVENT:
430 if (rds_event)
432 val = 1;
433 rds_event = false;
435 break;
437 return val;
440 char* ipod_get_rds_info(int setting)
442 char *text = NULL;
444 switch(setting)
446 case RADIO_RDS_NAME:
447 text = rds_radioname;
448 break;
450 case RADIO_RDS_TEXT:
451 text = rds_radioinfo;
452 break;
454 return text;
457 bool tuner_power(bool status)
459 bool oldstatus = powered;
460 powered = status;
461 return oldstatus;