diff options
Diffstat (limited to 'firmware/drivers/tuner/si4700.c')
-rw-r--r-- | firmware/drivers/tuner/si4700.c | 151 |
1 files changed, 146 insertions, 5 deletions
diff --git a/firmware/drivers/tuner/si4700.c b/firmware/drivers/tuner/si4700.c index 9233afae24..a55a8cfcc4 100644 --- a/firmware/drivers/tuner/si4700.c +++ b/firmware/drivers/tuner/si4700.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * | 9 | * |
10 | * Tuner "middleware" for Silicon Labs SI4700 chip | 10 | * Tuner "middleware" for Silicon Labs SI4700 chip |
11 | * | 11 | * |
12 | * Copyright (C) 2008 ??? | 12 | * Copyright (C) 2008 Nils Wallménius |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
15 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
@@ -29,19 +29,160 @@ | |||
29 | #include "fmradio.h" | 29 | #include "fmradio.h" |
30 | #include "fmradio_i2c.h" /* physical interface driver */ | 30 | #include "fmradio_i2c.h" /* physical interface driver */ |
31 | 31 | ||
32 | #define I2C_ADR 0x20 | ||
33 | |||
34 | /* I2C writes start at register 02h so the first two bytes are | ||
35 | 02h, next two 03h, etc. */ | ||
36 | static unsigned char write_bytes[8]; /* registers 02 - 05 */ | ||
37 | static bool tuner_present = false; | ||
38 | |||
39 | void si4700_init(void) | ||
40 | { | ||
41 | unsigned char read_bytes[32]; | ||
42 | tuner_power(true); | ||
43 | fmradio_i2c_read(I2C_ADR, read_bytes, sizeof(read_bytes)); | ||
44 | |||
45 | if ((read_bytes[12] << 8 | read_bytes[13]) == 0x1242) | ||
46 | { | ||
47 | tuner_present = true; | ||
48 | /* fill in the initial values in write_bytes */ | ||
49 | memcpy(&write_bytes[0], &read_bytes[16], sizeof(write_bytes)); | ||
50 | /* -6dB volume, keep everything else as default */ | ||
51 | write_bytes[7] = (write_bytes[7] & ~0xf) | 0xc; | ||
52 | } | ||
53 | |||
54 | tuner_power(false); | ||
55 | } | ||
56 | |||
57 | static void si4700_tune(void) | ||
58 | { | ||
59 | unsigned char read_bytes[1]; | ||
60 | |||
61 | write_bytes[2] |= (1 << 7); /* Set TUNE high to start tuning */ | ||
62 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
63 | |||
64 | do | ||
65 | { | ||
66 | sleep(HZ/50); | ||
67 | fmradio_i2c_read(I2C_ADR, read_bytes, 1); | ||
68 | } | ||
69 | while (!(read_bytes[0] & (1 << 6))); /* STC high == Seek/Tune complete */ | ||
70 | |||
71 | write_bytes[2] &= ~(1 << 7); /* Set TUNE low */ | ||
72 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
73 | } | ||
74 | |||
32 | /* tuner abstraction layer: set something to the tuner */ | 75 | /* tuner abstraction layer: set something to the tuner */ |
33 | int si4700_set(int setting, int value) | 76 | int si4700_set(int setting, int value) |
34 | { | 77 | { |
35 | (void)setting; | 78 | switch(setting) |
36 | (void)value; | 79 | { |
80 | case RADIO_SLEEP: | ||
81 | if (value) | ||
82 | { | ||
83 | write_bytes[1] = (1 | (1 << 6)); /* ENABLE high, DISABLE high */ | ||
84 | } | ||
85 | else | ||
86 | { | ||
87 | write_bytes[1] = 1; /* ENABLE high, DISABLE low */ | ||
88 | } | ||
89 | break; | ||
37 | 90 | ||
91 | case RADIO_FREQUENCY: | ||
92 | { | ||
93 | static const unsigned int spacings[3] = | ||
94 | { | ||
95 | 200000, 100000, 50000 | ||
96 | }; | ||
97 | unsigned int chan; | ||
98 | unsigned int spacing = spacings[(write_bytes[7] >> 4) & 3] ; | ||
99 | |||
100 | if (write_bytes[7] & (3 << 6)) /* check BAND */ | ||
101 | { | ||
102 | chan = (value - 76000000) / spacing; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | chan = (value - 87500000) / spacing; | ||
107 | } | ||
108 | |||
109 | write_bytes[2] = (write_bytes[2] & ~3) | ((chan & (3 << 8)) >> 8); | ||
110 | write_bytes[3] = (chan & 0xff); | ||
111 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
112 | si4700_tune(); | ||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | case RADIO_SCAN_FREQUENCY: | ||
117 | si4700_set(RADIO_FREQUENCY, value); | ||
118 | return 1; | ||
119 | |||
120 | case RADIO_MUTE: | ||
121 | if (value) | ||
122 | { | ||
123 | /* mute */ | ||
124 | write_bytes[0] &= ~(1 << 6); | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | /* unmute */ | ||
129 | write_bytes[0] |= (1 << 6); | ||
130 | } | ||
131 | break; | ||
132 | |||
133 | case RADIO_REGION: | ||
134 | { | ||
135 | const struct si4700_region_data *rd = | ||
136 | &si4700_region_data[value]; | ||
137 | |||
138 | write_bytes[4] = ((write_bytes[4] & ~(1 << 3)) | (rd->deemphasis << 3)); | ||
139 | write_bytes[7] = ((write_bytes[7] & ~(3 << 6)) | (rd->band << 6)); | ||
140 | write_bytes[7] = ((write_bytes[7] & ~(3 << 4)) | (rd->spacing << 4)); | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | case RADIO_FORCE_MONO: | ||
145 | if (value) | ||
146 | { | ||
147 | write_bytes[0] |= (1 << 5); | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | write_bytes[0] &= ~(1 << 5); | ||
152 | } | ||
153 | break; | ||
154 | |||
155 | default: | ||
156 | return -1; | ||
157 | } | ||
158 | |||
159 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
38 | return 1; | 160 | return 1; |
39 | } | 161 | } |
40 | 162 | ||
41 | /* tuner abstraction layer: read something from the tuner */ | 163 | /* tuner abstraction layer: read something from the tuner */ |
42 | int si4700_get(int setting) | 164 | int si4700_get(int setting) |
43 | { | 165 | { |
44 | (void)setting; | 166 | /* I2C reads start with register 0xA */ |
167 | unsigned char read_bytes[1]; | ||
168 | int val = -1; /* default for unsupported query */ | ||
169 | |||
170 | switch(setting) | ||
171 | { | ||
172 | case RADIO_PRESENT: | ||
173 | val = tuner_present ? 1 : 0; | ||
174 | break; | ||
45 | 175 | ||
46 | return -1; | 176 | case RADIO_TUNED: |
177 | val = 1; | ||
178 | break; | ||
179 | |||
180 | case RADIO_STEREO: | ||
181 | fmradio_i2c_read(I2C_ADR, read_bytes, sizeof(read_bytes)); | ||
182 | val = (read_bytes[0] & 1); /* ST high == Stereo */ | ||
183 | break; | ||
184 | } | ||
185 | |||
186 | return val; | ||
47 | } | 187 | } |
188 | |||