OSDN Git Service

[POWER] Wait correct time on idle(), idle_time_ms().
[openi2cradio/OpenI2CRadio.git] / akc6955.c
1 /*
2  * OpenI2CRADIO
3  * RADIO CHIP AKC6955 Handler
4  * Copyright (C) 2013-06-10 K.Ohta <whatisthis.sowhat ai gmail.com>
5  * License: GPL2+LE
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2,
10  *  or (at your option) any later version.
11  *  This library / program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  *  See the GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this library; see the file COPYING. If not, write to the
18  *  Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  *
21  *  As a special exception, if you link this(includeed from sdcc) library
22  *  with other files, some of which are compiled with SDCC,
23  *  to produce an executable, this library does not by itself cause
24  *  the resulting executable to be covered by the GNU General Public License.
25  *  This exception does not however invalidate any other reasons why
26  *  the executable file might be covered by the GNU General Public License.
27  */
28
29 #include <stdarg.h>
30 #include <stdio.h>
31 #ifdef __SDCC
32 #include <delay.h>
33 #else
34 #include <xc.h>
35 #endif
36 #include <string.h>
37 #include "akc6955.h"
38 #include "i2c_io.h"
39 #include "idle.h"
40 #include "power.h"
41 #include "commondef.h"
42 #include "menu.h"
43
44 void akc6955_writecmd(unsigned char reg, unsigned char data)
45 {
46 #ifdef __SDCC
47     i2c_open(I2C_MASTER, I2C_SLEW_ON, 5);
48     I2C_START();
49     i2c_writechar(0x20);
50     i2c_writechar(reg);
51     i2c_writechar(data);
52     I2C_STOP();
53     i2c_close();
54     delay100tcy(2);
55 #else
56     OpenI2C(MASTER, SLEW_ON);
57     SSPADD = 0x5;
58 //    IdleI2C();
59     StartI2C();
60     WriteI2C(0x20);
61     //delay1ktcy(8);
62     WriteI2C(reg);
63     //delay1ktcy(8);
64     WriteI2C(data);
65     //delay1ktcy(8);
66     StopI2C();
67  //   delay1ktcy(8);
68     CloseI2C();
69 #endif  //    i2c_idle();
70 }
71
72 unsigned char akc6955_readcmd(unsigned char reg)
73 {
74     unsigned char c;
75     //    OPENASMASTER();
76 #ifdef __SDCC
77     i2c_open(I2C_MASTER, I2C_SLEW_ON, 5);
78     I2C_START();
79     i2c_writechar(0x20);
80     i2c_writechar(reg);
81     I2C_STOP();
82     delay100tcy(2);
83     I2C_START();
84     i2c_writechar(0x21);
85     c = i2c_readchar();
86     I2C_ACK();
87     I2C_STOP();
88     i2c_close();
89 #else
90     OpenI2C(MASTER, SLEW_ON);
91     SSPADD = 0x5;
92 //    IdleI2C();
93     StartI2C();
94     WriteI2C(0x20);
95   //  delay1ktcy(8);
96     WriteI2C(reg);
97   //  delay1ktcy(8);
98     StopI2C();
99     __delay_us(13);
100     StartI2C();
101     WriteI2C(0x21);
102   //  delay1ktcy(8);
103     c = ReadI2C();
104     AckI2C();
105     StopI2C();
106  //   delay1ktcy(8);
107     CloseI2C();
108 #endif
109     //    CLOSEASMASTER();
110
111     return c;
112 }
113
114 void akc6955_chg_fm(unsigned char f, unsigned int freq)
115 {
116     __bitops_t b;
117     b.byte = akc6955_readcmd(AKC6955_POWER);
118     b.b6 = 0;
119     if(f != 0){
120         b.b6 = 1;
121         akc6955_set_fmband(fmband);
122         akc6955_writecmd(AKC6955_POWER, b.byte);
123         akc6955_set_freq(freq);
124         return;
125     }
126     akc6955_writecmd(AKC6955_POWER, b.byte);
127     akc6955_set_amband(amband);
128     akc6955_set_freq(freq);
129
130 }
131
132 unsigned char akc6955_get_fm(void)
133 {
134     __bitops_t b;
135     b.byte = akc6955_readcmd(AKC6955_POWER);
136     if(b.b6){
137         return 0xff;
138     }
139     return 0;
140 }
141
142
143 void akc6955_set_amband(unsigned char band)
144 {
145     unsigned char b;
146     unsigned char c;
147
148     c = RFAMP_SW;
149     if((band < AKC6955_BAND_SW1) || (band == AKC6955_BAND_MW4)) {
150         c = RFAMP_MWLW;
151     }
152     rfamp_power(c);
153     b = akc6955_readcmd(AKC6955_BAND);
154     b &= 0x07; // extract FM
155     b = b | ((band & 0x1f) << 3);
156     akc6955_writecmd(AKC6955_BAND, b);
157     akc6955_do_tune();
158 }
159
160 void akc6955_set_fmband(unsigned char band)
161 {
162     unsigned char b;
163     rfamp_power(RFAMP_FM);
164     b = akc6955_readcmd(AKC6955_BAND);
165     b &= 0xf8; // extract AM
166     b = b | (band & 0x07);
167     akc6955_writecmd(AKC6955_BAND, b);
168     akc6955_do_tune();
169 }
170
171 unsigned char akc6955_get_band(void)
172 {
173     return akc6955_readcmd(AKC6955_BAND);
174 }
175
176
177 void akc6955_set_power(unsigned char on)
178 {
179     __bitops_t b;
180     b.byte = akc6955_readcmd(AKC6955_POWER);
181     b.b7 = 0;
182     if(on != 0){
183         b.b7 = 1;
184     }
185     akc6955_writecmd(AKC6955_POWER, b.byte);
186 }
187
188 void akc6955_do_tune(void)
189 {
190     __bitops_t b;
191     b.byte = akc6955_readcmd(AKC6955_POWER);
192     b.b5 = 0; // Tun = '0'
193     b.b4 = 0; // Force abort scan.
194     akc6955_writecmd(AKC6955_POWER, b.byte);
195     idle_time_ms(1);
196     // Need sleep?-> Need! this sequence re                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 fer from reference code.
197     b.b5= 1; // Tun = '1'
198     akc6955_writecmd(AKC6955_POWER, b.byte);
199     idle_time_ms(1);
200     b.b5 = 0;
201     akc6955_writecmd(AKC6955_POWER, b.byte);
202     idle_time_ms(8);
203 }
204
205 unsigned char akc6955_tune(void)
206 {
207     __bitops_t b;
208     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
209     if(b.b5) {
210         return 0xff;
211     }
212     return 0;
213 }
214
215
216 void akc6955_mode3k(unsigned char flag)
217 {
218     __bitops_t b;
219     b.byte = akc6955_readcmd(AKC6955_CH_HI);
220     b.b5 = 0;
221     if(flag != 0){
222         b.b5 = 1;
223     }
224     akc6955_writecmd(AKC6955_CH_HI, b.byte);
225     akc6955_do_tune();
226     _AKC6955_WAIT_62_5MS();
227 }
228
229 void akc6955_set_tune(unsigned char mode_3k, unsigned int ch)
230 {
231     unsigned char band;
232     __bitops_t f;
233     __bitops_t b;
234     unsigned int i = ch;
235     unsigned char comp;
236
237     do { // Wait for before completed
238         comp = akc6955_chk_donescan();
239         idle_time_35ms();
240     } while(comp == 0x00);
241     f.byte = akc6955_readcmd(AKC6955_POWER);
242     band = 0;
243     if(!f.b6){
244         akc6955_get_amband(band);
245     }
246
247     if(band == AKC6955_BAND_MW2){
248         // BAND=AM && MW2
249         i = ch / 3; // On MW2, Channnel must be multiple of 3.
250         i = i * 3; // i = (i/3) * 3
251     }
252     if(i > 0x1fff) i = 0x1fff;
253     //i = ch & 0x1fff;
254
255     b.byte = i & 0xff;
256     akc6955_writecmd(AKC6955_CH_LO, b.byte);
257
258     b.byte = i >> 8;
259     b.b6 = 1;
260     if(mode_3k != 0){
261         b.b5 = 1; // Mode 3K ON
262     }
263     akc6955_writecmd(AKC6955_CH_HI, b.byte);
264
265     akc6955_do_tune();
266 }
267
268 void akc6955_do_scan(unsigned char up)
269 {
270     __bitops_t b;
271  //   akc6955_do_tune();
272     b.byte = akc6955_readcmd(AKC6955_POWER);
273     b.b3 = 0;
274     b.b4 = 0;
275     b.b5 = 0;
276     akc6955_writecmd(AKC6955_POWER, b.byte);
277     b.b5 = 1; // Tune 0->1.
278     idle_time_35ms();
279     akc6955_writecmd(AKC6955_POWER, b.byte);
280     idle_time_35ms();
281     if(up != 0) {
282         b.b3= 1;
283     }
284     b.b4 = 1;
285     akc6955_writecmd(AKC6955_POWER, b.byte); // Raise seek bit to '1'.
286 }
287
288 void akc6955_abort_scan(void)
289 {
290     unsigned char b;
291     b = akc6955_readcmd(AKC6955_POWER);
292     b &= 0xef;
293     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
294 }
295
296 void akc6955_set_scanrate_fm(unsigned char rate)
297 {
298     unsigned char c;
299     c = akc6955_readcmd(AKC6955_SPACE);
300     c = (c & 0xcf) | ((rate & 0x03) << 4);
301     akc6955_writecmd(AKC6955_SPACE, c);
302 }
303
304 unsigned char akc6955_chk_donescan(void)
305 {
306     __bitops_t b;
307     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
308     if(b.b6){
309         return 0xff;
310     }
311     return 0;
312 }
313
314 unsigned int akc6955_get_channel(void)
315 {
316     unsigned char h, l;
317     unsigned int u;
318     l = akc6955_readcmd(AKC6955_RCH_LO) ;
319     h = akc6955_readcmd(AKC6955_RCH_HI) & 0x1f;
320     u = (h << 8) | l;
321     return u;
322 }
323
324 /*
325  * Get AM/FM Frequency: ret = KHz at AM, 10KHz @FM.
326  */
327 unsigned int akc6955_get_freq(void)
328 {
329     __bitops_t f, b;
330     unsigned int i;
331     unsigned int freq;
332     unsigned char band;
333
334     f.byte = akc6955_readcmd(AKC6955_POWER);
335     i = akc6955_get_channel();
336     if(f.b6){ // 25KHz
337         freq = (i * 5) / 2 + 3000; // freq' = 25*i[KHz] = (25 / 10) *i [10KHz]
338     } else { // 5K
339        b.byte = akc6955_readcmd(AKC6955_CH_HI);
340        akc6955_get_amband(band);
341        freq = i * 5;
342        if((band == AKC6955_BAND_MW2) || (b.b5)){
343            freq = i * 3;
344        }
345     }
346     return freq;
347 }
348
349 void akc6955_set_freq(unsigned int freq)
350 {
351     unsigned int ch;
352     __bitops_t f;
353     __bitops_t mode3k;
354     unsigned char band;
355     unsigned int start, stop;
356
357     f.byte = akc6955_readcmd(AKC6955_POWER);
358     if(f.b6) { // FM
359         akc6955_get_fmband(band);
360 //        band &= 7;
361         if(band == AKC6955_BAND_FMUSER){
362             start = fm_usrbands[fm_userbandnum].start * 32;
363             stop = fm_usrbands[fm_userbandnum].stop * 32;
364         } else {
365             start = fmbands[band].start;
366             stop = fmbands[band].end;
367         }
368         ch = freq - 3000;
369         ch = (ch << 2) / 10;
370     } else {
371         akc6955_get_amband(band);
372 //        if(band >= AKC6955_BAND_AMEND) band = AKC6955_BAND_AMEND - 1;
373         if(band == AKC6955_BAND_AMUSER){
374             start = am_usrbands[am_userbandnum].start * 32;
375             stop = am_usrbands[am_userbandnum].stop * 32;
376         } else {
377             start = ambands[band].start;
378             stop = ambands[band].end;
379         }
380         mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
381         if(band == AKC6955_BAND_MW2) {
382             ch = (freq / 9) * 3; // See datasheet.
383         } else if(band == AKC6955_BAND_MW3) {
384             ch = freq / 5;
385         } else  if(mode3k.b7){
386             ch = freq / 3;
387         } else {
388             ch = freq / 5;
389         }
390     }
391     if(freq <  start) freq = start;
392     if(freq >= stop)   freq = stop - 1;
393     akc6955_set_tune(mode3k.b7, ch);
394 }
395
396 void akc6955_set_userband(unsigned char start, unsigned char stop, unsigned int ch, unsigned char mode3k)
397 {
398     __bitops_t f;
399
400     f.byte = akc6955_readcmd(AKC6955_POWER);
401     akc6955_writecmd(AKC6955_UCH_ST, start);
402     akc6955_writecmd(AKC6955_UCH_EN, stop);
403     if(f.b6){
404         akc6955_set_fmband(AKC6955_BAND_FMUSER);
405     } else {
406         akc6955_set_amband(AKC6955_BAND_AMUSER);
407     }
408     akc6955_set_tune(mode3k, ch);
409 }
410
411
412 unsigned char akc6955_get_cnr(void)
413 {
414     __bitops_t f;
415     __bitops_t b;
416     f.byte = akc6955_readcmd(AKC6955_POWER);
417     if(f.b6) { // FM
418         b.byte = akc6955_readcmd(AKC6955_CNR_FM);
419     } else { // AM
420         b.byte = akc6955_readcmd(AKC6955_CNR_AM);
421     }
422     b.b7 = 0;
423     return b.byte;
424 }
425
426 int akc6955_read_level(void)
427 {
428     __bitops_t f;
429     unsigned char rflevel, iflevel;
430     unsigned char b;
431     int rssi;
432     unsigned int freq;
433     int totallevel;
434     int level;
435
436     f.byte = akc6955_readcmd(AKC6955_POWER);
437     b =  akc6955_readcmd(AKC6955_PGALEVEL);
438     rflevel = (b & 0xe0) >> 5;
439     iflevel = (b & 0x1c) >> 2;
440     totallevel = rflevel + iflevel;
441
442     rssi = (int)(akc6955_readcmd(AKC6955_RSSI) & 0x7f);
443     // totallevel = rssi + 6*totallevel;
444     level = (int)(totallevel * 6 + rssi);
445     if(f.b6){
446         level = 103 - level; // totallevel * 6
447     } else {
448         freq = akc6955_get_freq();
449         if(freq > 2560) { // ASSUME SW
450             level = 103 - level;
451         } else { // ASSUME MW,LW
452             level = 123 - level;
453         }
454     }
455     return level;
456 }
457
458
459 // Get diff. unit = 100Hz.
460 int akc6955_get_diff(void)
461 {
462     __bitops_t diff;
463     __bitops_t f;
464     int n;
465
466     diff.byte = akc6955_readcmd(AKC6955_FDNUM);
467     if(diff.b7) {
468         diff.b7 = 0;
469         n = -((int) diff.byte);
470     } else {
471         diff.b7 = 0;
472         n = (int)diff.byte;
473     }
474
475     f.byte = akc6955_readcmd(AKC6955_POWER);
476     if(f.b6) { // FM
477         return n * 10;
478     }
479     return n; // 10n
480 }
481
482 void akc6955_up_freq(unsigned int step)
483 {
484     unsigned int freq;
485     __bitops_t mode3k;
486
487     freq = akc6955_get_channel();
488     freq += step;
489     mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
490     akc6955_set_tune(mode3k.b7, freq);
491 }
492
493
494 void akc6955_down_freq(unsigned int step)
495 {
496     unsigned int freq;
497     __bitops_t mode3k;
498
499     freq = akc6955_get_channel();
500     if(freq <= step) return;
501     freq -= step;
502     mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
503     akc6955_set_tune(mode3k.b7, freq);
504 }
505
506 void akc6955_setvolumemode(unsigned char flag)
507 {
508     __bitops_t c;
509     c.byte = akc6955_readcmd(AKC6955_ENABLE);
510     c.b3 = 0;
511     if(flag != 0x00){
512         c.b3 = 1;
513     }
514     akc6955_writecmd(AKC6955_ENABLE, c.byte);
515 }
516
517 unsigned char akc6955_getvolumemode(void)
518 {
519     __bitops_t c;
520     c.byte = akc6955_readcmd(AKC6955_ENABLE);
521     if(c.b3){
522         return 0xff;
523     }
524     return 0;
525 }
526
527 void akc6955_setvolume(unsigned char level)
528 {
529 //    unsigned char c;
530 //    c = akc6955_readcmd(AKC6955_VOLUME) & 0x03;
531     if(level > 63) level = 63;
532     akc6955_writecmd(AKC6955_VOLUME, ((akc6955_readcmd(AKC6955_VOLUME) & 0x03) | (level << 2)));
533 }
534
535 unsigned char akc6955_getvolume(void)
536 {
537     unsigned char c;
538     c = akc6955_readcmd(AKC6955_VOLUME) >> 2;
539     return c;
540 }
541
542 void akc6955_set_prevolume(unsigned char level)
543 {
544     unsigned char c;
545     c = akc6955_readcmd(AKC6955_PRE) & 0xf3;
546     c |= ((level & 0x03) << 2);
547     akc6955_writecmd(AKC6955_PRE, c);
548 }
549
550 unsigned char akc6955_get_prevolume(void)
551 {
552     unsigned char c;
553     c = akc6955_readcmd(AKC6955_PRE) & 0x0c;
554     c >>= 2;
555     return c;
556 }
557
558
559 void akc6955_setphase(unsigned char flag)
560 {
561     __bitops_t c;
562     c.byte = akc6955_readcmd(AKC6955_VOLUME);
563
564     c.b0 = 1;
565     if(flag == 0) {
566         c.b0 = 0; //
567     }
568     akc6955_writecmd(AKC6955_VOLUME, c.byte);
569 }
570
571 void akc6955_setline(unsigned char flag)
572 {
573     __bitops_t c;
574     c.byte = akc6955_readcmd(AKC6955_VOLUME);
575     c.b1 = 1;
576     if(flag == 0) {
577         c.b1 = 0;
578     }
579     akc6955_writecmd(AKC6955_VOLUME, c.byte);
580 }
581
582 void akc6955_set_lowboost(unsigned char flag)
583 {
584     __bitops_t c;
585     c.byte = akc6955_readcmd(AKC6955_STEREO);
586     c.b3 = 1;
587     if(flag == 0) {
588         c.b3 = 0;
589     }
590     akc6955_writecmd(AKC6955_STEREO, c.byte);
591 }
592
593 void akc6955_set_stereomode(unsigned char mode)
594 {
595     unsigned char c;
596     c = akc6955_readcmd(AKC6955_STEREO);
597     mode = (mode & 0x03) << 2;
598     c = (c & 0xf3) | mode;
599     akc6955_writecmd(AKC6955_STEREO, c);
600 }
601
602 unsigned char akc6955_get_stereo(void)
603 {
604     unsigned char c;
605     c = akc6955_readcmd(AKC6955_RCH_HI) & 0x80;
606     return c;
607 }
608
609 /*
610  * Get battery level.
611  * Unit = 0.01V
612  */
613
614 unsigned int akc6955_get_battery(void)
615 {
616     unsigned int batt;
617     unsigned char c;
618     c = akc6955_readcmd(AKC6955_VBAT) & 0x3f;
619     batt = 180 + c * 5;
620     return batt;
621 }
622
623 void akc6955_set_thresh_fmstereo(unsigned char a)
624 {
625     unsigned char b;
626     a = a & 0x03;
627     threshold_fmstereo = a;
628     b = akc6955_readcmd(AKC6955_THRESH) & 0xfc;
629     akc6955_writecmd(AKC6955_THRESH, a | b);
630 }
631
632 void akc6955_set_thresh_width(unsigned char a)
633 {
634     unsigned char b;
635     a = a & 0x03;
636     threshold_width = a;
637     a = a << 2; // << 2
638     b = akc6955_readcmd(AKC6955_THRESH) & 0xf3;;
639     akc6955_writecmd(AKC6955_THRESH, a | b);
640 }
641
642 void akc6955_set_thresh_amcnr(unsigned char a)
643 {
644     unsigned char b;
645     a = a & 0x03;
646     threshold_amcnr = a;
647     a = a << 4; // << 4
648     b = akc6955_readcmd(AKC6955_THRESH) & 0xcf;
649     akc6955_writecmd(AKC6955_THRESH, a | b);
650 }
651
652 void akc6955_set_thresh_fmcnr(unsigned char a)
653 {
654     unsigned char b;
655     a = a & 0x03;
656     threshold_fmcnr = a;
657     a = a << 6; // << 4
658     b = akc6955_readcmd(AKC6955_THRESH) & 0x3f;
659     akc6955_writecmd(AKC6955_THRESH, a | b);
660 }