OSDN Git Service

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