aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Wong <davidtlwong@gmail.com>2009-06-17 00:38:10 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-12 11:17:38 -0400
commitb80dc1c673f5ff79805215eb94ff008e634e4b2d (patch)
tree80a5849fadf39d81837a8e3ad5443b58032b8382
parenta0d64456f765297782d34750cf4dc862f2a8bce0 (diff)
V4L/DVB (12271): lgs8gxx: add lgs8g75 support
lgs8gxx: add lgs8g75 demodulator support Signed-off-by: David T.L. Wong <davidtlwong@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c484
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.h11
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx_priv.h12
3 files changed, 401 insertions, 106 deletions
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index fde27645bbed..eabcadc425d5 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -1,9 +1,9 @@
1/* 1/*
2 * Support for Legend Silicon DMB-TH demodulator 2 * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
3 * LGS8913, LGS8GL5 3 * LGS8913, LGS8GL5, LGS8G75
4 * experimental support LGS8G42, LGS8G52 4 * experimental support LGS8G42, LGS8G52
5 * 5 *
6 * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com> 6 * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited 7 * Copyright (C) 2008 Sirius International (Hong Kong) Limited
8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5) 8 * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
9 * 9 *
@@ -46,6 +46,42 @@ module_param(fake_signal_str, int, 0644);
46MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913." 46MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
47"Signal strength calculation is slow.(default:on)."); 47"Signal strength calculation is slow.(default:on).");
48 48
49static const u8 lgs8g75_initdat[] = {
50 0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
51 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
52 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
53 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
54 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
55 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
56 0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
57 0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
58 0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
59 0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
60 0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
61 0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
62 0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
63 0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
64 0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
65 0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
66 0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
67 0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
68 0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
69 0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
70 0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
71 0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
72 0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
73 0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
74 0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
75 0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
76 0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
77 0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
78 0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
80 0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
81 0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
82 0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
83};
84
49/* LGS8GXX internal helper functions */ 85/* LGS8GXX internal helper functions */
50 86
51static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data) 87static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -55,7 +91,7 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
55 struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; 91 struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
56 92
57 msg.addr = priv->config->demod_address; 93 msg.addr = priv->config->demod_address;
58 if (reg >= 0xC0) 94 if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
59 msg.addr += 0x02; 95 msg.addr += 0x02;
60 96
61 if (debug >= 2) 97 if (debug >= 2)
@@ -84,7 +120,7 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
84 }; 120 };
85 121
86 dev_addr = priv->config->demod_address; 122 dev_addr = priv->config->demod_address;
87 if (reg >= 0xC0) 123 if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
88 dev_addr += 0x02; 124 dev_addr += 0x02;
89 msg[1].addr = msg[0].addr = dev_addr; 125 msg[1].addr = msg[0].addr = dev_addr;
90 126
@@ -112,19 +148,36 @@ static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
112 return 0; 148 return 0;
113} 149}
114 150
151static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
152 u8 val, u8 delay, u8 tries)
153{
154 u8 t;
155 int i;
156
157 for (i = 0; i < tries; i++) {
158 lgs8gxx_read_reg(priv, reg, &t);
159
160 if ((t & mask) == val)
161 return 0;
162 msleep(delay);
163 }
164
165 return 1;
166}
167
115static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv) 168static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
116{ 169{
117 const struct lgs8gxx_config *config = priv->config; 170 const struct lgs8gxx_config *config = priv->config;
118 u8 if_conf; 171 u8 if_conf;
119 172
120 if_conf = 0x10; /* AGC output on; */ 173 if_conf = 0x10; /* AGC output on, RF_AGC output off; */
121 174
122 if_conf |= 175 if_conf |=
123 ((config->ext_adc) ? 0x80 : 0x00) | 176 ((config->ext_adc) ? 0x80 : 0x00) |
124 ((config->if_neg_center) ? 0x04 : 0x00) | 177 ((config->if_neg_center) ? 0x04 : 0x00) |
125 ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */ 178 ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
126 ((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) | 179 ((config->adc_signed) ? 0x02 : 0x00) |
127 ((config->ext_adc && config->if_neg_edge) ? 0x01 : 0x00); 180 ((config->if_neg_edge) ? 0x01 : 0x00);
128 181
129 if (config->ext_adc && 182 if (config->ext_adc &&
130 (config->prod == LGS8GXX_PROD_LGS8G52)) { 183 (config->prod == LGS8GXX_PROD_LGS8G52)) {
@@ -157,39 +210,82 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
157 } 210 }
158 dprintk("AFC_INIT_FREQ = 0x%08X\n", v32); 211 dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
159 212
160 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32)); 213 if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
161 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8)); 214 lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
162 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16)); 215 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
163 lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24)); 216 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
217 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
218 } else {
219 lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
220 lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
221 lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
222 lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
223 }
224
225 return 0;
226}
227
228static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
229{
230 u64 val;
231 u32 v32 = 0;
232 u8 reg_addr, t;
233 int i;
234
235 if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
236 reg_addr = 0x23;
237 else
238 reg_addr = 0x48;
239
240 for (i = 0; i < 4; i++) {
241 lgs8gxx_read_reg(priv, reg_addr, &t);
242 v32 <<= 8;
243 v32 |= t;
244 reg_addr--;
245 }
164 246
247 val = v32;
248 val *= priv->config->if_clk_freq;
249 val /= (u64)1 << 32;
250 dprintk("AFC = %u kHz\n", (u32)val);
165 return 0; 251 return 0;
166} 252}
167