174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29a0bf528SMauro Carvalho Chehab /*
39a0bf528SMauro Carvalho Chehab Driver for Philips tda1004xh OFDM Demodulator
49a0bf528SMauro Carvalho Chehab
59a0bf528SMauro Carvalho Chehab (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach
69a0bf528SMauro Carvalho Chehab
79a0bf528SMauro Carvalho Chehab
89a0bf528SMauro Carvalho Chehab */
99a0bf528SMauro Carvalho Chehab /*
109a0bf528SMauro Carvalho Chehab * This driver needs external firmware. Please use the commands
11fe63a1a6SMauro Carvalho Chehab * "<kerneldir>/scripts/get_dvb_firmware tda10045",
12fe63a1a6SMauro Carvalho Chehab * "<kerneldir>/scripts/get_dvb_firmware tda10046" to
139a0bf528SMauro Carvalho Chehab * download/extract them, and then copy them to /usr/lib/hotplug/firmware
149a0bf528SMauro Carvalho Chehab * or /lib/firmware (depending on configuration of firmware hotplug).
159a0bf528SMauro Carvalho Chehab */
169a0bf528SMauro Carvalho Chehab #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
179a0bf528SMauro Carvalho Chehab #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
189a0bf528SMauro Carvalho Chehab
199a0bf528SMauro Carvalho Chehab #include <linux/init.h>
209a0bf528SMauro Carvalho Chehab #include <linux/module.h>
219a0bf528SMauro Carvalho Chehab #include <linux/device.h>
229a0bf528SMauro Carvalho Chehab #include <linux/jiffies.h>
239a0bf528SMauro Carvalho Chehab #include <linux/string.h>
249a0bf528SMauro Carvalho Chehab #include <linux/slab.h>
259a0bf528SMauro Carvalho Chehab
26fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
279a0bf528SMauro Carvalho Chehab #include "tda1004x.h"
289a0bf528SMauro Carvalho Chehab
299a0bf528SMauro Carvalho Chehab static int debug;
309a0bf528SMauro Carvalho Chehab #define dprintk(args...) \
319a0bf528SMauro Carvalho Chehab do { \
329a0bf528SMauro Carvalho Chehab if (debug) printk(KERN_DEBUG "tda1004x: " args); \
339a0bf528SMauro Carvalho Chehab } while (0)
349a0bf528SMauro Carvalho Chehab
359a0bf528SMauro Carvalho Chehab #define TDA1004X_CHIPID 0x00
369a0bf528SMauro Carvalho Chehab #define TDA1004X_AUTO 0x01
379a0bf528SMauro Carvalho Chehab #define TDA1004X_IN_CONF1 0x02
389a0bf528SMauro Carvalho Chehab #define TDA1004X_IN_CONF2 0x03
399a0bf528SMauro Carvalho Chehab #define TDA1004X_OUT_CONF1 0x04
409a0bf528SMauro Carvalho Chehab #define TDA1004X_OUT_CONF2 0x05
419a0bf528SMauro Carvalho Chehab #define TDA1004X_STATUS_CD 0x06
429a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFC4 0x07
439a0bf528SMauro Carvalho Chehab #define TDA1004X_DSSPARE2 0x0C
449a0bf528SMauro Carvalho Chehab #define TDA10045H_CODE_IN 0x0D
459a0bf528SMauro Carvalho Chehab #define TDA10045H_FWPAGE 0x0E
469a0bf528SMauro Carvalho Chehab #define TDA1004X_SCAN_CPT 0x10
479a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_CMD 0x11
489a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_ARG 0x12
499a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_DATA1 0x13
509a0bf528SMauro Carvalho Chehab #define TDA1004X_DSP_DATA2 0x14
519a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFADC1 0x15
529a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFC1 0x16
539a0bf528SMauro Carvalho Chehab #define TDA10045H_S_AGC 0x1a
549a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_TUN_LEVEL 0x1a
559a0bf528SMauro Carvalho Chehab #define TDA1004X_SNR 0x1c
569a0bf528SMauro Carvalho Chehab #define TDA1004X_CONF_TS1 0x1e
579a0bf528SMauro Carvalho Chehab #define TDA1004X_CONF_TS2 0x1f
589a0bf528SMauro Carvalho Chehab #define TDA1004X_CBER_RESET 0x20
599a0bf528SMauro Carvalho Chehab #define TDA1004X_CBER_MSB 0x21
609a0bf528SMauro Carvalho Chehab #define TDA1004X_CBER_LSB 0x22
619a0bf528SMauro Carvalho Chehab #define TDA1004X_CVBER_LUT 0x23
629a0bf528SMauro Carvalho Chehab #define TDA1004X_VBER_MSB 0x24
639a0bf528SMauro Carvalho Chehab #define TDA1004X_VBER_MID 0x25
649a0bf528SMauro Carvalho Chehab #define TDA1004X_VBER_LSB 0x26
659a0bf528SMauro Carvalho Chehab #define TDA1004X_UNCOR 0x27
669a0bf528SMauro Carvalho Chehab
679a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_P 0x2D
689a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_M_MSB 0x2E
699a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_M_LSB 0x2F
709a0bf528SMauro Carvalho Chehab #define TDA10045H_CONFPLL_N 0x30
719a0bf528SMauro Carvalho Chehab
729a0bf528SMauro Carvalho Chehab #define TDA10046H_CONFPLL1 0x2D
739a0bf528SMauro Carvalho Chehab #define TDA10046H_CONFPLL2 0x2F
749a0bf528SMauro Carvalho Chehab #define TDA10046H_CONFPLL3 0x30
759a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF1 0x31
769a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF2 0x32
779a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF3 0x33
789a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF4 0x34
799a0bf528SMauro Carvalho Chehab #define TDA10046H_TIME_WREF5 0x35
809a0bf528SMauro Carvalho Chehab
819a0bf528SMauro Carvalho Chehab #define TDA10045H_UNSURW_MSB 0x31
829a0bf528SMauro Carvalho Chehab #define TDA10045H_UNSURW_LSB 0x32
839a0bf528SMauro Carvalho Chehab #define TDA10045H_WREF_MSB 0x33
849a0bf528SMauro Carvalho Chehab #define TDA10045H_WREF_MID 0x34
859a0bf528SMauro Carvalho Chehab #define TDA10045H_WREF_LSB 0x35
869a0bf528SMauro Carvalho Chehab #define TDA10045H_MUXOUT 0x36
879a0bf528SMauro Carvalho Chehab #define TDA1004X_CONFADC2 0x37
889a0bf528SMauro Carvalho Chehab
899a0bf528SMauro Carvalho Chehab #define TDA10045H_IOFFSET 0x38
909a0bf528SMauro Carvalho Chehab
919a0bf528SMauro Carvalho Chehab #define TDA10046H_CONF_TRISTATE1 0x3B
929a0bf528SMauro Carvalho Chehab #define TDA10046H_CONF_TRISTATE2 0x3C
939a0bf528SMauro Carvalho Chehab #define TDA10046H_CONF_POLARITY 0x3D
949a0bf528SMauro Carvalho Chehab #define TDA10046H_FREQ_OFFSET 0x3E
959a0bf528SMauro Carvalho Chehab #define TDA10046H_GPIO_OUT_SEL 0x41
969a0bf528SMauro Carvalho Chehab #define TDA10046H_GPIO_SELECT 0x42
979a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_CONF 0x43
989a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_THR 0x44
999a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_RENORM 0x45
1009a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_GAINS 0x46
1019a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_TUN_MIN 0x47
1029a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_TUN_MAX 0x48
1039a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_IF_MIN 0x49
1049a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_IF_MAX 0x4A
1059a0bf528SMauro Carvalho Chehab
1069a0bf528SMauro Carvalho Chehab #define TDA10046H_FREQ_PHY2_MSB 0x4D
1079a0bf528SMauro Carvalho Chehab #define TDA10046H_FREQ_PHY2_LSB 0x4E
1089a0bf528SMauro Carvalho Chehab
1099a0bf528SMauro Carvalho Chehab #define TDA10046H_CVBER_CTRL 0x4F
1109a0bf528SMauro Carvalho Chehab #define TDA10046H_AGC_IF_LEVEL 0x52
1119a0bf528SMauro Carvalho Chehab #define TDA10046H_CODE_CPT 0x57
1129a0bf528SMauro Carvalho Chehab #define TDA10046H_CODE_IN 0x58
1139a0bf528SMauro Carvalho Chehab
1149a0bf528SMauro Carvalho Chehab
tda1004x_write_byteI(struct tda1004x_state * state,int reg,int data)1159a0bf528SMauro Carvalho Chehab static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
1169a0bf528SMauro Carvalho Chehab {
1179a0bf528SMauro Carvalho Chehab int ret;
1189a0bf528SMauro Carvalho Chehab u8 buf[] = { reg, data };
1199a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
1209a0bf528SMauro Carvalho Chehab
1219a0bf528SMauro Carvalho Chehab dprintk("%s: reg=0x%x, data=0x%x\n", __func__, reg, data);
1229a0bf528SMauro Carvalho Chehab
1239a0bf528SMauro Carvalho Chehab msg.addr = state->config->demod_address;
1249a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, &msg, 1);
1259a0bf528SMauro Carvalho Chehab
1269a0bf528SMauro Carvalho Chehab if (ret != 1)
1279a0bf528SMauro Carvalho Chehab dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
1289a0bf528SMauro Carvalho Chehab __func__, reg, data, ret);
1299a0bf528SMauro Carvalho Chehab
1309a0bf528SMauro Carvalho Chehab dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
1319a0bf528SMauro Carvalho Chehab reg, data, ret);
1329a0bf528SMauro Carvalho Chehab return (ret != 1) ? -1 : 0;
1339a0bf528SMauro Carvalho Chehab }
1349a0bf528SMauro Carvalho Chehab
tda1004x_read_byte(struct tda1004x_state * state,int reg)1359a0bf528SMauro Carvalho Chehab static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
1369a0bf528SMauro Carvalho Chehab {
1379a0bf528SMauro Carvalho Chehab int ret;
1389a0bf528SMauro Carvalho Chehab u8 b0[] = { reg };
1399a0bf528SMauro Carvalho Chehab u8 b1[] = { 0 };
1409a0bf528SMauro Carvalho Chehab struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
1419a0bf528SMauro Carvalho Chehab { .flags = I2C_M_RD, .buf = b1, .len = 1 }};
1429a0bf528SMauro Carvalho Chehab
1439a0bf528SMauro Carvalho Chehab dprintk("%s: reg=0x%x\n", __func__, reg);
1449a0bf528SMauro Carvalho Chehab
1459a0bf528SMauro Carvalho Chehab msg[0].addr = state->config->demod_address;
1469a0bf528SMauro Carvalho Chehab msg[1].addr = state->config->demod_address;
1479a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c, msg, 2);
1489a0bf528SMauro Carvalho Chehab
1499a0bf528SMauro Carvalho Chehab if (ret != 2) {
1509a0bf528SMauro Carvalho Chehab dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg,
1519a0bf528SMauro Carvalho Chehab ret);
1529a0bf528SMauro Carvalho Chehab return -EINVAL;
1539a0bf528SMauro Carvalho Chehab }
1549a0bf528SMauro Carvalho Chehab
1559a0bf528SMauro Carvalho Chehab dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __func__,
1569a0bf528SMauro Carvalho Chehab reg, b1[0], ret);
1579a0bf528SMauro Carvalho Chehab return b1[0];
1589a0bf528SMauro Carvalho Chehab }
1599a0bf528SMauro Carvalho Chehab
tda1004x_write_mask(struct tda1004x_state * state,int reg,int mask,int data)1609a0bf528SMauro Carvalho Chehab static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
1619a0bf528SMauro Carvalho Chehab {
1629a0bf528SMauro Carvalho Chehab int val;
1639a0bf528SMauro Carvalho Chehab dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __func__, reg,
1649a0bf528SMauro Carvalho Chehab mask, data);
1659a0bf528SMauro Carvalho Chehab
1669a0bf528SMauro Carvalho Chehab // read a byte and check
1679a0bf528SMauro Carvalho Chehab val = tda1004x_read_byte(state, reg);
1689a0bf528SMauro Carvalho Chehab if (val < 0)
1699a0bf528SMauro Carvalho Chehab return val;
1709a0bf528SMauro Carvalho Chehab
1719a0bf528SMauro Carvalho Chehab // mask if off
1729a0bf528SMauro Carvalho Chehab val = val & ~mask;
1739a0bf528SMauro Carvalho Chehab val |= data & 0xff;
1749a0bf528SMauro Carvalho Chehab
1759a0bf528SMauro Carvalho Chehab // write it out again
1769a0bf528SMauro Carvalho Chehab return tda1004x_write_byteI(state, reg, val);
1779a0bf528SMauro Carvalho Chehab }
1789a0bf528SMauro Carvalho Chehab
tda1004x_write_buf(struct tda1004x_state * state,int reg,unsigned char * buf,int len)1799a0bf528SMauro Carvalho Chehab static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len)
1809a0bf528SMauro Carvalho Chehab {
1819a0bf528SMauro Carvalho Chehab int i;
1829a0bf528SMauro Carvalho Chehab int result;
1839a0bf528SMauro Carvalho Chehab
1849a0bf528SMauro Carvalho Chehab dprintk("%s: reg=0x%x, len=0x%x\n", __func__, reg, len);
1859a0bf528SMauro Carvalho Chehab
1869a0bf528SMauro Carvalho Chehab result = 0;
1879a0bf528SMauro Carvalho Chehab for (i = 0; i < len; i++) {
1889a0bf528SMauro Carvalho Chehab result = tda1004x_write_byteI(state, reg + i, buf[i]);
1899a0bf528SMauro Carvalho Chehab if (result != 0)
1909a0bf528SMauro Carvalho Chehab break;
1919a0bf528SMauro Carvalho Chehab }
1929a0bf528SMauro Carvalho Chehab
1939a0bf528SMauro Carvalho Chehab return result;
1949a0bf528SMauro Carvalho Chehab }
1959a0bf528SMauro Carvalho Chehab
tda1004x_enable_tuner_i2c(struct tda1004x_state * state)1969a0bf528SMauro Carvalho Chehab static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
1979a0bf528SMauro Carvalho Chehab {
1989a0bf528SMauro Carvalho Chehab int result;
1999a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
2009a0bf528SMauro Carvalho Chehab
2019a0bf528SMauro Carvalho Chehab result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
2029a0bf528SMauro Carvalho Chehab msleep(20);
2039a0bf528SMauro Carvalho Chehab return result;
2049a0bf528SMauro Carvalho Chehab }
2059a0bf528SMauro Carvalho Chehab
tda1004x_disable_tuner_i2c(struct tda1004x_state * state)2069a0bf528SMauro Carvalho Chehab static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
2079a0bf528SMauro Carvalho Chehab {
2089a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
2099a0bf528SMauro Carvalho Chehab
2109a0bf528SMauro Carvalho Chehab return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
2119a0bf528SMauro Carvalho Chehab }
2129a0bf528SMauro Carvalho Chehab
tda10045h_set_bandwidth(struct tda1004x_state * state,u32 bandwidth)2139a0bf528SMauro Carvalho Chehab static int tda10045h_set_bandwidth(struct tda1004x_state *state,
2149a0bf528SMauro Carvalho Chehab u32 bandwidth)
2159a0bf528SMauro Carvalho Chehab {
2169a0bf528SMauro Carvalho Chehab static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
2179a0bf528SMauro Carvalho Chehab static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
2189a0bf528SMauro Carvalho Chehab static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
2199a0bf528SMauro Carvalho Chehab
2209a0bf528SMauro Carvalho Chehab switch (bandwidth) {
2219a0bf528SMauro Carvalho Chehab case 6000000:
2229a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
2239a0bf528SMauro Carvalho Chehab break;
2249a0bf528SMauro Carvalho Chehab
2259a0bf528SMauro Carvalho Chehab case 7000000:
2269a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
2279a0bf528SMauro Carvalho Chehab break;
2289a0bf528SMauro Carvalho Chehab
2299a0bf528SMauro Carvalho Chehab case 8000000:
2309a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
2319a0bf528SMauro Carvalho Chehab break;
2329a0bf528SMauro Carvalho Chehab
2339a0bf528SMauro Carvalho Chehab default:
2349a0bf528SMauro Carvalho Chehab return -EINVAL;
2359a0bf528SMauro Carvalho Chehab }
2369a0bf528SMauro Carvalho Chehab
2379a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);
2389a0bf528SMauro Carvalho Chehab
2399a0bf528SMauro Carvalho Chehab return 0;
2409a0bf528SMauro Carvalho Chehab }
2419a0bf528SMauro Carvalho Chehab
tda10046h_set_bandwidth(struct tda1004x_state * state,u32 bandwidth)2429a0bf528SMauro Carvalho Chehab static int tda10046h_set_bandwidth(struct tda1004x_state *state,
2439a0bf528SMauro Carvalho Chehab u32 bandwidth)
2449a0bf528SMauro Carvalho Chehab {
2459a0bf528SMauro Carvalho Chehab static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
2469a0bf528SMauro Carvalho Chehab static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
2479a0bf528SMauro Carvalho Chehab static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
2489a0bf528SMauro Carvalho Chehab
2499a0bf528SMauro Carvalho Chehab static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
2509a0bf528SMauro Carvalho Chehab static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
2519a0bf528SMauro Carvalho Chehab static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
2529a0bf528SMauro Carvalho Chehab int tda10046_clk53m;
2539a0bf528SMauro Carvalho Chehab
2549a0bf528SMauro Carvalho Chehab if ((state->config->if_freq == TDA10046_FREQ_045) ||
2559a0bf528SMauro Carvalho Chehab (state->config->if_freq == TDA10046_FREQ_052))
2569a0bf528SMauro Carvalho Chehab tda10046_clk53m = 0;
2579a0bf528SMauro Carvalho Chehab else
2589a0bf528SMauro Carvalho Chehab tda10046_clk53m = 1;
2599a0bf528SMauro Carvalho Chehab switch (bandwidth) {
2609a0bf528SMauro Carvalho Chehab case 6000000:
2619a0bf528SMauro Carvalho Chehab if (tda10046_clk53m)
2629a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
2639a0bf528SMauro Carvalho Chehab sizeof(bandwidth_6mhz_53M));
2649a0bf528SMauro Carvalho Chehab else
2659a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
2669a0bf528SMauro Carvalho Chehab sizeof(bandwidth_6mhz_48M));
2679a0bf528SMauro Carvalho Chehab if (state->config->if_freq == TDA10046_FREQ_045) {
2689a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
2699a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
2709a0bf528SMauro Carvalho Chehab }
2719a0bf528SMauro Carvalho Chehab break;
2729a0bf528SMauro Carvalho Chehab
2739a0bf528SMauro Carvalho Chehab case 7000000:
2749a0bf528SMauro Carvalho Chehab if (tda10046_clk53m)
2759a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
2769a0bf528SMauro Carvalho Chehab sizeof(bandwidth_7mhz_53M));
2779a0bf528SMauro Carvalho Chehab else
2789a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
2799a0bf528SMauro Carvalho Chehab sizeof(bandwidth_7mhz_48M));
2809a0bf528SMauro Carvalho Chehab if (state->config->if_freq == TDA10046_FREQ_045) {
2819a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
2829a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
2839a0bf528SMauro Carvalho Chehab }
2849a0bf528SMauro Carvalho Chehab break;
2859a0bf528SMauro Carvalho Chehab
2869a0bf528SMauro Carvalho Chehab case 8000000:
2879a0bf528SMauro Carvalho Chehab if (tda10046_clk53m)
2889a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
2899a0bf528SMauro Carvalho Chehab sizeof(bandwidth_8mhz_53M));
2909a0bf528SMauro Carvalho Chehab else
2919a0bf528SMauro Carvalho Chehab tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
2929a0bf528SMauro Carvalho Chehab sizeof(bandwidth_8mhz_48M));
2939a0bf528SMauro Carvalho Chehab if (state->config->if_freq == TDA10046_FREQ_045) {
2949a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
2959a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
2969a0bf528SMauro Carvalho Chehab }
2979a0bf528SMauro Carvalho Chehab break;
2989a0bf528SMauro Carvalho Chehab
2999a0bf528SMauro Carvalho Chehab default:
3009a0bf528SMauro Carvalho Chehab return -EINVAL;
3019a0bf528SMauro Carvalho Chehab }
3029a0bf528SMauro Carvalho Chehab
3039a0bf528SMauro Carvalho Chehab return 0;
3049a0bf528SMauro Carvalho Chehab }
3059a0bf528SMauro Carvalho Chehab
tda1004x_do_upload(struct tda1004x_state * state,const unsigned char * mem,unsigned int len,u8 dspCodeCounterReg,u8 dspCodeInReg)3069a0bf528SMauro Carvalho Chehab static int tda1004x_do_upload(struct tda1004x_state *state,
3079a0bf528SMauro Carvalho Chehab const unsigned char *mem, unsigned int len,
3089a0bf528SMauro Carvalho Chehab u8 dspCodeCounterReg, u8 dspCodeInReg)
3099a0bf528SMauro Carvalho Chehab {
3109a0bf528SMauro Carvalho Chehab u8 buf[65];
3119a0bf528SMauro Carvalho Chehab struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 };
3129a0bf528SMauro Carvalho Chehab int tx_size;
3139a0bf528SMauro Carvalho Chehab int pos = 0;
3149a0bf528SMauro Carvalho Chehab
3159a0bf528SMauro Carvalho Chehab /* clear code counter */
3169a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, dspCodeCounterReg, 0);
3179a0bf528SMauro Carvalho Chehab fw_msg.addr = state->config->demod_address;
3189a0bf528SMauro Carvalho Chehab
3193e985b3dSPeter Rosin i2c_lock_bus(state->i2c, I2C_LOCK_SEGMENT);
3209a0bf528SMauro Carvalho Chehab buf[0] = dspCodeInReg;
3219a0bf528SMauro Carvalho Chehab while (pos != len) {
3229a0bf528SMauro Carvalho Chehab // work out how much to send this time
3239a0bf528SMauro Carvalho Chehab tx_size = len - pos;
3249a0bf528SMauro Carvalho Chehab if (tx_size > 0x10)
3259a0bf528SMauro Carvalho Chehab tx_size = 0x10;
3269a0bf528SMauro Carvalho Chehab
3279a0bf528SMauro Carvalho Chehab // send the chunk
3289a0bf528SMauro Carvalho Chehab memcpy(buf + 1, mem + pos, tx_size);
3299a0bf528SMauro Carvalho Chehab fw_msg.len = tx_size + 1;
330347c4e95SMauro Carvalho Chehab if (__i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
3319a0bf528SMauro Carvalho Chehab printk(KERN_ERR "tda1004x: Error during firmware upload\n");
3323e985b3dSPeter Rosin i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT);
3339a0bf528SMauro Carvalho Chehab return -EIO;
3349a0bf528SMauro Carvalho Chehab }
3359a0bf528SMauro Carvalho Chehab pos += tx_size;
3369a0bf528SMauro Carvalho Chehab
3379a0bf528SMauro Carvalho Chehab dprintk("%s: fw_pos=0x%x\n", __func__, pos);
3389a0bf528SMauro Carvalho Chehab }
3393e985b3dSPeter Rosin i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT);
340347c4e95SMauro Carvalho Chehab
341347c4e95SMauro Carvalho Chehab /* give the DSP a chance to settle 03/10/05 Hac */
3429a0bf528SMauro Carvalho Chehab msleep(100);
3439a0bf528SMauro Carvalho Chehab
3449a0bf528SMauro Carvalho Chehab return 0;
3459a0bf528SMauro Carvalho Chehab }
3469a0bf528SMauro Carvalho Chehab
tda1004x_check_upload_ok(struct tda1004x_state * state)3479a0bf528SMauro Carvalho Chehab static int tda1004x_check_upload_ok(struct tda1004x_state *state)
3489a0bf528SMauro Carvalho Chehab {
3499a0bf528SMauro Carvalho Chehab u8 data1, data2;
3509a0bf528SMauro Carvalho Chehab unsigned long timeout;
3519a0bf528SMauro Carvalho Chehab
3529a0bf528SMauro Carvalho Chehab if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
3539a0bf528SMauro Carvalho Chehab timeout = jiffies + 2 * HZ;
3549a0bf528SMauro Carvalho Chehab while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
3559a0bf528SMauro Carvalho Chehab if (time_after(jiffies, timeout)) {
3569a0bf528SMauro Carvalho Chehab printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
3579a0bf528SMauro Carvalho Chehab break;
3589a0bf528SMauro Carvalho Chehab }
3599a0bf528SMauro Carvalho Chehab msleep(1);
3609a0bf528SMauro Carvalho Chehab }
3619a0bf528SMauro Carvalho Chehab } else
3629a0bf528SMauro Carvalho Chehab msleep(100);
3639a0bf528SMauro Carvalho Chehab
3649a0bf528SMauro Carvalho Chehab // check upload was OK
3659a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
3669a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
3679a0bf528SMauro Carvalho Chehab
3689a0bf528SMauro Carvalho Chehab data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
3699a0bf528SMauro Carvalho Chehab data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
3709a0bf528SMauro Carvalho Chehab if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
3719a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
3729a0bf528SMauro Carvalho Chehab return -EIO;
3739a0bf528SMauro Carvalho Chehab }
3749a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
3759a0bf528SMauro Carvalho Chehab return 0;
3769a0bf528SMauro Carvalho Chehab }
3779a0bf528SMauro Carvalho Chehab
tda10045_fwupload(struct dvb_frontend * fe)3789a0bf528SMauro Carvalho Chehab static int tda10045_fwupload(struct dvb_frontend* fe)
3799a0bf528SMauro Carvalho Chehab {
3809a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
3819a0bf528SMauro Carvalho Chehab int ret;
3829a0bf528SMauro Carvalho Chehab const struct firmware *fw;
3839a0bf528SMauro Carvalho Chehab
3849a0bf528SMauro Carvalho Chehab /* don't re-upload unless necessary */
3859a0bf528SMauro Carvalho Chehab if (tda1004x_check_upload_ok(state) == 0)
3869a0bf528SMauro Carvalho Chehab return 0;
3879a0bf528SMauro Carvalho Chehab
3889a0bf528SMauro Carvalho Chehab /* request the firmware, this will block until someone uploads it */
3899a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
3909a0bf528SMauro Carvalho Chehab ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
3919a0bf528SMauro Carvalho Chehab if (ret) {
3929a0bf528SMauro Carvalho Chehab printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
3939a0bf528SMauro Carvalho Chehab return ret;
3949a0bf528SMauro Carvalho Chehab }
3959a0bf528SMauro Carvalho Chehab
3969a0bf528SMauro Carvalho Chehab /* reset chip */
3979a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);
3989a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
3999a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
4009a0bf528SMauro Carvalho Chehab msleep(10);
4019a0bf528SMauro Carvalho Chehab
4029a0bf528SMauro Carvalho Chehab /* set parameters */
4039a0bf528SMauro Carvalho Chehab tda10045h_set_bandwidth(state, 8000000);
4049a0bf528SMauro Carvalho Chehab
4059a0bf528SMauro Carvalho Chehab ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
4069a0bf528SMauro Carvalho Chehab release_firmware(fw);
4079a0bf528SMauro Carvalho Chehab if (ret)
4089a0bf528SMauro Carvalho Chehab return ret;
4099a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: firmware upload complete\n");
4109a0bf528SMauro Carvalho Chehab
4119a0bf528SMauro Carvalho Chehab /* wait for DSP to initialise */
4129a0bf528SMauro Carvalho Chehab /* DSPREADY doesn't seem to work on the TDA10045H */
4139a0bf528SMauro Carvalho Chehab msleep(100);
4149a0bf528SMauro Carvalho Chehab
4159a0bf528SMauro Carvalho Chehab return tda1004x_check_upload_ok(state);
4169a0bf528SMauro Carvalho Chehab }
4179a0bf528SMauro Carvalho Chehab
tda10046_init_plls(struct dvb_frontend * fe)4189a0bf528SMauro Carvalho Chehab static void tda10046_init_plls(struct dvb_frontend* fe)
4199a0bf528SMauro Carvalho Chehab {
4209a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
4219a0bf528SMauro Carvalho Chehab int tda10046_clk53m;
4229a0bf528SMauro Carvalho Chehab
4239a0bf528SMauro Carvalho Chehab if ((state->config->if_freq == TDA10046_FREQ_045) ||
4249a0bf528SMauro Carvalho Chehab (state->config->if_freq == TDA10046_FREQ_052))
4259a0bf528SMauro Carvalho Chehab tda10046_clk53m = 0;
4269a0bf528SMauro Carvalho Chehab else
4279a0bf528SMauro Carvalho Chehab tda10046_clk53m = 1;
4289a0bf528SMauro Carvalho Chehab
4299a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
4309a0bf528SMauro Carvalho Chehab if(tda10046_clk53m) {
4319a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
4329a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
4339a0bf528SMauro Carvalho Chehab } else {
4349a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
4359a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
4369a0bf528SMauro Carvalho Chehab }
4379a0bf528SMauro Carvalho Chehab if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
4389a0bf528SMauro Carvalho Chehab dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __func__);
4399a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
4409a0bf528SMauro Carvalho Chehab } else {
4419a0bf528SMauro Carvalho Chehab dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __func__);
4429a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
4439a0bf528SMauro Carvalho Chehab }
4449a0bf528SMauro Carvalho Chehab if(tda10046_clk53m)
4459a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
4469a0bf528SMauro Carvalho Chehab else
4479a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
4489a0bf528SMauro Carvalho Chehab /* Note clock frequency is handled implicitly */
4499a0bf528SMauro Carvalho Chehab switch (state->config->if_freq) {
4509a0bf528SMauro Carvalho Chehab case TDA10046_FREQ_045:
4519a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
4529a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
4539a0bf528SMauro Carvalho Chehab break;
4549a0bf528SMauro Carvalho Chehab case TDA10046_FREQ_052:
4559a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
4569a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
4579a0bf528SMauro Carvalho Chehab break;
4589a0bf528SMauro Carvalho Chehab case TDA10046_FREQ_3617:
4599a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4609a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
4619a0bf528SMauro Carvalho Chehab break;
4629a0bf528SMauro Carvalho Chehab case TDA10046_FREQ_3613:
4639a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
4649a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
4659a0bf528SMauro Carvalho Chehab break;
4669a0bf528SMauro Carvalho Chehab }
4679a0bf528SMauro Carvalho Chehab tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */
4689a0bf528SMauro Carvalho Chehab /* let the PLLs settle */
4699a0bf528SMauro Carvalho Chehab msleep(120);
4709a0bf528SMauro Carvalho Chehab }
4719a0bf528SMauro Carvalho Chehab
tda10046_fwupload(struct dvb_frontend * fe)4729a0bf528SMauro Carvalho Chehab static int tda10046_fwupload(struct dvb_frontend* fe)
4739a0bf528SMauro Carvalho Chehab {
4749a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
4759a0bf528SMauro Carvalho Chehab int ret, confc4;
4769a0bf528SMauro Carvalho Chehab const struct firmware *fw;
4779a0bf528SMauro Carvalho Chehab
4789a0bf528SMauro Carvalho Chehab /* reset + wake up chip */
4799a0bf528SMauro Carvalho Chehab if (state->config->xtal_freq == TDA10046_XTAL_4M) {
4809a0bf528SMauro Carvalho Chehab confc4 = 0;
4819a0bf528SMauro Carvalho Chehab } else {
4829a0bf528SMauro Carvalho Chehab dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __func__);
4839a0bf528SMauro Carvalho Chehab confc4 = 0x80;
4849a0bf528SMauro Carvalho Chehab }
4859a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
4869a0bf528SMauro Carvalho Chehab
4879a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
4889a0bf528SMauro Carvalho Chehab /* set GPIO 1 and 3 */
4899a0bf528SMauro Carvalho Chehab if (state->config->gpio_config != TDA10046_GPTRI) {
4909a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
4919a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
4929a0bf528SMauro Carvalho Chehab }
4939a0bf528SMauro Carvalho Chehab /* let the clocks recover from sleep */
4949a0bf528SMauro Carvalho Chehab msleep(10);
4959a0bf528SMauro Carvalho Chehab
4969a0bf528SMauro Carvalho Chehab /* The PLLs need to be reprogrammed after sleep */
4979a0bf528SMauro Carvalho Chehab tda10046_init_plls(fe);
4989a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0);
4999a0bf528SMauro Carvalho Chehab
5009a0bf528SMauro Carvalho Chehab /* don't re-upload unless necessary */
5019a0bf528SMauro Carvalho Chehab if (tda1004x_check_upload_ok(state) == 0)
5029a0bf528SMauro Carvalho Chehab return 0;
5039a0bf528SMauro Carvalho Chehab
5049a0bf528SMauro Carvalho Chehab /*
5059a0bf528SMauro Carvalho Chehab For i2c normal work, we need to slow down the bus speed.
5069a0bf528SMauro Carvalho Chehab However, the slow down breaks the eeprom firmware load.
5079a0bf528SMauro Carvalho Chehab So, use normal speed for eeprom booting and then restore the
5089a0bf528SMauro Carvalho Chehab i2c speed after that. Tested with MSI TV @nyware A/D board,
5099a0bf528SMauro Carvalho Chehab that comes with firmware version 29 inside their eeprom.
5109a0bf528SMauro Carvalho Chehab
5119a0bf528SMauro Carvalho Chehab It should also be noticed that no other I2C transfer should
5129a0bf528SMauro Carvalho Chehab be in course while booting from eeprom, otherwise, tda10046
5139a0bf528SMauro Carvalho Chehab goes into an instable state. So, proper locking are needed
5149a0bf528SMauro Carvalho Chehab at the i2c bus master.
5159a0bf528SMauro Carvalho Chehab */
5169a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
5179a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
5189a0bf528SMauro Carvalho Chehab msleep(300);
5199a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
5209a0bf528SMauro Carvalho Chehab
5219a0bf528SMauro Carvalho Chehab /* Checks if eeprom firmware went without troubles */
5229a0bf528SMauro Carvalho Chehab if (tda1004x_check_upload_ok(state) == 0)
5239a0bf528SMauro Carvalho Chehab return 0;
5249a0bf528SMauro Carvalho Chehab
5259a0bf528SMauro Carvalho Chehab /* eeprom firmware didn't work. Load one manually. */
5269a0bf528SMauro Carvalho Chehab
5279a0bf528SMauro Carvalho Chehab if (state->config->request_firmware != NULL) {
5289a0bf528SMauro Carvalho Chehab /* request the firmware, this will block until someone uploads it */
5299a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
5309a0bf528SMauro Carvalho Chehab ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
5319a0bf528SMauro Carvalho Chehab if (ret) {
5329a0bf528SMauro Carvalho Chehab /* remain compatible to old bug: try to load with tda10045 image name */
5339a0bf528SMauro Carvalho Chehab ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
5349a0bf528SMauro Carvalho Chehab if (ret) {
5359a0bf528SMauro Carvalho Chehab printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
5369a0bf528SMauro Carvalho Chehab return ret;
5379a0bf528SMauro Carvalho Chehab } else {
5389a0bf528SMauro Carvalho Chehab printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
5399a0bf528SMauro Carvalho Chehab TDA10046_DEFAULT_FIRMWARE);
5409a0bf528SMauro Carvalho Chehab }
5419a0bf528SMauro Carvalho Chehab }
5429a0bf528SMauro Carvalho Chehab } else {
5439a0bf528SMauro Carvalho Chehab printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
5449a0bf528SMauro Carvalho Chehab return -EIO;
5459a0bf528SMauro Carvalho Chehab }
5469a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
5479a0bf528SMauro Carvalho Chehab ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
5489a0bf528SMauro Carvalho Chehab release_firmware(fw);
5499a0bf528SMauro Carvalho Chehab return tda1004x_check_upload_ok(state);
5509a0bf528SMauro Carvalho Chehab }
5519a0bf528SMauro Carvalho Chehab
tda1004x_encode_fec(int fec)5529a0bf528SMauro Carvalho Chehab static int tda1004x_encode_fec(int fec)
5539a0bf528SMauro Carvalho Chehab {
5549a0bf528SMauro Carvalho Chehab // convert known FEC values
5559a0bf528SMauro Carvalho Chehab switch (fec) {
5569a0bf528SMauro Carvalho Chehab case FEC_1_2:
5579a0bf528SMauro Carvalho Chehab return 0;
5589a0bf528SMauro Carvalho Chehab case FEC_2_3:
5599a0bf528SMauro Carvalho Chehab return 1;
5609a0bf528SMauro Carvalho Chehab case FEC_3_4:
5619a0bf528SMauro Carvalho Chehab return 2;
5629a0bf528SMauro Carvalho Chehab case FEC_5_6:
5639a0bf528SMauro Carvalho Chehab return 3;
5649a0bf528SMauro Carvalho Chehab case FEC_7_8:
5659a0bf528SMauro Carvalho Chehab return 4;
5669a0bf528SMauro Carvalho Chehab }
5679a0bf528SMauro Carvalho Chehab
5689a0bf528SMauro Carvalho Chehab // unsupported
5699a0bf528SMauro Carvalho Chehab return -EINVAL;
5709a0bf528SMauro Carvalho Chehab }
5719a0bf528SMauro Carvalho Chehab
tda1004x_decode_fec(int tdafec)5729a0bf528SMauro Carvalho Chehab static int tda1004x_decode_fec(int tdafec)
5739a0bf528SMauro Carvalho Chehab {
5749a0bf528SMauro Carvalho Chehab // convert known FEC values
5759a0bf528SMauro Carvalho Chehab switch (tdafec) {
5769a0bf528SMauro Carvalho Chehab case 0:
5779a0bf528SMauro Carvalho Chehab return FEC_1_2;
5789a0bf528SMauro Carvalho Chehab case 1:
5799a0bf528SMauro Carvalho Chehab return FEC_2_3;
5809a0bf528SMauro Carvalho Chehab case 2:
5819a0bf528SMauro Carvalho Chehab return FEC_3_4;
5829a0bf528SMauro Carvalho Chehab case 3:
5839a0bf528SMauro Carvalho Chehab return FEC_5_6;
5849a0bf528SMauro Carvalho Chehab case 4:
5859a0bf528SMauro Carvalho Chehab return FEC_7_8;
5869a0bf528SMauro Carvalho Chehab }
5879a0bf528SMauro Carvalho Chehab
5889a0bf528SMauro Carvalho Chehab // unsupported
5899a0bf528SMauro Carvalho Chehab return -1;
5909a0bf528SMauro Carvalho Chehab }
5919a0bf528SMauro Carvalho Chehab
tda1004x_write(struct dvb_frontend * fe,const u8 buf[],int len)5929a0bf528SMauro Carvalho Chehab static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
5939a0bf528SMauro Carvalho Chehab {
5949a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
5959a0bf528SMauro Carvalho Chehab
5969a0bf528SMauro Carvalho Chehab if (len != 2)
5979a0bf528SMauro Carvalho Chehab return -EINVAL;
5989a0bf528SMauro Carvalho Chehab
5999a0bf528SMauro Carvalho Chehab return tda1004x_write_byteI(state, buf[0], buf[1]);
6009a0bf528SMauro Carvalho Chehab }
6019a0bf528SMauro Carvalho Chehab
tda10045_init(struct dvb_frontend * fe)6029a0bf528SMauro Carvalho Chehab static int tda10045_init(struct dvb_frontend* fe)
6039a0bf528SMauro Carvalho Chehab {
6049a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
6059a0bf528SMauro Carvalho Chehab
6069a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
6079a0bf528SMauro Carvalho Chehab
6089a0bf528SMauro Carvalho Chehab if (tda10045_fwupload(fe)) {
6099a0bf528SMauro Carvalho Chehab printk("tda1004x: firmware upload failed\n");
6109a0bf528SMauro Carvalho Chehab return -EIO;
6119a0bf528SMauro Carvalho Chehab }
6129a0bf528SMauro Carvalho Chehab
6139a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
6149a0bf528SMauro Carvalho Chehab
6159a0bf528SMauro Carvalho Chehab // tda setup
6169a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6179a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
6189a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal
6199a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
6209a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
6219a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
6229a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
6239a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
6249a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
6259a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
6269a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e);
6279a0bf528SMauro Carvalho Chehab
6289a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk);
6299a0bf528SMauro Carvalho Chehab
6309a0bf528SMauro Carvalho Chehab return 0;
6319a0bf528SMauro Carvalho Chehab }
6329a0bf528SMauro Carvalho Chehab
tda10046_init(struct dvb_frontend * fe)6339a0bf528SMauro Carvalho Chehab static int tda10046_init(struct dvb_frontend* fe)
6349a0bf528SMauro Carvalho Chehab {
6359a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
6369a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
6379a0bf528SMauro Carvalho Chehab
6389a0bf528SMauro Carvalho Chehab if (tda10046_fwupload(fe)) {
6399a0bf528SMauro Carvalho Chehab printk("tda1004x: firmware upload failed\n");
6409a0bf528SMauro Carvalho Chehab return -EIO;
6419a0bf528SMauro Carvalho Chehab }
6429a0bf528SMauro Carvalho Chehab
6439a0bf528SMauro Carvalho Chehab // tda setup
6449a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
6459a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
6469a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88); // enable pulse killer
6479a0bf528SMauro Carvalho Chehab
6489a0bf528SMauro Carvalho Chehab switch (state->config->agc_config) {
6499a0bf528SMauro Carvalho Chehab case TDA10046_AGC_DEFAULT:
6509a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
6519a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities
6529a0bf528SMauro Carvalho Chehab break;
6539a0bf528SMauro Carvalho Chehab case TDA10046_AGC_IFO_AUTO_NEG:
6549a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6559a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities
6569a0bf528SMauro Carvalho Chehab break;
6579a0bf528SMauro Carvalho Chehab case TDA10046_AGC_IFO_AUTO_POS:
6589a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
6599a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00); // set AGC polarities
6609a0bf528SMauro Carvalho Chehab break;
6619a0bf528SMauro Carvalho Chehab case TDA10046_AGC_TDA827X:
6629a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
6639a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
6649a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
6659a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities
6669a0bf528SMauro Carvalho Chehab break;
6679a0bf528SMauro Carvalho Chehab }
6689a0bf528SMauro Carvalho Chehab if (state->config->ts_mode == 0) {
6699a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40);
6709a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
6719a0bf528SMauro Carvalho Chehab } else {
6729a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80);
6739a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10,
6749a0bf528SMauro Carvalho Chehab state->config->invert_oclk << 4);
6759a0bf528SMauro Carvalho Chehab }
6769a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
6779a0bf528SMauro Carvalho Chehab tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on
6789a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // }
6799a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
6809a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // }
6819a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // }
6829a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
6839a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
6849a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
6859a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
6869a0bf528SMauro Carvalho Chehab // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes
6879a0bf528SMauro Carvalho Chehab
6889a0bf528SMauro Carvalho Chehab return 0;
6899a0bf528SMauro Carvalho Chehab }
6909a0bf528SMauro Carvalho Chehab
tda1004x_set_fe(struct dvb_frontend * fe)6919a0bf528SMauro Carvalho Chehab static int tda1004x_set_fe(struct dvb_frontend *fe)
6929a0bf528SMauro Carvalho Chehab {
6939a0bf528SMauro Carvalho Chehab struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
6949a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
6959a0bf528SMauro Carvalho Chehab int tmp;
6969a0bf528SMauro Carvalho Chehab int inversion;
6979a0bf528SMauro Carvalho Chehab
6989a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
6999a0bf528SMauro Carvalho Chehab
7009a0bf528SMauro Carvalho Chehab if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
7019a0bf528SMauro Carvalho Chehab // setup auto offset
7029a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10);
7039a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0);
7049a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0);
7059a0bf528SMauro Carvalho Chehab
7069a0bf528SMauro Carvalho Chehab // disable agc_conf[2]
7079a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0);
7089a0bf528SMauro Carvalho Chehab }
7099a0bf528SMauro Carvalho Chehab
7109a0bf528SMauro Carvalho Chehab // set frequency
7119a0bf528SMauro Carvalho Chehab if (fe->ops.tuner_ops.set_params) {
7129a0bf528SMauro Carvalho Chehab fe->ops.tuner_ops.set_params(fe);
7139a0bf528SMauro Carvalho Chehab if (fe->ops.i2c_gate_ctrl)
7149a0bf528SMauro Carvalho Chehab fe->ops.i2c_gate_ctrl(fe, 0);
7159a0bf528SMauro Carvalho Chehab }
7169a0bf528SMauro Carvalho Chehab
7179a0bf528SMauro Carvalho Chehab // Hardcoded to use auto as much as possible on the TDA10045 as it
7189a0bf528SMauro Carvalho Chehab // is very unreliable if AUTO mode is _not_ used.
7199a0bf528SMauro Carvalho Chehab if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
7209a0bf528SMauro Carvalho Chehab fe_params->code_rate_HP = FEC_AUTO;
7219a0bf528SMauro Carvalho Chehab fe_params->guard_interval = GUARD_INTERVAL_AUTO;
7229a0bf528SMauro Carvalho Chehab fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
7239a0bf528SMauro Carvalho Chehab }
7249a0bf528SMauro Carvalho Chehab
7259a0bf528SMauro Carvalho Chehab // Set standard params.. or put them to auto
7269a0bf528SMauro Carvalho Chehab if ((fe_params->code_rate_HP == FEC_AUTO) ||
7279a0bf528SMauro Carvalho Chehab (fe_params->code_rate_LP == FEC_AUTO) ||
7289a0bf528SMauro Carvalho Chehab (fe_params->modulation == QAM_AUTO) ||
7299a0bf528SMauro Carvalho Chehab (fe_params->hierarchy == HIERARCHY_AUTO)) {
7309a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto
7319a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); /* turn off modulation bits */
7329a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
7339a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits
7349a0bf528SMauro Carvalho Chehab } else {
7359a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto
7369a0bf528SMauro Carvalho Chehab
7379a0bf528SMauro Carvalho Chehab // set HP FEC
7389a0bf528SMauro Carvalho Chehab tmp = tda1004x_encode_fec(fe_params->code_rate_HP);
7399a0bf528SMauro Carvalho Chehab if (tmp < 0)
7409a0bf528SMauro Carvalho Chehab return tmp;
7419a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
7429a0bf528SMauro Carvalho Chehab
7439a0bf528SMauro Carvalho Chehab // set LP FEC
7449a0bf528SMauro Carvalho Chehab tmp = tda1004x_encode_fec(fe_params->code_rate_LP);
7459a0bf528SMauro Carvalho Chehab if (tmp < 0)
7469a0bf528SMauro Carvalho Chehab return tmp;
7479a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
7489a0bf528SMauro Carvalho Chehab
7499a0bf528SMauro Carvalho Chehab /* set modulation */
7509a0bf528SMauro Carvalho Chehab switch (fe_params->modulation) {
7519a0bf528SMauro Carvalho Chehab case QPSK:
7529a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
7539a0bf528SMauro Carvalho Chehab break;
7549a0bf528SMauro Carvalho Chehab
7559a0bf528SMauro Carvalho Chehab case QAM_16:
7569a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1);
7579a0bf528SMauro Carvalho Chehab break;
7589a0bf528SMauro Carvalho Chehab
7599a0bf528SMauro Carvalho Chehab case QAM_64:
7609a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2);
7619a0bf528SMauro Carvalho Chehab break;
7629a0bf528SMauro Carvalho Chehab
7639a0bf528SMauro Carvalho Chehab default:
7649a0bf528SMauro Carvalho Chehab return -EINVAL;
7659a0bf528SMauro Carvalho Chehab }
7669a0bf528SMauro Carvalho Chehab
7679a0bf528SMauro Carvalho Chehab // set hierarchy
7689a0bf528SMauro Carvalho Chehab switch (fe_params->hierarchy) {
7699a0bf528SMauro Carvalho Chehab case HIERARCHY_NONE:
7709a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
7719a0bf528SMauro Carvalho Chehab break;
7729a0bf528SMauro Carvalho Chehab
7739a0bf528SMauro Carvalho Chehab case HIERARCHY_1:
7749a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
7759a0bf528SMauro Carvalho Chehab break;
7769a0bf528SMauro Carvalho Chehab
7779a0bf528SMauro Carvalho Chehab case HIERARCHY_2:
7789a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
7799a0bf528SMauro Carvalho Chehab break;
7809a0bf528SMauro Carvalho Chehab
7819a0bf528SMauro Carvalho Chehab case HIERARCHY_4:
7829a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
7839a0bf528SMauro Carvalho Chehab break;
7849a0bf528SMauro Carvalho Chehab
7859a0bf528SMauro Carvalho Chehab default:
7869a0bf528SMauro Carvalho Chehab return -EINVAL;
7879a0bf528SMauro Carvalho Chehab }
7889a0bf528SMauro Carvalho Chehab }
7899a0bf528SMauro Carvalho Chehab
7909a0bf528SMauro Carvalho Chehab // set bandwidth
7919a0bf528SMauro Carvalho Chehab switch (state->demod_type) {
7929a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10045:
7939a0bf528SMauro Carvalho Chehab tda10045h_set_bandwidth(state, fe_params->bandwidth_hz);
7949a0bf528SMauro Carvalho Chehab break;
7959a0bf528SMauro Carvalho Chehab
7969a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10046:
7979a0bf528SMauro Carvalho Chehab tda10046h_set_bandwidth(state, fe_params->bandwidth_hz);
7989a0bf528SMauro Carvalho Chehab break;
7999a0bf528SMauro Carvalho Chehab }
8009a0bf528SMauro Carvalho Chehab
8019a0bf528SMauro Carvalho Chehab // set inversion
8029a0bf528SMauro Carvalho Chehab inversion = fe_params->inversion;
8039a0bf528SMauro Carvalho Chehab if (state->config->invert)
8049a0bf528SMauro Carvalho Chehab inversion = inversion ? INVERSION_OFF : INVERSION_ON;
8059a0bf528SMauro Carvalho Chehab switch (inversion) {
8069a0bf528SMauro Carvalho Chehab case INVERSION_OFF:
8079a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
8089a0bf528SMauro Carvalho Chehab break;
8099a0bf528SMauro Carvalho Chehab
8109a0bf528SMauro Carvalho Chehab case INVERSION_ON:
8119a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20);
8129a0bf528SMauro Carvalho Chehab break;
8139a0bf528SMauro Carvalho Chehab
8149a0bf528SMauro Carvalho Chehab default:
8159a0bf528SMauro Carvalho Chehab return -EINVAL;
8169a0bf528SMauro Carvalho Chehab }
8179a0bf528SMauro Carvalho Chehab
8189a0bf528SMauro Carvalho Chehab // set guard interval
8199a0bf528SMauro Carvalho Chehab switch (fe_params->guard_interval) {
8209a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_32:
8219a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8229a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8239a0bf528SMauro Carvalho Chehab break;
8249a0bf528SMauro Carvalho Chehab
8259a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_16:
8269a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8279a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
8289a0bf528SMauro Carvalho Chehab break;
8299a0bf528SMauro Carvalho Chehab
8309a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_8:
8319a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8329a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
8339a0bf528SMauro Carvalho Chehab break;
8349a0bf528SMauro Carvalho Chehab
8359a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_4:
8369a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
8379a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
8389a0bf528SMauro Carvalho Chehab break;
8399a0bf528SMauro Carvalho Chehab
8409a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_AUTO:
8419a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2);
8429a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
8439a0bf528SMauro Carvalho Chehab break;
8449a0bf528SMauro Carvalho Chehab
8459a0bf528SMauro Carvalho Chehab default:
8469a0bf528SMauro Carvalho Chehab return -EINVAL;
8479a0bf528SMauro Carvalho Chehab }
8489a0bf528SMauro Carvalho Chehab
8499a0bf528SMauro Carvalho Chehab // set transmission mode
8509a0bf528SMauro Carvalho Chehab switch (fe_params->transmission_mode) {
8519a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K:
8529a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8539a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
8549a0bf528SMauro Carvalho Chehab break;
8559a0bf528SMauro Carvalho Chehab
8569a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K:
8579a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
8589a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
8599a0bf528SMauro Carvalho Chehab break;
8609a0bf528SMauro Carvalho Chehab
8619a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_AUTO:
8629a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4);
8639a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0);
8649a0bf528SMauro Carvalho Chehab break;
8659a0bf528SMauro Carvalho Chehab
8669a0bf528SMauro Carvalho Chehab default:
8679a0bf528SMauro Carvalho Chehab return -EINVAL;
8689a0bf528SMauro Carvalho Chehab }
8699a0bf528SMauro Carvalho Chehab
8709a0bf528SMauro Carvalho Chehab // start the lock
8719a0bf528SMauro Carvalho Chehab switch (state->demod_type) {
8729a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10045:
8739a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
8749a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
8759a0bf528SMauro Carvalho Chehab break;
8769a0bf528SMauro Carvalho Chehab
8779a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10046:
8789a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
8799a0bf528SMauro Carvalho Chehab msleep(1);
8809a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
8819a0bf528SMauro Carvalho Chehab break;
8829a0bf528SMauro Carvalho Chehab }
8839a0bf528SMauro Carvalho Chehab
8849a0bf528SMauro Carvalho Chehab msleep(10);
8859a0bf528SMauro Carvalho Chehab
8869a0bf528SMauro Carvalho Chehab return 0;
8879a0bf528SMauro Carvalho Chehab }
8889a0bf528SMauro Carvalho Chehab
tda1004x_get_fe(struct dvb_frontend * fe,struct dtv_frontend_properties * fe_params)8897e3e68bcSMauro Carvalho Chehab static int tda1004x_get_fe(struct dvb_frontend *fe,
8907e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *fe_params)
8919a0bf528SMauro Carvalho Chehab {
8929a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
893e8beb023SMauro Carvalho Chehab int status;
8949a0bf528SMauro Carvalho Chehab
8959a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
8969a0bf528SMauro Carvalho Chehab
897e8beb023SMauro Carvalho Chehab status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
898e8beb023SMauro Carvalho Chehab if (status == -1)
899e8beb023SMauro Carvalho Chehab return -EIO;
900e8beb023SMauro Carvalho Chehab
901e8beb023SMauro Carvalho Chehab /* Only update the properties cache if device is locked */
902e8beb023SMauro Carvalho Chehab if (!(status & 8))
903e8beb023SMauro Carvalho Chehab return 0;
904e8beb023SMauro Carvalho Chehab
9059a0bf528SMauro Carvalho Chehab // inversion status
9069a0bf528SMauro Carvalho Chehab fe_params->inversion = INVERSION_OFF;
9079a0bf528SMauro Carvalho Chehab if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
9089a0bf528SMauro Carvalho Chehab fe_params->inversion = INVERSION_ON;
9099a0bf528SMauro Carvalho Chehab if (state->config->invert)
9109a0bf528SMauro Carvalho Chehab fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
9119a0bf528SMauro Carvalho Chehab
9129a0bf528SMauro Carvalho Chehab // bandwidth
9139a0bf528SMauro Carvalho Chehab switch (state->demod_type) {
9149a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10045:
9159a0bf528SMauro Carvalho Chehab switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
9169a0bf528SMauro Carvalho Chehab case 0x14:
9179a0bf528SMauro Carvalho Chehab fe_params->bandwidth_hz = 8000000;
9189a0bf528SMauro Carvalho Chehab break;
9199a0bf528SMauro Carvalho Chehab case 0xdb:
9209a0bf528SMauro Carvalho Chehab fe_params->bandwidth_hz = 7000000;
9219a0bf528SMauro Carvalho Chehab break;
9229a0bf528SMauro Carvalho Chehab case 0x4f:
9239a0bf528SMauro Carvalho Chehab fe_params->bandwidth_hz = 6000000;
9249a0bf528SMauro Carvalho Chehab break;
9259a0bf528SMauro Carvalho Chehab }
9269a0bf528SMauro Carvalho Chehab break;
9279a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10046:
9289a0bf528SMauro Carvalho Chehab switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
9299a0bf528SMauro Carvalho Chehab case 0x5c:
9309a0bf528SMauro Carvalho Chehab case 0x54:
9319a0bf528SMauro Carvalho Chehab fe_params->bandwidth_hz = 8000000;
9329a0bf528SMauro Carvalho Chehab break;
9339a0bf528SMauro Carvalho Chehab case 0x6a:
9349a0bf528SMauro Carvalho Chehab case 0x60:
9359a0bf528SMauro Carvalho Chehab fe_params->bandwidth_hz = 7000000;
9369a0bf528SMauro Carvalho Chehab break;
9379a0bf528SMauro Carvalho Chehab case 0x7b:
9389a0bf528SMauro Carvalho Chehab case 0x70:
9399a0bf528SMauro Carvalho Chehab fe_params->bandwidth_hz = 6000000;
9409a0bf528SMauro Carvalho Chehab break;
9419a0bf528SMauro Carvalho Chehab }
9429a0bf528SMauro Carvalho Chehab break;
9439a0bf528SMauro Carvalho Chehab }
9449a0bf528SMauro Carvalho Chehab
9459a0bf528SMauro Carvalho Chehab // FEC
9469a0bf528SMauro Carvalho Chehab fe_params->code_rate_HP =
9479a0bf528SMauro Carvalho Chehab tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
9489a0bf528SMauro Carvalho Chehab fe_params->code_rate_LP =
9499a0bf528SMauro Carvalho Chehab tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
9509a0bf528SMauro Carvalho Chehab
9519a0bf528SMauro Carvalho Chehab /* modulation */
9529a0bf528SMauro Carvalho Chehab switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
9539a0bf528SMauro Carvalho Chehab case 0:
9549a0bf528SMauro Carvalho Chehab fe_params->modulation = QPSK;
9559a0bf528SMauro Carvalho Chehab break;
9569a0bf528SMauro Carvalho Chehab case 1:
9579a0bf528SMauro Carvalho Chehab fe_params->modulation = QAM_16;
9589a0bf528SMauro Carvalho Chehab break;
9599a0bf528SMauro Carvalho Chehab case 2:
9609a0bf528SMauro Carvalho Chehab fe_params->modulation = QAM_64;
9619a0bf528SMauro Carvalho Chehab break;
9629a0bf528SMauro Carvalho Chehab }
9639a0bf528SMauro Carvalho Chehab
9649a0bf528SMauro Carvalho Chehab // transmission mode
9659a0bf528SMauro Carvalho Chehab fe_params->transmission_mode = TRANSMISSION_MODE_2K;
9669a0bf528SMauro Carvalho Chehab if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
9679a0bf528SMauro Carvalho Chehab fe_params->transmission_mode = TRANSMISSION_MODE_8K;
9689a0bf528SMauro Carvalho Chehab
9699a0bf528SMauro Carvalho Chehab // guard interval
9709a0bf528SMauro Carvalho Chehab switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
9719a0bf528SMauro Carvalho Chehab case 0:
9729a0bf528SMauro Carvalho Chehab fe_params->guard_interval = GUARD_INTERVAL_1_32;
9739a0bf528SMauro Carvalho Chehab break;
9749a0bf528SMauro Carvalho Chehab case 1:
9759a0bf528SMauro Carvalho Chehab fe_params->guard_interval = GUARD_INTERVAL_1_16;
9769a0bf528SMauro Carvalho Chehab break;
9779a0bf528SMauro Carvalho Chehab case 2:
9789a0bf528SMauro Carvalho Chehab fe_params->guard_interval = GUARD_INTERVAL_1_8;
9799a0bf528SMauro Carvalho Chehab break;
9809a0bf528SMauro Carvalho Chehab case 3:
9819a0bf528SMauro Carvalho Chehab fe_params->guard_interval = GUARD_INTERVAL_1_4;
9829a0bf528SMauro Carvalho Chehab break;
9839a0bf528SMauro Carvalho Chehab }
9849a0bf528SMauro Carvalho Chehab
9859a0bf528SMauro Carvalho Chehab // hierarchy
9869a0bf528SMauro Carvalho Chehab switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
9879a0bf528SMauro Carvalho Chehab case 0:
9889a0bf528SMauro Carvalho Chehab fe_params->hierarchy = HIERARCHY_NONE;
9899a0bf528SMauro Carvalho Chehab break;
9909a0bf528SMauro Carvalho Chehab case 1:
9919a0bf528SMauro Carvalho Chehab fe_params->hierarchy = HIERARCHY_1;
9929a0bf528SMauro Carvalho Chehab break;
9939a0bf528SMauro Carvalho Chehab case 2:
9949a0bf528SMauro Carvalho Chehab fe_params->hierarchy = HIERARCHY_2;
9959a0bf528SMauro Carvalho Chehab break;
9969a0bf528SMauro Carvalho Chehab case 3:
9979a0bf528SMauro Carvalho Chehab fe_params->hierarchy = HIERARCHY_4;
9989a0bf528SMauro Carvalho Chehab break;
9999a0bf528SMauro Carvalho Chehab }
10009a0bf528SMauro Carvalho Chehab
10019a0bf528SMauro Carvalho Chehab return 0;
10029a0bf528SMauro Carvalho Chehab }
10039a0bf528SMauro Carvalho Chehab
tda1004x_read_status(struct dvb_frontend * fe,enum fe_status * fe_status)10040df289a2SMauro Carvalho Chehab static int tda1004x_read_status(struct dvb_frontend *fe,
10050df289a2SMauro Carvalho Chehab enum fe_status *fe_status)
10069a0bf528SMauro Carvalho Chehab {
10079a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
10089a0bf528SMauro Carvalho Chehab int status;
10099a0bf528SMauro Carvalho Chehab int cber;
10109a0bf528SMauro Carvalho Chehab int vber;
10119a0bf528SMauro Carvalho Chehab
10129a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
10139a0bf528SMauro Carvalho Chehab
10149a0bf528SMauro Carvalho Chehab // read status
10159a0bf528SMauro Carvalho Chehab status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
10169a0bf528SMauro Carvalho Chehab if (status == -1)
10179a0bf528SMauro Carvalho Chehab return -EIO;
10189a0bf528SMauro Carvalho Chehab
10199a0bf528SMauro Carvalho Chehab // decode
10209a0bf528SMauro Carvalho Chehab *fe_status = 0;
10219a0bf528SMauro Carvalho Chehab if (status & 4)
10229a0bf528SMauro Carvalho Chehab *fe_status |= FE_HAS_SIGNAL;
10239a0bf528SMauro Carvalho Chehab if (status & 2)
10249a0bf528SMauro Carvalho Chehab *fe_status |= FE_HAS_CARRIER;
10259a0bf528SMauro Carvalho Chehab if (status & 8)
10269a0bf528SMauro Carvalho Chehab *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
10279a0bf528SMauro Carvalho Chehab
10289a0bf528SMauro Carvalho Chehab // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi
10299a0bf528SMauro Carvalho Chehab // is getting anything valid
10309a0bf528SMauro Carvalho Chehab if (!(*fe_status & FE_HAS_VITERBI)) {
10319a0bf528SMauro Carvalho Chehab // read the CBER
10329a0bf528SMauro Carvalho Chehab cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
10339a0bf528SMauro Carvalho Chehab if (cber == -1)
10349a0bf528SMauro Carvalho Chehab return -EIO;
10359a0bf528SMauro Carvalho Chehab status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
10369a0bf528SMauro Carvalho Chehab if (status == -1)
10379a0bf528SMauro Carvalho Chehab return -EIO;
10389a0bf528SMauro Carvalho Chehab cber |= (status << 8);
10399a0bf528SMauro Carvalho Chehab // The address 0x20 should be read to cope with a TDA10046 bug
10409a0bf528SMauro Carvalho Chehab tda1004x_read_byte(state, TDA1004X_CBER_RESET);
10419a0bf528SMauro Carvalho Chehab
10429a0bf528SMauro Carvalho Chehab if (cber != 65535)
10439a0bf528SMauro Carvalho Chehab *fe_status |= FE_HAS_VITERBI;
10449a0bf528SMauro Carvalho Chehab }
10459a0bf528SMauro Carvalho Chehab
10469a0bf528SMauro Carvalho Chehab // if we DO have some valid VITERBI output, but don't already have SYNC
10479a0bf528SMauro Carvalho Chehab // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
10489a0bf528SMauro Carvalho Chehab if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
10499a0bf528SMauro Carvalho Chehab // read the VBER
10509a0bf528SMauro Carvalho Chehab vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
10519a0bf528SMauro Carvalho Chehab if (vber == -1)
10529a0bf528SMauro Carvalho Chehab return -EIO;
10539a0bf528SMauro Carvalho Chehab status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
10549a0bf528SMauro Carvalho Chehab if (status == -1)
10559a0bf528SMauro Carvalho Chehab return -EIO;
10569a0bf528SMauro Carvalho Chehab vber |= (status << 8);
10579a0bf528SMauro Carvalho Chehab status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
10589a0bf528SMauro Carvalho Chehab if (status == -1)
10599a0bf528SMauro Carvalho Chehab return -EIO;
10609a0bf528SMauro Carvalho Chehab vber |= (status & 0x0f) << 16;
10619a0bf528SMauro Carvalho Chehab // The CVBER_LUT should be read to cope with TDA10046 hardware bug
10629a0bf528SMauro Carvalho Chehab tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
10639a0bf528SMauro Carvalho Chehab
10649a0bf528SMauro Carvalho Chehab // if RS has passed some valid TS packets, then we must be
10659a0bf528SMauro Carvalho Chehab // getting some SYNC bytes
10669a0bf528SMauro Carvalho Chehab if (vber < 16632)
10679a0bf528SMauro Carvalho Chehab *fe_status |= FE_HAS_SYNC;
10689a0bf528SMauro Carvalho Chehab }
10699a0bf528SMauro Carvalho Chehab
10709a0bf528SMauro Carvalho Chehab // success
10719a0bf528SMauro Carvalho Chehab dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
10729a0bf528SMauro Carvalho Chehab return 0;
10739a0bf528SMauro Carvalho Chehab }
10749a0bf528SMauro Carvalho Chehab
tda1004x_read_signal_strength(struct dvb_frontend * fe,u16 * signal)10759a0bf528SMauro Carvalho Chehab static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
10769a0bf528SMauro Carvalho Chehab {
10779a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
10789a0bf528SMauro Carvalho Chehab int tmp;
10799a0bf528SMauro Carvalho Chehab int reg = 0;
10809a0bf528SMauro Carvalho Chehab
10819a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
10829a0bf528SMauro Carvalho Chehab
10839a0bf528SMauro Carvalho Chehab // determine the register to use
10849a0bf528SMauro Carvalho Chehab switch (state->demod_type) {
10859a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10045:
10869a0bf528SMauro Carvalho Chehab reg = TDA10045H_S_AGC;
10879a0bf528SMauro Carvalho Chehab break;
10889a0bf528SMauro Carvalho Chehab
10899a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10046:
10909a0bf528SMauro Carvalho Chehab reg = TDA10046H_AGC_IF_LEVEL;
10919a0bf528SMauro Carvalho Chehab break;
10929a0bf528SMauro Carvalho Chehab }
10939a0bf528SMauro Carvalho Chehab
10949a0bf528SMauro Carvalho Chehab // read it
10959a0bf528SMauro Carvalho Chehab tmp = tda1004x_read_byte(state, reg);
10969a0bf528SMauro Carvalho Chehab if (tmp < 0)
10979a0bf528SMauro Carvalho Chehab return -EIO;
10989a0bf528SMauro Carvalho Chehab
10999a0bf528SMauro Carvalho Chehab *signal = (tmp << 8) | tmp;
11009a0bf528SMauro Carvalho Chehab dprintk("%s: signal=0x%x\n", __func__, *signal);
11019a0bf528SMauro Carvalho Chehab return 0;
11029a0bf528SMauro Carvalho Chehab }
11039a0bf528SMauro Carvalho Chehab
tda1004x_read_snr(struct dvb_frontend * fe,u16 * snr)11049a0bf528SMauro Carvalho Chehab static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
11059a0bf528SMauro Carvalho Chehab {
11069a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
11079a0bf528SMauro Carvalho Chehab int tmp;
11089a0bf528SMauro Carvalho Chehab
11099a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
11109a0bf528SMauro Carvalho Chehab
11119a0bf528SMauro Carvalho Chehab // read it
11129a0bf528SMauro Carvalho Chehab tmp = tda1004x_read_byte(state, TDA1004X_SNR);
11139a0bf528SMauro Carvalho Chehab if (tmp < 0)
11149a0bf528SMauro Carvalho Chehab return -EIO;
11159a0bf528SMauro Carvalho Chehab tmp = 255 - tmp;
11169a0bf528SMauro Carvalho Chehab
11179a0bf528SMauro Carvalho Chehab *snr = ((tmp << 8) | tmp);
11189a0bf528SMauro Carvalho Chehab dprintk("%s: snr=0x%x\n", __func__, *snr);
11199a0bf528SMauro Carvalho Chehab return 0;
11209a0bf528SMauro Carvalho Chehab }
11219a0bf528SMauro Carvalho Chehab
tda1004x_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)11229a0bf528SMauro Carvalho Chehab static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
11239a0bf528SMauro Carvalho Chehab {
11249a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
11259a0bf528SMauro Carvalho Chehab int tmp;
11269a0bf528SMauro Carvalho Chehab int tmp2;
11279a0bf528SMauro Carvalho Chehab int counter;
11289a0bf528SMauro Carvalho Chehab
11299a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
11309a0bf528SMauro Carvalho Chehab
11319a0bf528SMauro Carvalho Chehab // read the UCBLOCKS and reset
11329a0bf528SMauro Carvalho Chehab counter = 0;
11339a0bf528SMauro Carvalho Chehab tmp = tda1004x_read_byte(state, TDA1004X_UNCOR);
11349a0bf528SMauro Carvalho Chehab if (tmp < 0)
11359a0bf528SMauro Carvalho Chehab return -EIO;
11369a0bf528SMauro Carvalho Chehab tmp &= 0x7f;
11379a0bf528SMauro Carvalho Chehab while (counter++ < 5) {
11389a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11399a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11409a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
11419a0bf528SMauro Carvalho Chehab
11429a0bf528SMauro Carvalho Chehab tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR);
11439a0bf528SMauro Carvalho Chehab if (tmp2 < 0)
11449a0bf528SMauro Carvalho Chehab return -EIO;
11459a0bf528SMauro Carvalho Chehab tmp2 &= 0x7f;
11469a0bf528SMauro Carvalho Chehab if ((tmp2 < tmp) || (tmp2 == 0))
11479a0bf528SMauro Carvalho Chehab break;
11489a0bf528SMauro Carvalho Chehab }
11499a0bf528SMauro Carvalho Chehab
11509a0bf528SMauro Carvalho Chehab if (tmp != 0x7f)
11519a0bf528SMauro Carvalho Chehab *ucblocks = tmp;
11529a0bf528SMauro Carvalho Chehab else
11539a0bf528SMauro Carvalho Chehab *ucblocks = 0xffffffff;
11549a0bf528SMauro Carvalho Chehab
11559a0bf528SMauro Carvalho Chehab dprintk("%s: ucblocks=0x%x\n", __func__, *ucblocks);
11569a0bf528SMauro Carvalho Chehab return 0;
11579a0bf528SMauro Carvalho Chehab }
11589a0bf528SMauro Carvalho Chehab
tda1004x_read_ber(struct dvb_frontend * fe,u32 * ber)11599a0bf528SMauro Carvalho Chehab static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
11609a0bf528SMauro Carvalho Chehab {
11619a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
11629a0bf528SMauro Carvalho Chehab int tmp;
11639a0bf528SMauro Carvalho Chehab
11649a0bf528SMauro Carvalho Chehab dprintk("%s\n", __func__);
11659a0bf528SMauro Carvalho Chehab
11669a0bf528SMauro Carvalho Chehab // read it in
11679a0bf528SMauro Carvalho Chehab tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
11689a0bf528SMauro Carvalho Chehab if (tmp < 0)
11699a0bf528SMauro Carvalho Chehab return -EIO;
11709a0bf528SMauro Carvalho Chehab *ber = tmp << 1;
11719a0bf528SMauro Carvalho Chehab tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
11729a0bf528SMauro Carvalho Chehab if (tmp < 0)
11739a0bf528SMauro Carvalho Chehab return -EIO;
11749a0bf528SMauro Carvalho Chehab *ber |= (tmp << 9);
11759a0bf528SMauro Carvalho Chehab // The address 0x20 should be read to cope with a TDA10046 bug
11769a0bf528SMauro Carvalho Chehab tda1004x_read_byte(state, TDA1004X_CBER_RESET);
11779a0bf528SMauro Carvalho Chehab
11789a0bf528SMauro Carvalho Chehab dprintk("%s: ber=0x%x\n", __func__, *ber);
11799a0bf528SMauro Carvalho Chehab return 0;
11809a0bf528SMauro Carvalho Chehab }
11819a0bf528SMauro Carvalho Chehab
tda1004x_sleep(struct dvb_frontend * fe)11829a0bf528SMauro Carvalho Chehab static int tda1004x_sleep(struct dvb_frontend* fe)
11839a0bf528SMauro Carvalho Chehab {
11849a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
11859a0bf528SMauro Carvalho Chehab int gpio_conf;
11869a0bf528SMauro Carvalho Chehab
11879a0bf528SMauro Carvalho Chehab switch (state->demod_type) {
11889a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10045:
11899a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
11909a0bf528SMauro Carvalho Chehab break;
11919a0bf528SMauro Carvalho Chehab
11929a0bf528SMauro Carvalho Chehab case TDA1004X_DEMOD_TDA10046:
11939a0bf528SMauro Carvalho Chehab /* set outputs to tristate */
11949a0bf528SMauro Carvalho Chehab tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
11959a0bf528SMauro Carvalho Chehab /* invert GPIO 1 and 3 if desired*/
11969a0bf528SMauro Carvalho Chehab gpio_conf = state->config->gpio_config;
11979a0bf528SMauro Carvalho Chehab if (gpio_conf >= TDA10046_GP00_I)
11989a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
11999a0bf528SMauro Carvalho Chehab (gpio_conf & 0x0f) ^ 0x0a);
12009a0bf528SMauro Carvalho Chehab
12019a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0);
12029a0bf528SMauro Carvalho Chehab tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
12039a0bf528SMauro Carvalho Chehab break;
12049a0bf528SMauro Carvalho Chehab }
12059a0bf528SMauro Carvalho Chehab
12069a0bf528SMauro Carvalho Chehab return 0;
12079a0bf528SMauro Carvalho Chehab }
12089a0bf528SMauro Carvalho Chehab
tda1004x_i2c_gate_ctrl(struct dvb_frontend * fe,int enable)12099a0bf528SMauro Carvalho Chehab static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
12109a0bf528SMauro Carvalho Chehab {
12119a0bf528SMauro Carvalho Chehab struct tda1004x_state* state = fe->demodulator_priv;
12129a0bf528SMauro Carvalho Chehab
12139a0bf528SMauro Carvalho Chehab if (enable) {
12149a0bf528SMauro Carvalho Chehab return tda1004x_enable_tuner_i2c(state);
12159a0bf528SMauro Carvalho Chehab } else {
12169a0bf528SMauro Carvalho Chehab return tda1004x_disable_tuner_i2c(state);
12179a0bf528SMauro Carvalho Chehab }
12189a0bf528SMauro Carvalho Chehab }
12199a0bf528SMauro Carvalho Chehab
tda1004x_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * fesettings)12209a0bf528SMauro Carvalho Chehab static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
12219a0bf528SMauro Carvalho Chehab {
12229a0bf528SMauro Carvalho Chehab fesettings->min_delay_ms = 800;
12239a0bf528SMauro Carvalho Chehab /* Drift compensation makes no sense for DVB-T */
12249a0bf528SMauro Carvalho Chehab fesettings->step_size = 0;
12259a0bf528SMauro Carvalho Chehab fesettings->max_drift = 0;
12269a0bf528SMauro Carvalho Chehab return 0;
12279a0bf528SMauro Carvalho Chehab }
12289a0bf528SMauro Carvalho Chehab
tda1004x_release(struct dvb_frontend * fe)12299a0bf528SMauro Carvalho Chehab static void tda1004x_release(struct dvb_frontend* fe)
12309a0bf528SMauro Carvalho Chehab {
12319a0bf528SMauro Carvalho Chehab struct tda1004x_state *state = fe->demodulator_priv;
12329a0bf528SMauro Carvalho Chehab kfree(state);
12339a0bf528SMauro Carvalho Chehab }
12349a0bf528SMauro Carvalho Chehab
1235bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10045_ops = {
12369a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBT },
12379a0bf528SMauro Carvalho Chehab .info = {
12389a0bf528SMauro Carvalho Chehab .name = "Philips TDA10045H DVB-T",
1239f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 51 * MHz,
1240f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 858 * MHz,
1241f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 166667,
12429a0bf528SMauro Carvalho Chehab .caps =
12439a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
12449a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
12459a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
12469a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
12479a0bf528SMauro Carvalho Chehab },
12489a0bf528SMauro Carvalho Chehab
12499a0bf528SMauro Carvalho Chehab .release = tda1004x_release,
12509a0bf528SMauro Carvalho Chehab
12519a0bf528SMauro Carvalho Chehab .init = tda10045_init,
12529a0bf528SMauro Carvalho Chehab .sleep = tda1004x_sleep,
12539a0bf528SMauro Carvalho Chehab .write = tda1004x_write,
12549a0bf528SMauro Carvalho Chehab .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
12559a0bf528SMauro Carvalho Chehab
12569a0bf528SMauro Carvalho Chehab .set_frontend = tda1004x_set_fe,
12579a0bf528SMauro Carvalho Chehab .get_frontend = tda1004x_get_fe,
12589a0bf528SMauro Carvalho Chehab .get_tune_settings = tda1004x_get_tune_settings,
12599a0bf528SMauro Carvalho Chehab
12609a0bf528SMauro Carvalho Chehab .read_status = tda1004x_read_status,
12619a0bf528SMauro Carvalho Chehab .read_ber = tda1004x_read_ber,
12629a0bf528SMauro Carvalho Chehab .read_signal_strength = tda1004x_read_signal_strength,
12639a0bf528SMauro Carvalho Chehab .read_snr = tda1004x_read_snr,
12649a0bf528SMauro Carvalho Chehab .read_ucblocks = tda1004x_read_ucblocks,
12659a0bf528SMauro Carvalho Chehab };
12669a0bf528SMauro Carvalho Chehab
tda10045_attach(const struct tda1004x_config * config,struct i2c_adapter * i2c)12679a0bf528SMauro Carvalho Chehab struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
12689a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c)
12699a0bf528SMauro Carvalho Chehab {
12709a0bf528SMauro Carvalho Chehab struct tda1004x_state *state;
12719a0bf528SMauro Carvalho Chehab int id;
12729a0bf528SMauro Carvalho Chehab
12739a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */
12749a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
12759a0bf528SMauro Carvalho Chehab if (!state) {
12769a0bf528SMauro Carvalho Chehab printk(KERN_ERR "Can't allocate memory for tda10045 state\n");
12779a0bf528SMauro Carvalho Chehab return NULL;
12789a0bf528SMauro Carvalho Chehab }
12799a0bf528SMauro Carvalho Chehab
12809a0bf528SMauro Carvalho Chehab /* setup the state */
12819a0bf528SMauro Carvalho Chehab state->config = config;
12829a0bf528SMauro Carvalho Chehab state->i2c = i2c;
12839a0bf528SMauro Carvalho Chehab state->demod_type = TDA1004X_DEMOD_TDA10045;
12849a0bf528SMauro Carvalho Chehab
12859a0bf528SMauro Carvalho Chehab /* check if the demod is there */
12869a0bf528SMauro Carvalho Chehab id = tda1004x_read_byte(state, TDA1004X_CHIPID);
12879a0bf528SMauro Carvalho Chehab if (id < 0) {
12889a0bf528SMauro Carvalho Chehab printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
12899a0bf528SMauro Carvalho Chehab kfree(state);
12909a0bf528SMauro Carvalho Chehab return NULL;
12919a0bf528SMauro Carvalho Chehab }
12929a0bf528SMauro Carvalho Chehab
12939a0bf528SMauro Carvalho Chehab if (id != 0x25) {
12949a0bf528SMauro Carvalho Chehab printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
12959a0bf528SMauro Carvalho Chehab kfree(state);
12969a0bf528SMauro Carvalho Chehab return NULL;
12979a0bf528SMauro Carvalho Chehab }
12989a0bf528SMauro Carvalho Chehab
12999a0bf528SMauro Carvalho Chehab /* create dvb_frontend */
13009a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
13019a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state;
13029a0bf528SMauro Carvalho Chehab return &state->frontend;
13039a0bf528SMauro Carvalho Chehab }
13049a0bf528SMauro Carvalho Chehab
1305bd336e63SMax Kellermann static const struct dvb_frontend_ops tda10046_ops = {
13069a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBT },
13079a0bf528SMauro Carvalho Chehab .info = {
13089a0bf528SMauro Carvalho Chehab .name = "Philips TDA10046H DVB-T",
1309f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 51 * MHz,
1310f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 858 * MHz,
1311f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 166667,
13129a0bf528SMauro Carvalho Chehab .caps =
13139a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
13149a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
13159a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
13169a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
13179a0bf528SMauro Carvalho Chehab },
13189a0bf528SMauro Carvalho Chehab
13199a0bf528SMauro Carvalho Chehab .release = tda1004x_release,
13209a0bf528SMauro Carvalho Chehab
13219a0bf528SMauro Carvalho Chehab .init = tda10046_init,
13229a0bf528SMauro Carvalho Chehab .sleep = tda1004x_sleep,
13239a0bf528SMauro Carvalho Chehab .write = tda1004x_write,
13249a0bf528SMauro Carvalho Chehab .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
13259a0bf528SMauro Carvalho Chehab
13269a0bf528SMauro Carvalho Chehab .set_frontend = tda1004x_set_fe,
13279a0bf528SMauro Carvalho Chehab .get_frontend = tda1004x_get_fe,
13289a0bf528SMauro Carvalho Chehab .get_tune_settings = tda1004x_get_tune_settings,
13299a0bf528SMauro Carvalho Chehab
13309a0bf528SMauro Carvalho Chehab .read_status = tda1004x_read_status,
13319a0bf528SMauro Carvalho Chehab .read_ber = tda1004x_read_ber,
13329a0bf528SMauro Carvalho Chehab .read_signal_strength = tda1004x_read_signal_strength,
13339a0bf528SMauro Carvalho Chehab .read_snr = tda1004x_read_snr,
13349a0bf528SMauro Carvalho Chehab .read_ucblocks = tda1004x_read_ucblocks,
13359a0bf528SMauro Carvalho Chehab };
13369a0bf528SMauro Carvalho Chehab
tda10046_attach(const struct tda1004x_config * config,struct i2c_adapter * i2c)13379a0bf528SMauro Carvalho Chehab struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
13389a0bf528SMauro Carvalho Chehab struct i2c_adapter* i2c)
13399a0bf528SMauro Carvalho Chehab {
13409a0bf528SMauro Carvalho Chehab struct tda1004x_state *state;
13419a0bf528SMauro Carvalho Chehab int id;
13429a0bf528SMauro Carvalho Chehab
13439a0bf528SMauro Carvalho Chehab /* allocate memory for the internal state */
13449a0bf528SMauro Carvalho Chehab state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
13459a0bf528SMauro Carvalho Chehab if (!state) {
13469a0bf528SMauro Carvalho Chehab printk(KERN_ERR "Can't allocate memory for tda10046 state\n");
13479a0bf528SMauro Carvalho Chehab return NULL;
13489a0bf528SMauro Carvalho Chehab }
13499a0bf528SMauro Carvalho Chehab
13509a0bf528SMauro Carvalho Chehab /* setup the state */
13519a0bf528SMauro Carvalho Chehab state->config = config;
13529a0bf528SMauro Carvalho Chehab state->i2c = i2c;
13539a0bf528SMauro Carvalho Chehab state->demod_type = TDA1004X_DEMOD_TDA10046;
13549a0bf528SMauro Carvalho Chehab
13559a0bf528SMauro Carvalho Chehab /* check if the demod is there */
13569a0bf528SMauro Carvalho Chehab id = tda1004x_read_byte(state, TDA1004X_CHIPID);
13579a0bf528SMauro Carvalho Chehab if (id < 0) {
13589a0bf528SMauro Carvalho Chehab printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
13599a0bf528SMauro Carvalho Chehab kfree(state);
13609a0bf528SMauro Carvalho Chehab return NULL;
13619a0bf528SMauro Carvalho Chehab }
13629a0bf528SMauro Carvalho Chehab if (id != 0x46) {
13639a0bf528SMauro Carvalho Chehab printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
13649a0bf528SMauro Carvalho Chehab kfree(state);
13659a0bf528SMauro Carvalho Chehab return NULL;
13669a0bf528SMauro Carvalho Chehab }
13679a0bf528SMauro Carvalho Chehab
13689a0bf528SMauro Carvalho Chehab /* create dvb_frontend */
13699a0bf528SMauro Carvalho Chehab memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
13709a0bf528SMauro Carvalho Chehab state->frontend.demodulator_priv = state;
13719a0bf528SMauro Carvalho Chehab return &state->frontend;
13729a0bf528SMauro Carvalho Chehab }
13739a0bf528SMauro Carvalho Chehab
13749a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644);
13759a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
13769a0bf528SMauro Carvalho Chehab
13779a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");
13789a0bf528SMauro Carvalho Chehab MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
13799a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL");
13809a0bf528SMauro Carvalho Chehab
1381*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tda10045_attach);
1382*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tda10046_attach);
1383