diff options
| author | David Wong <davidtlwong@gmail.com> | 2009-06-17 00:38:10 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-12 11:17:38 -0400 |
| commit | b80dc1c673f5ff79805215eb94ff008e634e4b2d (patch) | |
| tree | 80a5849fadf39d81837a8e3ad5443b58032b8382 | |
| parent | a0d64456f765297782d34750cf4dc862f2a8bce0 (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.c | 484 | ||||
| -rw-r--r-- | drivers/media/dvb/frontends/lgs8gxx.h | 11 | ||||
| -rw-r--r-- | drivers/media/dvb/frontends/lgs8gxx_priv.h | 12 |
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); | |||
| 46 | MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913." | 46 | MODULE_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 | ||
| 49 | static 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 | ||
| 51 | static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data) | 87 | static 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 | ||
| 151 | static 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 | |||
| 115 | static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv) | 168 | static 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 | |||
| 228 | static 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 | |||
