OSDN Git Service

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