OSDN Git Service

[Schematic] Change coil of SW-PRE-AMP, issue of low-gain @higher freq.
[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
43 void akc6955_writecmd(unsigned char reg, unsigned char data)
44 {
45 #ifdef __SDCC
46     i2c_open(I2C_MASTER, I2C_SLEW_ON, 5);
47     I2C_START();
48     i2c_writechar(0x20);
49     i2c_writechar(reg);
50     i2c_writechar(data);
51     I2C_STOP();
52     i2c_close();
53     delay100tcy(2);
54 #else
55     OpenI2C(MASTER, SLEW_OFF);
56     StartI2C();
57     WriteI2C(0x20);
58     //delay1ktcy(8);
59     WriteI2C(reg);
60     //delay1ktcy(8);
61     WriteI2C(data);
62     //delay1ktcy(8);
63     StopI2C();
64  //   delay1ktcy(8);
65     CloseI2C();
66 //    CLOSEASMASTER();
67 #endif  //    i2c_idle();
68 }
69
70 unsigned char akc6955_readcmd(unsigned char reg)
71 {
72     unsigned char c;
73     //    OPENASMASTER();
74 #ifdef __SDCC
75     i2c_open(I2C_MASTER, I2C_SLEW_ON, 5);
76 #else
77     OpenI2C(MASTER, SLEW_OFF);
78 #endif
79 #ifdef __SDCC
80     I2C_START();
81     i2c_writechar(0x20);
82     i2c_writechar(reg);
83     I2C_STOP();
84     delay100tcy(2);
85     I2C_START();
86     i2c_writechar(0x21);
87     c = i2c_readchar();
88     I2C_ACK();
89     I2C_STOP();
90     i2c_close();
91 #else
92     StartI2C();
93     WriteI2C(0x20);
94   //  delay1ktcy(8);
95     WriteI2C(reg);
96   //  delay1ktcy(8);
97     StopI2C();
98     __delay_us(13);
99     StartI2C();
100     WriteI2C(0x21);
101   //  delay1ktcy(8);
102     c = ReadI2C();
103     AckI2C();
104     StopI2C();
105  //   delay1ktcy(8);
106     CloseI2C();
107 #endif
108     //    CLOSEASMASTER();
109
110     return c;
111 }
112
113 void akc6955_chg_fm(unsigned char f, unsigned int freq)
114 {
115     __bitops_t b;
116     unsigned char c;
117     b.byte = akc6955_readcmd(AKC6955_POWER);
118     b.b6 = 0;
119     if(f != 0){
120         rfamp_power(RFAMP_FM);
121         b.b6 = 1;
122         akc6955_set_fmband(fmband);
123         akc6955_writecmd(AKC6955_POWER, b.byte);
124         akc6955_set_freq(freq);
125         return;
126     }
127     c = RFAMP_SW;
128     if((amband < AKC6955_BAND_SW1) || (amband == AKC6955_BAND_MW4)) {
129         c = RFAMP_MWLW;
130     }
131     rfamp_power(c);
132     akc6955_writecmd(AKC6955_POWER, b.byte);
133     akc6955_set_amband(amband);
134     akc6955_set_freq(freq);
135
136 }
137
138 unsigned char akc6955_get_fm(void)
139 {
140     __bitops_t b;
141     b.byte = akc6955_readcmd(AKC6955_POWER);
142     if(b.b6){
143         return 0xff;
144     }
145     return 0;
146 }
147
148
149 void akc6955_set_amband(unsigned char band)
150 {
151     unsigned char b;
152     b = akc6955_readcmd(AKC6955_BAND);
153     b &= 0x07; // extract FM
154     b = b | ((band & 0x1f) << 3);
155     akc6955_writecmd(AKC6955_BAND, b);
156     akc6955_do_tune();
157 }
158
159 void akc6955_set_fmband(unsigned char band)
160 {
161     unsigned char b;
162     b = akc6955_readcmd(AKC6955_BAND);
163     b &= 0xf8; // extract AM
164     b = b | (band & 0x07);
165     akc6955_writecmd(AKC6955_BAND, b);
166     akc6955_do_tune();
167 }
168
169 unsigned char akc6955_get_band(void)
170 {
171     return akc6955_readcmd(AKC6955_BAND);
172 }
173
174
175 void akc6955_set_power(unsigned char on)
176 {
177     __bitops_t b;
178     b.byte = akc6955_readcmd(AKC6955_POWER);
179     b.b7 = 0;
180     if(on != 0){
181         b.b7 = 1;
182     }
183     akc6955_writecmd(AKC6955_POWER, b.byte);
184 }
185
186 void akc6955_do_tune(void)
187 {
188     __bitops_t b;
189     b.byte = akc6955_readcmd(AKC6955_POWER);
190     b.b5 = 0; // Tun = '0'
191     b.b4 = 0; // Force abort scan.
192     akc6955_writecmd(AKC6955_POWER, b.byte);
193     idle_time_ms(1);
194     // Need sleep?-> Need! this sequence re                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 fer from reference code.
195     b.b5= 1; // Tun = '1'
196     akc6955_writecmd(AKC6955_POWER, b.byte);
197     idle_time_ms(1);
198     b.b5 = 0;
199     akc6955_writecmd(AKC6955_POWER, b.byte);
200     idle_time_ms(8);
201 }
202
203 unsigned char akc6955_tune(void)
204 {
205     __bitops_t b;
206     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
207     if(b.b5) {
208         return 0xff;
209     }
210     return 0;
211 }
212
213
214 void akc6955_mode3k(unsigned char flag)
215 {
216     __bitops_t b;
217     b.byte = akc6955_readcmd(AKC6955_CH_HI);
218     b.b5 = 0;
219     if(flag != 0){
220         b.b5 = 1;
221     }
222     akc6955_writecmd(AKC6955_CH_HI, b.byte);
223     akc6955_do_tune();
224     _AKC6955_WAIT_62_5MS();
225 }
226
227 void akc6955_set_tune(unsigned char mode_3k, unsigned int ch)
228 {
229     unsigned char band;
230     __bitops_t f;
231     __bitops_t b;
232     unsigned int i = ch;
233     unsigned char comp;
234
235     do { // Wait for before completed
236         comp = akc6955_chk_donescan();
237         idle_time_35ms();
238     } while(comp == 0x00);
239     f.byte = akc6955_readcmd(AKC6955_POWER);
240     band = 0;
241     if(f.b6 == 0){
242         akc6955_get_amband(band);
243     }
244
245     if(band == AKC6955_BAND_MW2){
246         // BAND=AM && MW2
247         i = ch / 3; // On MW2, Channnel must be multiple of 3.
248         i = i * 3; // i = (i/3) * 3
249     }
250     if(i > 0x1fff) i = 0x1fff;
251     //i = ch & 0x1fff;
252
253     b.byte = i & 0xff;
254     akc6955_writecmd(AKC6955_CH_LO, b.byte);
255
256     b.byte = i >> 8;
257     b.b6 = 1;
258     if(mode_3k != 0){
259         b.b5 = 1; // Mode 3K ON
260     }
261     akc6955_writecmd(AKC6955_CH_HI, b.byte);
262
263     akc6955_do_tune();
264 }
265
266 void akc6955_do_scan(unsigned char up)
267 {
268     __bitops_t b;
269  //   akc6955_do_tune();
270     b.byte = akc6955_readcmd(AKC6955_POWER);
271     b.b3 = 0;
272     b.b4 = 0;
273     b.b5 = 0;
274     akc6955_writecmd(AKC6955_POWER, b.byte);
275     b.b5 = 1; // Tune 0->1.
276     idle_time_35ms();
277     akc6955_writecmd(AKC6955_POWER, b.byte);
278     idle_time_35ms();
279     if(up != 0) {
280         b.b3= 1;
281     }
282     b.b4 = 1;
283     akc6955_writecmd(AKC6955_POWER, b.byte); // Raise seek bit to '1'.
284 }
285
286 void akc6955_abort_scan(void)
287 {
288     unsigned char b;
289     b = akc6955_readcmd(AKC6955_POWER);
290     b &= 0xef;
291     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
292 }
293
294 void akc6955_set_scanrate_fm(unsigned char rate)
295 {
296     unsigned char c;
297     c = akc6955_readcmd(AKC6955_SPACE);
298     c = (c & 0xcf) | ((rate & 0x03) << 4);
299     akc6955_writecmd(AKC6955_SPACE, c);
300 }
301
302 unsigned char akc6955_chk_donescan(void)
303 {
304     __bitops_t b;
305     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
306     if(b.b6){
307         return 0xff;
308     }
309     return 0;
310 }
311
312 unsigned int akc6955_get_channel(void)
313 {
314     unsigned char h, l;
315     unsigned int u;
316     l = akc6955_readcmd(AKC6955_RCH_LO) ;
317     h = akc6955_readcmd(AKC6955_RCH_HI) & 0x1f;
318     u = (h << 8) | l;
319     return u;
320 }
321
322 /*
323  * Get AM/FM Frequency: ret = KHz at AM, 10KHz @FM.
324  */
325 unsigned int akc6955_get_freq(void)
326 {
327     __bitops_t f, b;
328     unsigned int i;
329     unsigned int freq;
330     unsigned char band;
331
332     f.byte = akc6955_readcmd(AKC6955_POWER);
333     i = akc6955_get_channel();
334     if(f.b6){ // 25KHz
335         freq = (i * 5) / 2 + 3000; // freq' = 25*i[KHz] = (25 / 10) *i [10KHz]
336     } else { // 5K
337        b.byte = akc6955_readcmd(AKC6955_CH_HI);
338        akc6955_get_amband(band);
339        freq = i * 5;
340        if((band == AKC6955_BAND_MW2) || (b.b5)){
341            freq = i * 3;
342        }
343     }
344     return freq;
345 }
346
347 void akc6955_set_freq(unsigned int freq)
348 {
349     unsigned int ch;
350     __bitops_t f;
351     __bitops_t mode3k;
352     unsigned char band;
353     unsigned int start, stop;
354
355     f.byte = akc6955_readcmd(AKC6955_POWER);
356     if(f.b6) { // FM
357         akc6955_get_fmband(band);
358 //        band &= 7;
359         if(band == AKC6955_BAND_FMUSER){
360             start = fm_usrbands[fm_userbandnum].start * 32;
361             stop = fm_usrbands[fm_userbandnum].stop * 32;
362         } else {
363             start = fmbands[band].start;
364             stop = fmbands[band].end;
365         }
366         ch = freq - 3000;
367         ch = (ch * 4) / 10;
368     } else {
369         akc6955_get_amband(band);
370 //        if(band >= AKC6955_BAND_AMEND) band = AKC6955_BAND_AMEND - 1;
371         if(band == AKC6955_BAND_AMUSER){
372             start = am_usrbands[am_userbandnum].start * 32;
373             stop = am_usrbands[am_userbandnum].stop * 32;
374         } else {
375             start = ambands[band].start;
376             stop = ambands[band].end;
377         }
378         mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
379         if(band == AKC6955_BAND_MW2) {
380             ch = (freq / 9) * 3; // See datasheet.
381         } else if(band == AKC6955_BAND_MW3) {
382             ch = freq / 5;
383         } else  if(mode3k.b7){
384             ch = freq / 3;
385         } else {
386             ch = freq / 5;
387         }
388     }
389     if(freq <  start) freq = start;
390     if(freq >= stop)   freq = stop - 1;
391     akc6955_set_tune(mode3k.b7, ch);
392 }
393
394 void akc6955_set_userband(unsigned char start, unsigned char stop, unsigned int ch, unsigned char mode3k)
395 {
396     __bitops_t f;
397
398     f.byte = akc6955_readcmd(AKC6955_POWER);
399     akc6955_writecmd(AKC6955_UCH_ST, start);
400     akc6955_writecmd(AKC6955_UCH_EN, stop);
401     if(f.b6){
402         akc6955_set_fmband(AKC6955_BAND_FMUSER);
403     } else {
404         akc6955_set_amband(AKC6955_BAND_AMUSER);
405     }
406     akc6955_set_tune(mode3k, ch);
407 }
408
409
410 unsigned char akc6955_get_cnr(void)
411 {
412     __bitops_t f;
413     __bitops_t b;
414     f.byte = akc6955_readcmd(AKC6955_POWER);
415     if(f.b6) { // FM
416         b.byte = akc6955_readcmd(AKC6955_CNR_FM);
417     } else { // AM
418         b.byte = akc6955_readcmd(AKC6955_CNR_AM);
419     }
420     b.b7 = 0;
421     return b.byte;
422 }
423
424 int akc6955_read_level(void)
425 {
426     __bitops_t f;
427     unsigned char rflevel, iflevel;
428     unsigned char b;
429     int rssi;
430     unsigned int freq;
431     int totallevel;
432     int level;
433
434     f.byte = akc6955_readcmd(AKC6955_POWER);
435     b =  akc6955_readcmd(AKC6955_PGALEVEL);
436     rflevel = (b & 0xe0) >> 5;
437     iflevel = (b & 0x1c) >> 2;
438     totallevel = rflevel + iflevel;
439
440     rssi = (int)(akc6955_readcmd(AKC6955_RSSI) & 0x7f);
441     // totallevel = rssi + 6*totallevel;
442     level = (int)(totallevel * 6 + rssi);
443     if(f.b6){
444         level = 103 - level; // totallevel * 6
445     } else {
446         freq = akc6955_get_freq();
447         if(freq > 2560) { // ASSUME SW
448             level = 103 - level;
449         } else { // ASSUME MW,LW
450             level = 123 - level;
451         }
452     }
453     return level;
454 }
455
456
457 // Get diff. unit = 100Hz.
458 int akc6955_get_diff(void)
459 {
460     __bitops_t diff;
461     __bitops_t f;
462     int n;
463
464     diff.byte = akc6955_readcmd(AKC6955_FDNUM);
465     if(diff.b7) {
466         diff.b7 = 0;
467         n = -((int) diff.byte);
468     } else {
469         diff.b7 = 0;
470         n = (int)diff.byte;
471     }
472
473     f.byte = akc6955_readcmd(AKC6955_POWER);
474     if(f.b6) { // FM
475         return n * 10;
476     }
477     return n; // 10n
478 }
479
480 void akc6955_up_freq(unsigned int step)
481 {
482     unsigned int freq;
483     __bitops_t mode3k;
484
485     freq = akc6955_get_channel();
486     freq += step;
487     mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
488     akc6955_set_tune(mode3k.b7, freq);
489 }
490
491
492 void akc6955_down_freq(unsigned int step)
493 {
494     unsigned int freq;
495     __bitops_t mode3k;
496
497     freq = akc6955_get_channel();
498     if(freq <= step) return;
499     freq -= step;
500     mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
501     akc6955_set_tune(mode3k.b7, freq);
502 }
503
504 void akc6955_setvolumemode(unsigned char flag)
505 {
506     __bitops_t c;
507     c.byte = akc6955_readcmd(AKC6955_ENABLE);
508     c.b3 = 0;
509     if(flag != 0x00){
510         c.b3 = 1;
511     }
512     akc6955_writecmd(AKC6955_ENABLE, c.byte);
513 }
514
515 unsigned char akc6955_getvolumemode(void)
516 {
517     __bitops_t c;
518     c.byte = akc6955_readcmd(AKC6955_ENABLE);
519     if(c.b3){
520         return 0xff;
521     }
522     return 0;
523 }
524
525 void akc6955_setvolume(unsigned char level)
526 {
527 //    unsigned char c;
528 //    c = akc6955_readcmd(AKC6955_VOLUME) & 0x03;
529     if(level > 63) level = 63;
530     akc6955_writecmd(AKC6955_VOLUME, ((akc6955_readcmd(AKC6955_VOLUME) & 0x03) | (level << 2)));
531 }
532
533 unsigned char akc6955_getvolume(void)
534 {
535     unsigned char c;
536     c = akc6955_readcmd(AKC6955_VOLUME) >> 2;
537     return c;
538 }
539
540 void akc6955_set_prevolume(unsigned char level)
541 {
542     unsigned char c;
543     c = akc6955_readcmd(AKC6955_PRE) & 0xf3;
544     c |= ((level & 0x03) << 2);
545     akc6955_writecmd(AKC6955_PRE, c);
546 }
547
548 unsigned char akc6955_get_prevolume(void)
549 {
550     unsigned char c;
551     c = akc6955_readcmd(AKC6955_PRE) & 0x0c;
552     c >>= 2;
553     return c;
554 }
555
556
557 void akc6955_setphase(unsigned char flag)
558 {
559     __bitops_t c;
560     c.byte = akc6955_readcmd(AKC6955_VOLUME);
561
562     c.b0 = 0;
563     if(flag != 0) {
564         c.b0 = 1; //
565     }
566     akc6955_writecmd(AKC6955_VOLUME, c.byte);
567 }
568
569 void akc6955_setline(unsigned char flag)
570 {
571     __bitops_t c;
572     c.byte = akc6955_readcmd(AKC6955_VOLUME);
573     c.b1 = 0;
574     if(flag != 0) {
575         c.b1 = 1;
576     }
577     akc6955_writecmd(AKC6955_VOLUME, c.byte);
578 }
579
580 void akc6955_set_lowboost(unsigned char flag)
581 {
582     __bitops_t c;
583     c.byte = akc6955_readcmd(AKC6955_STEREO);
584     c.b3 = 0;
585     if(flag != 0) {
586         c.b3 = 1;
587     }
588     akc6955_writecmd(AKC6955_STEREO, c.byte);
589 }
590
591 void akc6955_set_stereomode(unsigned char mode)
592 {
593     unsigned char c;
594     c = akc6955_readcmd(AKC6955_STEREO);
595     mode = (mode & 0x03) << 2;
596     c = (c & 0xf3) | mode;
597     akc6955_writecmd(AKC6955_STEREO, c);
598 }
599
600 unsigned char akc6955_get_stereo(void)
601 {
602     unsigned char c;
603     c = akc6955_readcmd(AKC6955_RCH_HI) & 0x80;
604     return c;
605 }
606
607 /*
608  * Get battery level.
609  * Unit = 0.01V
610  */
611
612 unsigned int akc6955_get_battery(void)
613 {
614     unsigned int batt;
615     unsigned char c;
616     c = akc6955_readcmd(AKC6955_VBAT) & 0x3f;
617     batt = 180 + c * 5;
618     return batt;
619 }
620