summaryrefslogtreecommitdiff
path: root/firmware/drivers/tuner/si4700.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/tuner/si4700.c')
-rw-r--r--firmware/drivers/tuner/si4700.c151
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. */
36static unsigned char write_bytes[8]; /* registers 02 - 05 */
37static bool tuner_present = false;
38
39void 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
57static 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 */
33int si4700_set(int setting, int value) 76int 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 */
42int si4700_get(int setting) 164int 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