OSDN Git Service

4d6dabfb1f6d10d0786d442ff45154f25d56a3c7
[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 #include <delay.h>
32 #include <string.h>
33 #include "akc6955.h"
34 #include "i2c_io.h"
35 #include "idle.h"
36
37
38 void akc6955_writecmd(unsigned char reg, unsigned char data)
39 {
40     i2c_idle();
41     OPENASMASTER();
42     i2c_writechar(AKC6955_ADDRESS);
43     i2c_writechar(reg);
44     i2c_writechar(data);
45     CLOSEASMASTER();
46 }
47
48 unsigned char akc6955_readcmd(unsigned char reg)
49 {
50     unsigned char c;
51     i2c_idle();
52     OPENASMASTER();
53     i2c_writechar(AKC6955_ADDRESS);
54     i2c_writechar(reg);
55     c = i2c_readchar();
56     CLOSEASMASTER();
57     return c;
58 }
59
60
61 void akc6955_chg_fm(unsigned char fm)
62 {
63     unsigned char b;
64     b = akc6955_readcmd(AKC6955_POWER);
65     if(fm != 0){
66         b |= 0x40;
67     } else {
68         b &= 0xbf;
69     }
70     akc6955_writecmd(AKC6955_POWER, b);
71 }
72
73 void akc6955_set_amband(unsigned char band)
74 {
75     unsigned char b;
76     b = akc6955_readcmd(AKC6955_BAND);
77     b &= 0x07; // extract FM
78     b = b | ((band & 0x1f) << 3);
79     akc6955_writecmd(AKC6955_BAND, b);
80 }
81
82 void akc6955_set_fmband(unsigned char band)
83 {
84     unsigned char b;
85     b = akc6955_readcmd(AKC6955_BAND);
86     b &= 0xf8; // extract AM
87     b = b | (band & 0x07);
88     akc6955_writecmd(AKC6955_BAND, b);
89 }
90
91 unsigned char akc6955_get_amband(void)
92 {
93     unsigned char b;
94     b = akc6955_readcmd(AKC6955_BAND);
95     b = (b & 0xf8) >> 3;
96     return b;
97 }
98
99 unsigned char akc6955_get_fmband(void)
100 {
101     unsigned char b;
102     b = akc6955_readcmd(AKC6955_BAND);
103     b = b & 0x07;
104     return b;
105 }
106
107 void akc6955_set_power(unsigned char on)
108 {
109     unsigned char b;
110     b = akc6955_readcmd(AKC6955_POWER);
111     if(on != 0){
112         b |= 0x80;
113     } else {
114         b &= 0x7f;
115     }
116     akc6955_writecmd(AKC6955_POWER, b);
117 }
118
119 void akc6955_do_tune(void)
120 {
121     unsigned char b;
122     b = akc6955_readcmd(AKC6955_POWER);
123     b &= 0xdf; // Tun = '0'
124     akc6955_writecmd(AKC6955_POWER, b);
125     // Need sleep?
126     b |= 0x20; // Tun = '1'
127     akc6955_writecmd(AKC6955_POWER, b);
128 }
129
130 unsigned char akc6955_tune(void)
131 {
132     unsigned char b;
133     b = akc6955_readcmd(AKC6955_RCH_HI) & 0x20;
134     if(b == 0x00) {
135         return 0;
136     } else {
137         return 0xff;
138     }
139 }
140
141
142 unsigned int akc6955_mode3k(unsigned char flag)
143 {
144     unsigned char b;
145     b = akc6955_readcmd(AKC6955_CH_HI);
146     if(flag != 0){
147         b |= 0x20;
148     } else {
149         b &= 0xdf;
150     }
151     akc6955_writecmd(AKC6955_CH_HI, b);
152 //    akc6955_do_tune();
153     _AKC6955_WAIT_62_5MS();
154     return akc6955_get_freq();
155 }
156
157 void akc6955_set_tune(unsigned char mode_3k, unsigned int ch)
158 {
159     unsigned char band;
160     unsigned char fm;
161     unsigned char b;
162     unsigned int i;
163     unsigned int mod;
164
165     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
166     if(fm == 0){
167         // AM
168         band = akc6955_get_amband();
169     } else {
170         band = 0;
171     }
172     if(band == 2){
173         // BAND=AM && MW2
174         i = i / 3; // On MW2, Channnel must be multiple of 3.
175         i = (i << 1) + i; // i = (i/3) * 3
176     }
177     if(i > 0x1fff) i = 0x1fff;
178     //i = ch & 0x1fff;
179
180     if(mode_3k == 0){
181         b = ((i >> 8) & 0x1f) | 0x40; // 32.768KHz clock
182     } else {
183         b = ((i >> 8) & 0x1f) | 0x60;
184     }
185     akc6955_writecmd(AKC6955_CH_HI, b);
186     b = i & 0xff;
187     akc6955_writecmd(AKC6955_CH_LO, b);
188     akc6955_do_tune();
189     do{
190         // Use software-delay, but recommands hardware-delay ;-(
191         //_AKC6955_WAIT_12_5MS();
192         idle(65535 - 100 + 1); // 0.128 * 100 = 12.8ms
193     } while(akc6955_tune() == 0);
194 }
195
196 void akc6955_do_scan(unsigned char up)
197 {
198     unsigned char b;
199     akc6955_do_tune();
200     b = akc6955_readcmd(AKC6955_POWER);
201     b &= 0xe3;
202     if(up != 0) {
203         b |= 0x08;
204     }
205     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
206     b |= 0x10;
207     akc6955_writecmd(AKC6955_POWER, b); // Raise seek bit to '1'.
208 }
209
210 void akc6955_abort_scan(void)
211 {
212     unsigned char b;
213     b = akc6955_readcmd(AKC6955_POWER);
214     b &= 0xef;
215     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
216 }
217
218 void akc6955_set_scanrate_fm(unsigned char rate)
219 {
220     unsigned char c;
221     c = akc6955_readcmd(AKC6955_SPACE);
222     c = (c & 0xcf) | ((rate & 0x03) << 4);
223     akc6955_writecmd(AKC6955_SPACE, c);
224 }
225
226 unsigned char akc6955_chk_donescan(void)
227 {
228     unsigned char b;
229     b = akc6955_readcmd(AKC6955_RCH_HI) & 0x40;
230     if(b == 0) return 0;
231     return 0xff;
232 }
233
234
235 /*
236  * Get AM/FM Frequency: ret = KHz at AM, 10KHz @FM.
237  */
238 unsigned int akc6955_get_freq(void)
239 {
240     unsigned char b, h, l;
241     unsigned char fm;
242     unsigned int i;
243     unsigned int freq;
244
245     b = akc6955_readcmd(AKC6955_CNR_AM) & 0x80;
246     l = akc6955_readcmd(AKC6955_RCH_LO) ;
247     h = akc6955_readcmd(AKC6955_RCH_HI) & 0x1f;
248     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
249     i = l + (h << 8);
250     if(fm != 0){ // 25KHz
251         freq = i << 1 + i >> 1 + 3000; // freq' = 25*i[KHz] = (25 / 10) *i [10KHz]
252                                        // = 2.5i[10KHz]
253                                        // freq = freq' + 30MHz = freq' + 3000[10KHz]
254     } else { // 5K
255        if(b == 0) { // 5KHz
256            freq = i << 2 + i; // freq = 5*i[KHz] = (4+1)*i[KHz]
257         } else { // 3KHz
258            freq = i << 1 + i; // freq = 3i[KHz] = (2+1)i[KHz]
259         }
260     }
261     return freq;
262 }
263
264 void akc6955_set_freq(unsigned int freq)
265 {
266     unsigned int ch;
267     unsigned char fm;
268     unsigned char mode3k = 0;
269
270     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
271     if(fm != 0) { // FM
272       ch = freq - 3000;
273       ch = ch << 2;
274       ch = ch / 10; // 10/25 = 0.4
275     } else {
276         mode3k = akc6955_readcmd(AKC6955_CNR_AM) & 0x80;
277         if(mode3k == 0){
278             ch = freq / 5;
279         } else {
280             ch = freq / 3;
281         }
282     }
283     akc6955_set_tune(mode3k, ch);
284 }
285
286 void akc6955_set_userband(unsigned char start, unsigned char stop, unsigned int ch, unsigned char mode3k)
287 {
288     unsigned char fm;
289     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
290     akc6955_writecmd(AKC6955_UCH_ST, start);
291     akc6955_writecmd(AKC6955_UCH_EN, stop);
292     if(fm == 0){
293         akc6955_set_amband(AKC6955_BAND_AMUSER);
294     } else {
295         akc6955_set_fmband(AKC6955_BAND_FMUSER);
296     }
297     akc6955_set_tune(mode3k, ch);
298 }
299
300
301 unsigned char akc6955_get_cnr(void)
302 {
303     unsigned char fm;
304     unsigned char b;
305     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
306     if(fm != 0) { // FM
307         b = akc6955_readcmd(AKC6955_CNR_FM);
308     } else { // AM
309         b = akc6955_readcmd(AKC6955_CNR_AM);
310     }
311     b &= 0x7f;
312     return b;
313 }
314
315 int akc6955_read_level(void)
316 {
317     unsigned char fm;
318     unsigned char rflevel, iflevel;
319     unsigned char b;
320     unsigned int rssi;
321     unsigned int freq;
322     unsigned int totallevel;
323     int level;
324
325     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
326     b =  akc6955_readcmd(AKC6955_PGALEVEL);
327     rflevel = (b & 0xe0) >> 5;
328     iflevel = (b & 0x1c) >> 2;
329     totallevel = rflevel + iflevel;
330
331     rssi = (unsigned int)(akc6955_readcmd(AKC6955_RSSI) & 0x7f);
332     // totallevel = rssi + 6*totallevel;
333     level = (int)((totallevel << 2) + (totallevel << 1) + rssi);
334     if(fm != 0){
335         level = 103 - level; // totallevel * 6
336     } else {
337         freq = akc6955_get_freq();
338         if(freq > 2560) { // ASSUME SW
339             level = 103 - level;
340         } else { // ASSUME MW,LW
341             level = 123 - level;
342         }
343     }
344     return level;
345 }
346
347 // Get diff. unit = 100Hz.
348 int akc6955_get_diff(void)
349 {
350     unsigned char diff;
351     unsigned char fm;
352     int n;
353     diff = akc6955_readcmd(AKC6955_FDNUM);
354     if(diff  <= 127) {
355         n = (int)diff & 0x007f;
356     } else {
357         n = -((int)(diff & 0x007f));
358     }
359     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
360     if(fm == 0) { // AM
361         return n;
362     } else {
363         return (n << 3 + n << 1); // 10n
364     }
365 }
366
367 unsigned int akc6955_up_freq(unsigned int step)
368 {
369     unsigned int freq;
370     freq = akc6955_get_freq();
371     freq += step;
372     akc6955_set_freq(freq);
373     return akc6955_get_freq();
374 }
375
376
377 unsigned int akc6955_down_freq(unsigned int step)
378 {
379     unsigned int freq;
380     freq = akc6955_get_freq();
381     if(freq <= step) return freq;
382     freq -= step;
383     akc6955_set_freq(freq);
384     return akc6955_get_freq();
385 }
386 void akc6955_setvolumemode(unsigned char flag)
387 {
388     unsigned char c;
389     c = akc6955_readcmd(AKC6955_ENABLE) & 0xf7;
390     if(flag != 0x00){
391         c |= 0x08;
392     }
393     akc6955_writecmd(AKC6955_ENABLE, c);
394 }
395
396 void akc6955_setvolume(unsigned char level)
397 {
398     unsigned char c;
399     c = akc6955_readcmd(AKC6955_VOLUME) & 0x03;
400     if(level > 63) level = 63;
401     akc6955_writecmd(AKC6955_VOLUME, (c | (level << 2)));
402 }
403
404 unsigned char akc6955_getvolume(void)
405 {
406     unsigned char c;
407     c = (akc6955_readcmd(AKC6955_VOLUME) & 0xfc) >> 2;
408     return c;
409 }
410
411 void akc6955_set_prevolume(unsigned char level)
412 {
413     unsigned char c;
414     c = akc6955_readcmd(AKC6955_PRE) & 0xf3;
415     c |= ((level & 0x03) << 2);
416     akc6955_writecmd(AKC6955_PRE, c);
417 }
418
419 unsigned char akc6955_get_prevolume(void)
420 {
421     unsigned char c;
422     c = akc6955_readcmd(AKC6955_PRE) & 0x0c;
423     c >>= 2;
424     return c;
425 }
426
427
428 void akc6955_setphase(unsigned char flag)
429 {
430     unsigned char c;
431     c = akc6955_readcmd(AKC6955_VOLUME);
432
433     if(flag == 0) {
434         c = c & 0xfe; //
435     } else {
436         c = c | 0x01;
437     }
438     akc6955_writecmd(AKC6955_VOLUME, c);
439 }
440
441 void akc6955_setline(unsigned char flag)
442 {
443     unsigned char c;
444     c = akc6955_readcmd(AKC6955_VOLUME);
445
446     if(flag == 0) {
447         c = c & 0xfd; //
448     } else {
449         c = c | 0x02;
450     }
451     akc6955_writecmd(AKC6955_VOLUME, c);
452 }
453
454 void akc6955_set_lowboost(unsigned char flag)
455 {
456     unsigned char c;
457     c = akc6955_readcmd(AKC6955_STEREO);
458     if(flag == 0) {
459         c &= 0xf7;
460     } else {
461         c |= 0x08;
462     }
463     akc6955_writecmd(AKC6955_STEREO, c);
464 }
465
466 void akc6955_set_stereomode(unsigned char mode)
467 {
468     unsigned char c;
469     c = akc6955_readcmd(AKC6955_STEREO);
470     mode = (mode & 0x03) << 2;
471     c = (c & 0xf3) | mode;
472     akc6955_writecmd(AKC6955_STEREO, c);
473 }
474
475 unsigned char akc6955_get_stereo(void)
476 {
477     unsigned char c;
478     c = akc6955_readcmd(AKC6955_RCH_HI) & 0x80;
479     if(c == 0) return 0x00;
480     return 0xff;
481 }
482
483 void akc6955_set_fm_threash(unsigned char val)
484 {
485     unsigned char c = akc6955_readcmd(AKC6955_THRESH);
486     val = val & 0x03;
487     c = (c & 0x3f) | (val << 6);
488     akc6955_writecmd(AKC6955_THRESH, c);
489 }
490
491 void akc6955_set_am_threash(unsigned char val)
492 {
493     unsigned char c = akc6955_readcmd(AKC6955_THRESH);
494     val = val & 0x03;
495     c = (c & 0xcf) | (val << 4);
496     akc6955_writecmd(AKC6955_THRESH, c);
497 }
498
499 void akc6955_set_fd_threash(unsigned char val)
500 {
501     unsigned char c = akc6955_readcmd(AKC6955_THRESH);
502     val = val & 0x03;
503     c = (c & 0xf3) | (val << 2);
504     akc6955_writecmd(AKC6955_THRESH, c);
505 }
506
507 void akc6955_set_stereo_threash(unsigned char val)
508 {
509     unsigned char c = akc6955_readcmd(AKC6955_THRESH);
510     val = val & 0x03;
511     c = (c & 0xfc) | val ;
512     akc6955_writecmd(AKC6955_THRESH, c);
513 }
514
515 /*
516  * Get battery level.
517  * Unit = 0.01V
518  */
519
520 unsigned int akc6955_get_battery(void)
521 {
522     unsigned int batt;
523     unsigned char c;
524     c = akc6955_readcmd(AKC6955_VBAT) & 0x3f;
525     batt = 180 + (c << 2) + c;
526     return batt;
527 }
528
529 /*
530  * 0 = 150KHz
531  * 1 = 200KHz
532  * 2 = 50KHz
533  * 3 = 100KHz
534  */
535 void akc6955_set_fmbandwidth(unsigned char bw)
536 {
537     unsigned char c = akc6955_readcmd(AKC6955_STEREO);
538     c = (c & 0xfc) | (bw & 0x03);
539     akc6955_writecmd(AKC6955_STEREO, c);
540 }
541
542 unsigned char akc6955_get_fmbandwidth(void)
543 {
544     unsigned char c = akc6955_readcmd(AKC6955_STEREO) & 0x03;
545     return c;
546 }