OSDN Git Service

b8f2f35de7f89316861996654f80606b26b4b51e
[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
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 unsigned int akc6955_mode3k(unsigned char flag)
142 {
143     unsigned char b;
144     b = akc6955_readcmd(AKC6955_CH_HI);
145     if(flag != 0){
146         b |= 0x20;
147     } else {
148         b &= 0xdf;
149     }
150     akc6955_writecmd(AKC6955_CH_HI, b);
151 //    akc6955_do_tune();
152     _AKC6955_WAIT_62_5MS();
153     return akc6955_get_freq();
154 }
155
156 void akc6955_set_tune(unsigned char mode_3k, unsigned int ch)
157 {
158     unsigned char band;
159     unsigned char fm;
160     unsigned char b;
161     unsigned int i;
162
163     i = ch;
164     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
165     if(fm == 0){
166         // AM
167         band = akc6955_get_amband();
168     } else {
169         band = 0;
170     }
171     if(band == 2){
172         // BAND=AM && MW2
173         i = (i / 3) * 3;
174     }
175     if(i > 0x1fff) i = 0x1fff;
176     //i = ch & 0x1fff;
177
178     if(mode_3k == 0){
179         b = ((i >> 8) & 0x1f) | 0x40; // 32.768KHz clock
180     } else {
181         b = ((i >> 8) & 0x1f) | 0x60;
182     }
183     akc6955_writecmd(AKC6955_CH_HI, b);
184     b = i & 0xff;
185     akc6955_writecmd(AKC6955_CH_LO, b);
186     akc6955_do_tune();
187     do{
188         // Use software-delay, but recommands hardware-delay ;-(
189         _AKC6955_WAIT_12_5MS();
190     } while(akc6955_tune() == 0);
191 }
192
193 void akc6955_do_scan(unsigned char up)
194 {
195     unsigned char b;
196     akc6955_do_tune();
197     b = akc6955_readcmd(AKC6955_POWER);
198     b &= 0xe3;
199     if(up != 0) {
200         b |= 0x08;
201     }
202     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
203     b |= 0x10;
204     akc6955_writecmd(AKC6955_POWER, b); // Raise seek bit to '1'.
205 }
206
207 void akc6955_abort_scan(void)
208 {
209     unsigned char b;
210     b = akc6955_readcmd(AKC6955_POWER);
211     b &= 0xef;
212     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
213 }
214
215 unsigned char akc6955_chk_donescan(void)
216 {
217     unsigned char b;
218     b = akc6955_readcmd(AKC6955_RCH_HI) & 0x40;
219     if(b == 0) return 0;
220     return 0xff;
221 }
222
223
224 /*
225  * Get AM/FM Frequency: ret = KHz at AM, 10KHz @FM.
226  */
227 unsigned int akc6955_get_freq(void)
228 {
229     unsigned char b, h, l;
230     unsigned char fm;
231     unsigned int i;
232     b = akc6955_readcmd(AKC6955_CNR_AM) & 0x80;
233     l = akc6955_readcmd(AKC6955_RCH_LO) ;
234     h = akc6955_readcmd(AKC6955_RCH_HI) & 0x1f;
235     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
236     i = l + h * 256;
237     if(fm != 0){ // 25KHz
238         i = i * 10; // 25 / 10 = 10/4
239         i = i / 4;
240         i += 3000; // 30MHz
241     } else if(b == 0){ // 5K
242         i = i * 5;
243     } else { // 3K
244         i = i * 3;
245     }
246     return i;
247 }
248
249 void akc6955_set_freq(unsigned int freq)
250 {
251     unsigned int ch;
252     unsigned char fm;
253     unsigned char mode3k = 0;
254
255     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
256     if(fm != 0) { // FM
257       ch = freq - 3000;
258       ch = ch * 4;
259       ch = ch / 10; // 10/25 = 0.4
260     } else {
261         mode3k = akc6955_readcmd(AKC6955_CNR_AM) & 0x80;
262         if(mode3k == 0){
263             ch = freq / 5;
264         } else {
265             ch = freq / 3;
266         }
267     }
268     akc6955_set_tune(mode3k, ch);
269 }
270
271
272 unsigned char akc6955_get_cnr(void)
273 {
274     unsigned char fm;
275     unsigned char b;
276     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
277     if(fm != 0) { // FM
278         b = akc6955_readcmd(AKC6955_CNR_FM);
279     } else { // AM
280         b = akc6955_readcmd(AKC6955_CNR_AM);
281     }
282     b &= 0x7f;
283     return b;
284 }
285
286 int akc6955_read_level(void)
287 {
288     unsigned char fm;
289     unsigned char rflevel, iflevel;
290     unsigned char b;
291     unsigned int rssi;
292     unsigned int freq;
293     int level;
294
295     fm = akc6955_readcmd(AKC6955_POWER) & 0x40;
296     b =  akc6955_readcmd(AKC6955_PGALEVEL);
297     rflevel = (b & 0xe0) >> 5;
298     iflevel = (b & 0x1c) >> 2;
299     rssi = (unsigned int)(akc6955_readcmd(AKC6955_RSSI) & 0x7f);
300     if(fm != 0){
301         level = 103 - (rssi + 6 * (rflevel + iflevel));
302     } else {
303         freq = akc6955_get_freq();
304         if(freq > 2560) { // ASSUME SW
305             level = 103 - (rssi + 6 * (rflevel + iflevel));
306         } else { // ASSUME MW,LW
307             level = 123 - (rssi + 6 * (rflevel + iflevel));
308         }
309     }
310     return level;
311 }
312
313 unsigned int akc6955_up_freq(unsigned int step)
314 {
315     unsigned int freq;
316     freq = akc6955_get_freq();
317     freq += step;
318     akc6955_set_freq(freq);
319     return akc6955_get_freq();
320 }
321
322
323 unsigned int akc6955_down_freq(unsigned int step)
324 {
325     unsigned int freq;
326     freq = akc6955_get_freq();
327     if(freq <= step) return freq;
328     freq -= step;
329     akc6955_set_freq(freq);
330     return akc6955_get_freq();
331 }