1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29a0bf528SMauro Carvalho Chehab /* 39a0bf528SMauro Carvalho Chehab * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family. 49a0bf528SMauro Carvalho Chehab * 59a0bf528SMauro Carvalho Chehab * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/) 69a0bf528SMauro Carvalho Chehab */ 73dd72262SMauro Carvalho Chehab 83dd72262SMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 93dd72262SMauro Carvalho Chehab 109a0bf528SMauro Carvalho Chehab #include <linux/kernel.h> 119a0bf528SMauro Carvalho Chehab #include <linux/i2c.h> 129a0bf528SMauro Carvalho Chehab #include <linux/mutex.h> 139a0bf528SMauro Carvalho Chehab 14*f97fa3dcSAndy Shevchenko #include <linux/int_log.h> 15fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h> 169a0bf528SMauro Carvalho Chehab 179a0bf528SMauro Carvalho Chehab #include "dib9000.h" 189a0bf528SMauro Carvalho Chehab #include "dibx000_common.h" 199a0bf528SMauro Carvalho Chehab 209a0bf528SMauro Carvalho Chehab static int debug; 219a0bf528SMauro Carvalho Chehab module_param(debug, int, 0644); 229a0bf528SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 239a0bf528SMauro Carvalho Chehab 243dd72262SMauro Carvalho Chehab #define dprintk(fmt, arg...) do { \ 253dd72262SMauro Carvalho Chehab if (debug) \ 263dd72262SMauro Carvalho Chehab printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 273dd72262SMauro Carvalho Chehab __func__, ##arg); \ 283dd72262SMauro Carvalho Chehab } while (0) 293dd72262SMauro Carvalho Chehab 309a0bf528SMauro Carvalho Chehab #define MAX_NUMBER_OF_FRONTENDS 6 319a0bf528SMauro Carvalho Chehab 329a0bf528SMauro Carvalho Chehab struct i2c_device { 339a0bf528SMauro Carvalho Chehab struct i2c_adapter *i2c_adap; 349a0bf528SMauro Carvalho Chehab u8 i2c_addr; 359a0bf528SMauro Carvalho Chehab u8 *i2c_read_buffer; 369a0bf528SMauro Carvalho Chehab u8 *i2c_write_buffer; 379a0bf528SMauro Carvalho Chehab }; 389a0bf528SMauro Carvalho Chehab 399a0bf528SMauro Carvalho Chehab struct dib9000_pid_ctrl { 409a0bf528SMauro Carvalho Chehab #define DIB9000_PID_FILTER_CTRL 0 419a0bf528SMauro Carvalho Chehab #define DIB9000_PID_FILTER 1 429a0bf528SMauro Carvalho Chehab u8 cmd; 439a0bf528SMauro Carvalho Chehab u8 id; 449a0bf528SMauro Carvalho Chehab u16 pid; 459a0bf528SMauro Carvalho Chehab u8 onoff; 469a0bf528SMauro Carvalho Chehab }; 479a0bf528SMauro Carvalho Chehab 489a0bf528SMauro Carvalho Chehab struct dib9000_state { 499a0bf528SMauro Carvalho Chehab struct i2c_device i2c; 509a0bf528SMauro Carvalho Chehab 519a0bf528SMauro Carvalho Chehab struct dibx000_i2c_master i2c_master; 529a0bf528SMauro Carvalho Chehab struct i2c_adapter tuner_adap; 539a0bf528SMauro Carvalho Chehab struct i2c_adapter component_bus; 549a0bf528SMauro Carvalho Chehab 559a0bf528SMauro Carvalho Chehab u16 revision; 569a0bf528SMauro Carvalho Chehab u8 reg_offs; 579a0bf528SMauro Carvalho Chehab 589a0bf528SMauro Carvalho Chehab enum frontend_tune_state tune_state; 599a0bf528SMauro Carvalho Chehab u32 status; 609a0bf528SMauro Carvalho Chehab struct dvb_frontend_parametersContext channel_status; 619a0bf528SMauro Carvalho Chehab 629a0bf528SMauro Carvalho Chehab u8 fe_id; 639a0bf528SMauro Carvalho Chehab 649a0bf528SMauro Carvalho Chehab #define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff 659a0bf528SMauro Carvalho Chehab u16 gpio_dir; 669a0bf528SMauro Carvalho Chehab #define DIB9000_GPIO_DEFAULT_VALUES 0x0000 679a0bf528SMauro Carvalho Chehab u16 gpio_val; 689a0bf528SMauro Carvalho Chehab #define DIB9000_GPIO_DEFAULT_PWM_POS 0xffff 699a0bf528SMauro Carvalho Chehab u16 gpio_pwm_pos; 709a0bf528SMauro Carvalho Chehab 719a0bf528SMauro Carvalho Chehab union { /* common for all chips */ 729a0bf528SMauro Carvalho Chehab struct { 739a0bf528SMauro Carvalho Chehab u8 mobile_mode:1; 749a0bf528SMauro Carvalho Chehab } host; 759a0bf528SMauro Carvalho Chehab 769a0bf528SMauro Carvalho Chehab struct { 779a0bf528SMauro Carvalho Chehab struct dib9000_fe_memory_map { 789a0bf528SMauro Carvalho Chehab u16 addr; 799a0bf528SMauro Carvalho Chehab u16 size; 809a0bf528SMauro Carvalho Chehab } fe_mm[18]; 819a0bf528SMauro Carvalho Chehab u8 memcmd; 829a0bf528SMauro Carvalho Chehab 839a0bf528SMauro Carvalho Chehab struct mutex mbx_if_lock; /* to protect read/write operations */ 849a0bf528SMauro Carvalho Chehab struct mutex mbx_lock; /* to protect the whole mailbox handling */ 859a0bf528SMauro Carvalho Chehab 869a0bf528SMauro Carvalho Chehab struct mutex mem_lock; /* to protect the memory accesses */ 879a0bf528SMauro Carvalho Chehab struct mutex mem_mbx_lock; /* to protect the memory-based mailbox */ 889a0bf528SMauro Carvalho Chehab 899a0bf528SMauro Carvalho Chehab #define MBX_MAX_WORDS (256 - 200 - 2) 909a0bf528SMauro Carvalho Chehab #define DIB9000_MSG_CACHE_SIZE 2 919a0bf528SMauro Carvalho Chehab u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS]; 929a0bf528SMauro Carvalho Chehab u8 fw_is_running; 939a0bf528SMauro Carvalho Chehab } risc; 949a0bf528SMauro Carvalho Chehab } platform; 959a0bf528SMauro Carvalho Chehab 969a0bf528SMauro Carvalho Chehab union { /* common for all platforms */ 979a0bf528SMauro Carvalho Chehab struct { 989a0bf528SMauro Carvalho Chehab struct dib9000_config cfg; 999a0bf528SMauro Carvalho Chehab } d9; 1009a0bf528SMauro Carvalho Chehab } chip; 1019a0bf528SMauro Carvalho Chehab 1029a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; 1039a0bf528SMauro Carvalho Chehab u16 component_bus_speed; 1049a0bf528SMauro Carvalho Chehab 1059a0bf528SMauro Carvalho Chehab /* for the I2C transfer */ 1069a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2]; 1079a0bf528SMauro Carvalho Chehab u8 i2c_write_buffer[255]; 1089a0bf528SMauro Carvalho Chehab u8 i2c_read_buffer[255]; 1099a0bf528SMauro Carvalho Chehab struct mutex demod_lock; 1109a0bf528SMauro Carvalho Chehab u8 get_frontend_internal; 1119a0bf528SMauro Carvalho Chehab struct dib9000_pid_ctrl pid_ctrl[10]; 1129a0bf528SMauro Carvalho Chehab s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */ 1139a0bf528SMauro Carvalho Chehab }; 1149a0bf528SMauro Carvalho Chehab 1159a0bf528SMauro Carvalho Chehab static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1169a0bf528SMauro Carvalho Chehab 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1179a0bf528SMauro Carvalho Chehab 0, 0, 0, 0, 0, 0, 0, 0 1189a0bf528SMauro Carvalho Chehab }; 1199a0bf528SMauro Carvalho Chehab 1209a0bf528SMauro Carvalho Chehab enum dib9000_power_mode { 1219a0bf528SMauro Carvalho Chehab DIB9000_POWER_ALL = 0, 1229a0bf528SMauro Carvalho Chehab 1239a0bf528SMauro Carvalho Chehab DIB9000_POWER_NO, 1249a0bf528SMauro Carvalho Chehab DIB9000_POWER_INTERF_ANALOG_AGC, 1259a0bf528SMauro Carvalho Chehab DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, 1269a0bf528SMauro Carvalho Chehab DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD, 1279a0bf528SMauro Carvalho Chehab DIB9000_POWER_INTERFACE_ONLY, 1289a0bf528SMauro Carvalho Chehab }; 1299a0bf528SMauro Carvalho Chehab 1309a0bf528SMauro Carvalho Chehab enum dib9000_out_messages { 1319a0bf528SMauro Carvalho Chehab OUT_MSG_HBM_ACK, 1329a0bf528SMauro Carvalho Chehab OUT_MSG_HOST_BUF_FAIL, 1339a0bf528SMauro Carvalho Chehab OUT_MSG_REQ_VERSION, 1349a0bf528SMauro Carvalho Chehab OUT_MSG_BRIDGE_I2C_W, 1359a0bf528SMauro Carvalho Chehab OUT_MSG_BRIDGE_I2C_R, 1369a0bf528SMauro Carvalho Chehab OUT_MSG_BRIDGE_APB_W, 1379a0bf528SMauro Carvalho Chehab OUT_MSG_BRIDGE_APB_R, 1389a0bf528SMauro Carvalho Chehab OUT_MSG_SCAN_CHANNEL, 1399a0bf528SMauro Carvalho Chehab OUT_MSG_MONIT_DEMOD, 1409a0bf528SMauro Carvalho Chehab OUT_MSG_CONF_GPIO, 1419a0bf528SMauro Carvalho Chehab OUT_MSG_DEBUG_HELP, 1429a0bf528SMauro Carvalho Chehab OUT_MSG_SUBBAND_SEL, 1439a0bf528SMauro Carvalho Chehab OUT_MSG_ENABLE_TIME_SLICE, 1449a0bf528SMauro Carvalho Chehab OUT_MSG_FE_FW_DL, 1459a0bf528SMauro Carvalho Chehab OUT_MSG_FE_CHANNEL_SEARCH, 1469a0bf528SMauro Carvalho Chehab OUT_MSG_FE_CHANNEL_TUNE, 1479a0bf528SMauro Carvalho Chehab OUT_MSG_FE_SLEEP, 1489a0bf528SMauro Carvalho Chehab OUT_MSG_FE_SYNC, 1499a0bf528SMauro Carvalho Chehab OUT_MSG_CTL_MONIT, 1509a0bf528SMauro Carvalho Chehab 1519a0bf528SMauro Carvalho Chehab OUT_MSG_CONF_SVC, 1529a0bf528SMauro Carvalho Chehab OUT_MSG_SET_HBM, 1539a0bf528SMauro Carvalho Chehab OUT_MSG_INIT_DEMOD, 1549a0bf528SMauro Carvalho Chehab OUT_MSG_ENABLE_DIVERSITY, 1559a0bf528SMauro Carvalho Chehab OUT_MSG_SET_OUTPUT_MODE, 1569a0bf528SMauro Carvalho Chehab OUT_MSG_SET_PRIORITARY_CHANNEL, 1579a0bf528SMauro Carvalho Chehab OUT_MSG_ACK_FRG, 1589a0bf528SMauro Carvalho Chehab OUT_MSG_INIT_PMU, 1599a0bf528SMauro Carvalho Chehab }; 1609a0bf528SMauro Carvalho Chehab 1619a0bf528SMauro Carvalho Chehab enum dib9000_in_messages { 1629a0bf528SMauro Carvalho Chehab IN_MSG_DATA, 1639a0bf528SMauro Carvalho Chehab IN_MSG_FRAME_INFO, 1649a0bf528SMauro Carvalho Chehab IN_MSG_CTL_MONIT, 1659a0bf528SMauro Carvalho Chehab IN_MSG_ACK_FREE_ITEM, 1669a0bf528SMauro Carvalho Chehab IN_MSG_DEBUG_BUF, 1679a0bf528SMauro Carvalho Chehab IN_MSG_MPE_MONITOR, 1689a0bf528SMauro Carvalho Chehab IN_MSG_RAWTS_MONITOR, 1699a0bf528SMauro Carvalho Chehab IN_MSG_END_BRIDGE_I2C_RW, 1709a0bf528SMauro Carvalho Chehab IN_MSG_END_BRIDGE_APB_RW, 1719a0bf528SMauro Carvalho Chehab IN_MSG_VERSION, 1729a0bf528SMauro Carvalho Chehab IN_MSG_END_OF_SCAN, 1739a0bf528SMauro Carvalho Chehab IN_MSG_MONIT_DEMOD, 1749a0bf528SMauro Carvalho Chehab IN_MSG_ERROR, 1759a0bf528SMauro Carvalho Chehab IN_MSG_FE_FW_DL_DONE, 1769a0bf528SMauro Carvalho Chehab IN_MSG_EVENT, 1779a0bf528SMauro Carvalho Chehab IN_MSG_ACK_CHANGE_SVC, 1789a0bf528SMauro Carvalho Chehab IN_MSG_HBM_PROF, 1799a0bf528SMauro Carvalho Chehab }; 1809a0bf528SMauro Carvalho Chehab 1819a0bf528SMauro Carvalho Chehab /* memory_access requests */ 1829a0bf528SMauro Carvalho Chehab #define FE_MM_W_CHANNEL 0 1839a0bf528SMauro Carvalho Chehab #define FE_MM_W_FE_INFO 1 1849a0bf528SMauro Carvalho Chehab #define FE_MM_RW_SYNC 2 1859a0bf528SMauro Carvalho Chehab 1869a0bf528SMauro Carvalho Chehab #define FE_SYNC_CHANNEL 1 1879a0bf528SMauro Carvalho Chehab #define FE_SYNC_W_GENERIC_MONIT 2 1889a0bf528SMauro Carvalho Chehab #define FE_SYNC_COMPONENT_ACCESS 3 1899a0bf528SMauro Carvalho Chehab 1909a0bf528SMauro Carvalho Chehab #define FE_MM_R_CHANNEL_SEARCH_STATE 3 1919a0bf528SMauro Carvalho Chehab #define FE_MM_R_CHANNEL_UNION_CONTEXT 4 1929a0bf528SMauro Carvalho Chehab #define FE_MM_R_FE_INFO 5 1939a0bf528SMauro Carvalho Chehab #define FE_MM_R_FE_MONITOR 6 1949a0bf528SMauro Carvalho Chehab 1959a0bf528SMauro Carvalho Chehab #define FE_MM_W_CHANNEL_HEAD 7 1969a0bf528SMauro Carvalho Chehab #define FE_MM_W_CHANNEL_UNION 8 1979a0bf528SMauro Carvalho Chehab #define FE_MM_W_CHANNEL_CONTEXT 9 1989a0bf528SMauro Carvalho Chehab #define FE_MM_R_CHANNEL_UNION 10 1999a0bf528SMauro Carvalho Chehab #define FE_MM_R_CHANNEL_CONTEXT 11 2009a0bf528SMauro Carvalho Chehab #define FE_MM_R_CHANNEL_TUNE_STATE 12 2019a0bf528SMauro Carvalho Chehab 2029a0bf528SMauro Carvalho Chehab #define FE_MM_R_GENERIC_MONITORING_SIZE 13 2039a0bf528SMauro Carvalho Chehab #define FE_MM_W_GENERIC_MONITORING 14 2049a0bf528SMauro Carvalho Chehab #define FE_MM_R_GENERIC_MONITORING 15 2059a0bf528SMauro Carvalho Chehab 2069a0bf528SMauro Carvalho Chehab #define FE_MM_W_COMPONENT_ACCESS 16 2079a0bf528SMauro Carvalho Chehab #define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17 2089a0bf528SMauro Carvalho Chehab static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len); 2099a0bf528SMauro Carvalho Chehab static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len); 2109a0bf528SMauro Carvalho Chehab 2119a0bf528SMauro Carvalho Chehab static u16 to_fw_output_mode(u16 mode) 2129a0bf528SMauro Carvalho Chehab { 2139a0bf528SMauro Carvalho Chehab switch (mode) { 2149a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: 2159a0bf528SMauro Carvalho Chehab return 0; 2169a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 2179a0bf528SMauro Carvalho Chehab return 4; 2189a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: 2199a0bf528SMauro Carvalho Chehab return 8; 2209a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 2219a0bf528SMauro Carvalho Chehab return 16; 2229a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 2239a0bf528SMauro Carvalho Chehab return 128; 2249a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: 2259a0bf528SMauro Carvalho Chehab return 2; 2269a0bf528SMauro Carvalho Chehab case OUTMODE_ANALOG_ADC: 2279a0bf528SMauro Carvalho Chehab return 1; 2289a0bf528SMauro Carvalho Chehab default: 2299a0bf528SMauro Carvalho Chehab return 0; 2309a0bf528SMauro Carvalho Chehab } 2319a0bf528SMauro Carvalho Chehab } 2329a0bf528SMauro Carvalho Chehab 23388d0518cSMauro Carvalho Chehab static int dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 *b, u32 len, u16 attribute) 2349a0bf528SMauro Carvalho Chehab { 2359a0bf528SMauro Carvalho Chehab u32 chunk_size = 126; 2369a0bf528SMauro Carvalho Chehab u32 l; 2379a0bf528SMauro Carvalho Chehab int ret; 2389a0bf528SMauro Carvalho Chehab 2399a0bf528SMauro Carvalho Chehab if (state->platform.risc.fw_is_running && (reg < 1024)) 2409a0bf528SMauro Carvalho Chehab return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len); 2419a0bf528SMauro Carvalho Chehab 2429a0bf528SMauro Carvalho Chehab memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 2439a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.i2c_addr >> 1; 2449a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 2459a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 2469a0bf528SMauro Carvalho Chehab state->msg[0].len = 2; 2479a0bf528SMauro Carvalho Chehab state->msg[1].addr = state->i2c.i2c_addr >> 1; 2489a0bf528SMauro Carvalho Chehab state->msg[1].flags = I2C_M_RD; 2499a0bf528SMauro Carvalho Chehab state->msg[1].buf = b; 2509a0bf528SMauro Carvalho Chehab state->msg[1].len = len; 2519a0bf528SMauro Carvalho Chehab 2529a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = reg >> 8; 2539a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = reg & 0xff; 2549a0bf528SMauro Carvalho Chehab 2559a0bf528SMauro Carvalho Chehab if (attribute & DATA_BUS_ACCESS_MODE_8BIT) 2569a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] |= (1 << 5); 2579a0bf528SMauro Carvalho Chehab if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 2589a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] |= (1 << 4); 2599a0bf528SMauro Carvalho Chehab 2609a0bf528SMauro Carvalho Chehab do { 261e59a9e50Szhaoxiao l = min(len, chunk_size); 2629a0bf528SMauro Carvalho Chehab state->msg[1].len = l; 2639a0bf528SMauro Carvalho Chehab state->msg[1].buf = b; 2649a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0; 2659a0bf528SMauro Carvalho Chehab if (ret != 0) { 2663dd72262SMauro Carvalho Chehab dprintk("i2c read error on %d\n", reg); 2679a0bf528SMauro Carvalho Chehab return -EREMOTEIO; 2689a0bf528SMauro Carvalho Chehab } 2699a0bf528SMauro Carvalho Chehab 2709a0bf528SMauro Carvalho Chehab b += l; 2719a0bf528SMauro Carvalho Chehab len -= l; 2729a0bf528SMauro Carvalho Chehab 2739a0bf528SMauro Carvalho Chehab if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) 2749a0bf528SMauro Carvalho Chehab reg += l / 2; 2759a0bf528SMauro Carvalho Chehab } while ((ret == 0) && len); 2769a0bf528SMauro Carvalho Chehab 2779a0bf528SMauro Carvalho Chehab return 0; 2789a0bf528SMauro Carvalho Chehab } 2799a0bf528SMauro Carvalho Chehab 2809a0bf528SMauro Carvalho Chehab static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) 2819a0bf528SMauro Carvalho Chehab { 2829a0bf528SMauro Carvalho Chehab struct i2c_msg msg[2] = { 2839a0bf528SMauro Carvalho Chehab {.addr = i2c->i2c_addr >> 1, .flags = 0, 2849a0bf528SMauro Carvalho Chehab .buf = i2c->i2c_write_buffer, .len = 2}, 2859a0bf528SMauro Carvalho Chehab {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, 2869a0bf528SMauro Carvalho Chehab .buf = i2c->i2c_read_buffer, .len = 2}, 2879a0bf528SMauro Carvalho Chehab }; 2889a0bf528SMauro Carvalho Chehab 2899a0bf528SMauro Carvalho Chehab i2c->i2c_write_buffer[0] = reg >> 8; 2909a0bf528SMauro Carvalho Chehab i2c->i2c_write_buffer[1] = reg & 0xff; 2919a0bf528SMauro Carvalho Chehab 2929a0bf528SMauro Carvalho Chehab if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { 2933dd72262SMauro Carvalho Chehab dprintk("read register %x error\n", reg); 2949a0bf528SMauro Carvalho Chehab return 0; 2959a0bf528SMauro Carvalho Chehab } 2969a0bf528SMauro Carvalho Chehab 2979a0bf528SMauro Carvalho Chehab return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1]; 2989a0bf528SMauro Carvalho Chehab } 2999a0bf528SMauro Carvalho Chehab 3009a0bf528SMauro Carvalho Chehab static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg) 3019a0bf528SMauro Carvalho Chehab { 3029a0bf528SMauro Carvalho Chehab if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0) 3039a0bf528SMauro Carvalho Chehab return 0; 3049a0bf528SMauro Carvalho Chehab return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 3059a0bf528SMauro Carvalho Chehab } 3069a0bf528SMauro Carvalho Chehab 3079a0bf528SMauro Carvalho Chehab static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute) 3089a0bf528SMauro Carvalho Chehab { 3099a0bf528SMauro Carvalho Chehab if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 3109a0bf528SMauro Carvalho Chehab attribute) != 0) 3119a0bf528SMauro Carvalho Chehab return 0; 3129a0bf528SMauro Carvalho Chehab return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 3139a0bf528SMauro Carvalho Chehab } 3149a0bf528SMauro Carvalho Chehab 3159a0bf528SMauro Carvalho Chehab #define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 3169a0bf528SMauro Carvalho Chehab 31788d0518cSMauro Carvalho Chehab static int dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *buf, u32 len, u16 attribute) 3189a0bf528SMauro Carvalho Chehab { 3199a0bf528SMauro Carvalho Chehab u32 chunk_size = 126; 3209a0bf528SMauro Carvalho Chehab u32 l; 3219a0bf528SMauro Carvalho Chehab int ret; 3229a0bf528SMauro Carvalho Chehab 3239a0bf528SMauro Carvalho Chehab if (state->platform.risc.fw_is_running && (reg < 1024)) { 3249a0bf528SMauro Carvalho Chehab if (dib9000_risc_apb_access_write 3259a0bf528SMauro Carvalho Chehab (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) 3269a0bf528SMauro Carvalho Chehab return -EINVAL; 3279a0bf528SMauro Carvalho Chehab return 0; 3289a0bf528SMauro Carvalho Chehab } 3299a0bf528SMauro Carvalho Chehab 3309a0bf528SMauro Carvalho Chehab memset(&state->msg[0], 0, sizeof(struct i2c_msg)); 3319a0bf528SMauro Carvalho Chehab state->msg[0].addr = state->i2c.i2c_addr >> 1; 3329a0bf528SMauro Carvalho Chehab state->msg[0].flags = 0; 3339a0bf528SMauro Carvalho Chehab state->msg[0].buf = state->i2c_write_buffer; 3349a0bf528SMauro Carvalho Chehab state->msg[0].len = len + 2; 3359a0bf528SMauro Carvalho Chehab 3369a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] = (reg >> 8) & 0xff; 3379a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[1] = (reg) & 0xff; 3389a0bf528SMauro Carvalho Chehab 3399a0bf528SMauro Carvalho Chehab if (attribute & DATA_BUS_ACCESS_MODE_8BIT) 3409a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] |= (1 << 5); 3419a0bf528SMauro Carvalho Chehab if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 3429a0bf528SMauro Carvalho Chehab state->i2c_write_buffer[0] |= (1 << 4); 3439a0bf528SMauro Carvalho Chehab 3449a0bf528SMauro Carvalho Chehab do { 345e59a9e50Szhaoxiao l = min(len, chunk_size); 3469a0bf528SMauro Carvalho Chehab state->msg[0].len = l + 2; 3479a0bf528SMauro Carvalho Chehab memcpy(&state->i2c_write_buffer[2], buf, l); 3489a0bf528SMauro Carvalho Chehab 3499a0bf528SMauro Carvalho Chehab ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; 3509a0bf528SMauro Carvalho Chehab 3519a0bf528SMauro Carvalho Chehab buf += l; 3529a0bf528SMauro Carvalho Chehab len -= l; 3539a0bf528SMauro Carvalho Chehab 3549a0bf528SMauro Carvalho Chehab if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) 3559a0bf528SMauro Carvalho Chehab reg += l / 2; 3569a0bf528SMauro Carvalho Chehab } while ((ret == 0) && len); 3579a0bf528SMauro Carvalho Chehab 3589a0bf528SMauro Carvalho Chehab return ret; 3599a0bf528SMauro Carvalho Chehab } 3609a0bf528SMauro Carvalho Chehab 3619a0bf528SMauro Carvalho Chehab static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) 3629a0bf528SMauro Carvalho Chehab { 3639a0bf528SMauro Carvalho Chehab struct i2c_msg msg = { 3649a0bf528SMauro Carvalho Chehab .addr = i2c->i2c_addr >> 1, .flags = 0, 3659a0bf528SMauro Carvalho Chehab .buf = i2c->i2c_write_buffer, .len = 4 3669a0bf528SMauro Carvalho Chehab }; 3679a0bf528SMauro Carvalho Chehab 3689a0bf528SMauro Carvalho Chehab i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff; 3699a0bf528SMauro Carvalho Chehab i2c->i2c_write_buffer[1] = reg & 0xff; 3709a0bf528SMauro Carvalho Chehab i2c->i2c_write_buffer[2] = (val >> 8) & 0xff; 3719a0bf528SMauro Carvalho Chehab i2c->i2c_write_buffer[3] = val & 0xff; 3729a0bf528SMauro Carvalho Chehab 3739a0bf528SMauro Carvalho Chehab return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; 3749a0bf528SMauro Carvalho Chehab } 3759a0bf528SMauro Carvalho Chehab 3769a0bf528SMauro Carvalho Chehab static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val) 3779a0bf528SMauro Carvalho Chehab { 3789a0bf528SMauro Carvalho Chehab u8 b[2] = { val >> 8, val & 0xff }; 3799a0bf528SMauro Carvalho Chehab return dib9000_write16_attr(state, reg, b, 2, 0); 3809a0bf528SMauro Carvalho Chehab } 3819a0bf528SMauro Carvalho Chehab 3829a0bf528SMauro Carvalho Chehab static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute) 3839a0bf528SMauro Carvalho Chehab { 3849a0bf528SMauro Carvalho Chehab u8 b[2] = { val >> 8, val & 0xff }; 3859a0bf528SMauro Carvalho Chehab return dib9000_write16_attr(state, reg, b, 2, attribute); 3869a0bf528SMauro Carvalho Chehab } 3879a0bf528SMauro Carvalho Chehab 3889a0bf528SMauro Carvalho Chehab #define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0) 3899a0bf528SMauro Carvalho Chehab #define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 3909a0bf528SMauro Carvalho Chehab #define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute)) 3919a0bf528SMauro Carvalho Chehab 3929a0bf528SMauro Carvalho Chehab #define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0) 3939a0bf528SMauro Carvalho Chehab #define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0) 3949a0bf528SMauro Carvalho Chehab 3959a0bf528SMauro Carvalho Chehab #define MAC_IRQ (1 << 1) 3969a0bf528SMauro Carvalho Chehab #define IRQ_POL_MSK (1 << 4) 3979a0bf528SMauro Carvalho Chehab 3989a0bf528SMauro Carvalho Chehab #define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 3999a0bf528SMauro Carvalho Chehab #define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 4009a0bf528SMauro Carvalho Chehab 4019a0bf528SMauro Carvalho Chehab static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading) 4029a0bf528SMauro Carvalho Chehab { 4039a0bf528SMauro Carvalho Chehab u8 b[14] = { 0 }; 4049a0bf528SMauro Carvalho Chehab 4059a0bf528SMauro Carvalho Chehab /* dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */ 4069a0bf528SMauro Carvalho Chehab /* b[0] = 0 << 7; */ 4079a0bf528SMauro Carvalho Chehab b[1] = 1; 4089a0bf528SMauro Carvalho Chehab 4099a0bf528SMauro Carvalho Chehab /* b[2] = 0; */ 4109a0bf528SMauro Carvalho Chehab /* b[3] = 0; */ 4119a0bf528SMauro Carvalho Chehab b[4] = (u8) (addr >> 8); 4129a0bf528SMauro Carvalho Chehab b[5] = (u8) (addr & 0xff); 4139a0bf528SMauro Carvalho Chehab 4149a0bf528SMauro Carvalho Chehab /* b[10] = 0; */ 4159a0bf528SMauro Carvalho Chehab /* b[11] = 0; */ 4169a0bf528SMauro Carvalho Chehab b[12] = (u8) (addr >> 8); 4179a0bf528SMauro Carvalho Chehab b[13] = (u8) (addr & 0xff); 4189a0bf528SMauro Carvalho Chehab 4199a0bf528SMauro Carvalho Chehab addr += len; 4209a0bf528SMauro Carvalho Chehab /* b[6] = 0; */ 4219a0bf528SMauro Carvalho Chehab /* b[7] = 0; */ 4229a0bf528SMauro Carvalho Chehab b[8] = (u8) (addr >> 8); 4239a0bf528SMauro Carvalho Chehab b[9] = (u8) (addr & 0xff); 4249a0bf528SMauro Carvalho Chehab 4259a0bf528SMauro Carvalho Chehab dib9000_write(state, 1056, b, 14); 4269a0bf528SMauro Carvalho Chehab if (reading) 4279a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1056, (1 << 15) | 1); 4289a0bf528SMauro Carvalho Chehab state->platform.risc.memcmd = -1; /* if it was called directly reset it - to force a future setup-call to set it */ 4299a0bf528SMauro Carvalho Chehab } 4309a0bf528SMauro Carvalho Chehab 4319a0bf528SMauro Carvalho Chehab static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd) 4329a0bf528SMauro Carvalho Chehab { 4339a0bf528SMauro Carvalho Chehab struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f]; 4349a0bf528SMauro Carvalho Chehab /* decide whether we need to "refresh" the memory controller */ 4359a0bf528SMauro Carvalho Chehab if (state->platform.risc.memcmd == cmd && /* same command */ 4369a0bf528SMauro Carvalho Chehab !(cmd & 0x80 && m->size < 67)) /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */ 4379a0bf528SMauro Carvalho Chehab return; 4389a0bf528SMauro Carvalho Chehab dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80); 4399a0bf528SMauro Carvalho Chehab state->platform.risc.memcmd = cmd; 4409a0bf528SMauro Carvalho Chehab } 4419a0bf528SMauro Carvalho Chehab 4429a0bf528SMauro Carvalho Chehab static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len) 4439a0bf528SMauro Carvalho Chehab { 4449a0bf528SMauro Carvalho Chehab if (!state->platform.risc.fw_is_running) 4459a0bf528SMauro Carvalho Chehab return -EIO; 4469a0bf528SMauro Carvalho Chehab 4479a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { 4483dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 4499a0bf528SMauro Carvalho Chehab return -EINTR; 4509a0bf528SMauro Carvalho Chehab } 4519a0bf528SMauro Carvalho Chehab dib9000_risc_mem_setup(state, cmd | 0x80); 4529a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read_chunks(state, b, len); 4539a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_lock); 4549a0bf528SMauro Carvalho Chehab return 0; 4559a0bf528SMauro Carvalho Chehab } 4569a0bf528SMauro Carvalho Chehab 4579a0bf528SMauro Carvalho Chehab static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b) 4589a0bf528SMauro Carvalho Chehab { 4599a0bf528SMauro Carvalho Chehab struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd]; 4609a0bf528SMauro Carvalho Chehab if (!state->platform.risc.fw_is_running) 4619a0bf528SMauro Carvalho Chehab return -EIO; 4629a0bf528SMauro Carvalho Chehab 4639a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { 4643dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 4659a0bf528SMauro Carvalho Chehab return -EINTR; 4669a0bf528SMauro Carvalho Chehab } 4679a0bf528SMauro Carvalho Chehab dib9000_risc_mem_setup(state, cmd); 4689a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write_chunks(state, b, m->size); 4699a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_lock); 4709a0bf528SMauro Carvalho Chehab return 0; 4719a0bf528SMauro Carvalho Chehab } 4729a0bf528SMauro Carvalho Chehab 4739a0bf528SMauro Carvalho Chehab static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len) 4749a0bf528SMauro Carvalho Chehab { 4759a0bf528SMauro Carvalho Chehab u16 offs; 4769a0bf528SMauro Carvalho Chehab 4779a0bf528SMauro Carvalho Chehab if (risc_id == 1) 4789a0bf528SMauro Carvalho Chehab offs = 16; 4799a0bf528SMauro Carvalho Chehab else 4809a0bf528SMauro Carvalho Chehab offs = 0; 4819a0bf528SMauro Carvalho Chehab 4829a0bf528SMauro Carvalho Chehab /* config crtl reg */ 4839a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1024 + offs, 0x000f); 4849a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1025 + offs, 0); 4859a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1031 + offs, key); 4869a0bf528SMauro Carvalho Chehab 4873dd72262SMauro Carvalho Chehab dprintk("going to download %dB of microcode\n", len); 4889a0bf528SMauro Carvalho Chehab if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) { 4893dd72262SMauro Carvalho Chehab dprintk("error while downloading microcode for RISC %c\n", 'A' + risc_id); 4909a0bf528SMauro Carvalho Chehab return -EIO; 4919a0bf528SMauro Carvalho Chehab } 4929a0bf528SMauro Carvalho Chehab 4933dd72262SMauro Carvalho Chehab dprintk("Microcode for RISC %c loaded\n", 'A' + risc_id); 4949a0bf528SMauro Carvalho Chehab 4959a0bf528SMauro Carvalho Chehab return 0; 4969a0bf528SMauro Carvalho Chehab } 4979a0bf528SMauro Carvalho Chehab 4989a0bf528SMauro Carvalho Chehab static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id) 4999a0bf528SMauro Carvalho Chehab { 5009a0bf528SMauro Carvalho Chehab u16 mbox_offs; 5019a0bf528SMauro Carvalho Chehab u16 reset_reg; 5029a0bf528SMauro Carvalho Chehab u16 tries = 1000; 5039a0bf528SMauro Carvalho Chehab 5049a0bf528SMauro Carvalho Chehab if (risc_id == 1) 5059a0bf528SMauro Carvalho Chehab mbox_offs = 16; 5069a0bf528SMauro Carvalho Chehab else 5079a0bf528SMauro Carvalho Chehab mbox_offs = 0; 5089a0bf528SMauro Carvalho Chehab 5099a0bf528SMauro Carvalho Chehab /* Reset mailbox */ 5109a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1027 + mbox_offs, 0x8000); 5119a0bf528SMauro Carvalho Chehab 5129a0bf528SMauro Carvalho Chehab /* Read reset status */ 5139a0bf528SMauro Carvalho Chehab do { 5149a0bf528SMauro Carvalho Chehab reset_reg = dib9000_read_word(state, 1027 + mbox_offs); 5159a0bf528SMauro Carvalho Chehab msleep(100); 5169a0bf528SMauro Carvalho Chehab } while ((reset_reg & 0x8000) && --tries); 5179a0bf528SMauro Carvalho Chehab 5189a0bf528SMauro Carvalho Chehab if (reset_reg & 0x8000) { 5193dd72262SMauro Carvalho Chehab dprintk("MBX: init ERROR, no response from RISC %c\n", 'A' + risc_id); 5209a0bf528SMauro Carvalho Chehab return -EIO; 5219a0bf528SMauro Carvalho Chehab } 5223dd72262SMauro Carvalho Chehab dprintk("MBX: initialized\n"); 5239a0bf528SMauro Carvalho Chehab return 0; 5249a0bf528SMauro Carvalho Chehab } 5259a0bf528SMauro Carvalho Chehab 5269a0bf528SMauro Carvalho Chehab #define MAX_MAILBOX_TRY 100 5279a0bf528SMauro Carvalho Chehab static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr) 5289a0bf528SMauro Carvalho Chehab { 5299a0bf528SMauro Carvalho Chehab u8 *d, b[2]; 5309a0bf528SMauro Carvalho Chehab u16 tmp; 5319a0bf528SMauro Carvalho Chehab u16 size; 5329a0bf528SMauro Carvalho Chehab u32 i; 5339a0bf528SMauro Carvalho Chehab int ret = 0; 5349a0bf528SMauro Carvalho Chehab 5359a0bf528SMauro Carvalho Chehab if (!state->platform.risc.fw_is_running) 5369a0bf528SMauro Carvalho Chehab return -EINVAL; 5379a0bf528SMauro Carvalho Chehab 5389a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { 5393dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 5409a0bf528SMauro Carvalho Chehab return -EINTR; 5419a0bf528SMauro Carvalho Chehab } 5429a0bf528SMauro Carvalho Chehab tmp = MAX_MAILBOX_TRY; 5439a0bf528SMauro Carvalho Chehab do { 5449a0bf528SMauro Carvalho Chehab size = dib9000_read_word_attr(state, 1043, attr) & 0xff; 5459a0bf528SMauro Carvalho Chehab if ((size + len + 1) > MBX_MAX_WORDS && --tmp) { 5463dd72262SMauro Carvalho Chehab dprintk("MBX: RISC mbx full, retrying\n"); 5479a0bf528SMauro Carvalho Chehab msleep(100); 5489a0bf528SMauro Carvalho Chehab } else 5499a0bf528SMauro Carvalho Chehab break; 5509a0bf528SMauro Carvalho Chehab } while (1); 5519a0bf528SMauro Carvalho Chehab 5523dd72262SMauro Carvalho Chehab /*dprintk( "MBX: size: %d\n", size); */ 5539a0bf528SMauro Carvalho Chehab 5549a0bf528SMauro Carvalho Chehab if (tmp == 0) { 5559a0bf528SMauro Carvalho Chehab ret = -EINVAL; 5569a0bf528SMauro Carvalho Chehab goto out; 5579a0bf528SMauro Carvalho Chehab } 5589a0bf528SMauro Carvalho Chehab #ifdef DUMP_MSG 5593dd72262SMauro Carvalho Chehab dprintk("--> %02x %d %*ph\n", id, len + 1, len, data); 5609a0bf528SMauro Carvalho Chehab #endif 5619a0bf528SMauro Carvalho Chehab 5629a0bf528SMauro Carvalho Chehab /* byte-order conversion - works on big (where it is not necessary) or little endian */ 5639a0bf528SMauro Carvalho Chehab d = (u8 *) data; 5649a0bf528SMauro Carvalho Chehab for (i = 0; i < len; i++) { 5659a0bf528SMauro Carvalho Chehab tmp = data[i]; 5669a0bf528SMauro Carvalho Chehab *d++ = tmp >> 8; 5679a0bf528SMauro Carvalho Chehab *d++ = tmp & 0xff; 5689a0bf528SMauro Carvalho Chehab } 5699a0bf528SMauro Carvalho Chehab 5709a0bf528SMauro Carvalho Chehab /* write msg */ 5719a0bf528SMauro Carvalho Chehab b[0] = id; 5729a0bf528SMauro Carvalho Chehab b[1] = len + 1; 5739a0bf528SMauro Carvalho Chehab if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) { 5749a0bf528SMauro Carvalho Chehab ret = -EIO; 5759a0bf528SMauro Carvalho Chehab goto out; 5769a0bf528SMauro Carvalho Chehab } 5779a0bf528SMauro Carvalho Chehab 5789a0bf528SMauro Carvalho Chehab /* update register nb_mes_in_RX */ 5799a0bf528SMauro Carvalho Chehab ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); 5809a0bf528SMauro Carvalho Chehab 5819a0bf528SMauro Carvalho Chehab out: 5829a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mbx_if_lock); 5839a0bf528SMauro Carvalho Chehab 5849a0bf528SMauro Carvalho Chehab return ret; 5859a0bf528SMauro Carvalho Chehab } 5869a0bf528SMauro Carvalho Chehab 5879a0bf528SMauro Carvalho Chehab static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr) 5889a0bf528SMauro Carvalho Chehab { 5899a0bf528SMauro Carvalho Chehab #ifdef DUMP_MSG 5909a0bf528SMauro Carvalho Chehab u16 *d = data; 5919a0bf528SMauro Carvalho Chehab #endif 5929a0bf528SMauro Carvalho Chehab 5939a0bf528SMauro Carvalho Chehab u16 tmp, i; 5949a0bf528SMauro Carvalho Chehab u8 size; 5959a0bf528SMauro Carvalho Chehab u8 mc_base; 5969a0bf528SMauro Carvalho Chehab 5979a0bf528SMauro Carvalho Chehab if (!state->platform.risc.fw_is_running) 5989a0bf528SMauro Carvalho Chehab return 0; 5999a0bf528SMauro Carvalho Chehab 6009a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { 6013dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 6029a0bf528SMauro Carvalho Chehab return 0; 6039a0bf528SMauro Carvalho Chehab } 6049a0bf528SMauro Carvalho Chehab if (risc_id == 1) 6059a0bf528SMauro Carvalho Chehab mc_base = 16; 6069a0bf528SMauro Carvalho Chehab else 6079a0bf528SMauro Carvalho Chehab mc_base = 0; 6089a0bf528SMauro Carvalho Chehab 6099a0bf528SMauro Carvalho Chehab /* Length and type in the first word */ 6109a0bf528SMauro Carvalho Chehab *data = dib9000_read_word_attr(state, 1029 + mc_base, attr); 6119a0bf528SMauro Carvalho Chehab 6129a0bf528SMauro Carvalho Chehab size = *data & 0xff; 6139a0bf528SMauro Carvalho Chehab if (size <= MBX_MAX_WORDS) { 6149a0bf528SMauro Carvalho Chehab data++; 6159a0bf528SMauro Carvalho Chehab size--; /* Initial word already read */ 6169a0bf528SMauro Carvalho Chehab 6179a0bf528SMauro Carvalho Chehab dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr); 6189a0bf528SMauro Carvalho Chehab 6199a0bf528SMauro Carvalho Chehab /* to word conversion */ 6209a0bf528SMauro Carvalho Chehab for (i = 0; i < size; i++) { 6219a0bf528SMauro Carvalho Chehab tmp = *data; 6229a0bf528SMauro Carvalho Chehab *data = (tmp >> 8) | (tmp << 8); 6239a0bf528SMauro Carvalho Chehab data++; 6249a0bf528SMauro Carvalho Chehab } 6259a0bf528SMauro Carvalho Chehab 6269a0bf528SMauro Carvalho Chehab #ifdef DUMP_MSG 6273dd72262SMauro Carvalho Chehab dprintk("<--\n"); 6289a0bf528SMauro Carvalho Chehab for (i = 0; i < size + 1; i++) 6293dd72262SMauro Carvalho Chehab dprintk("%04x\n", d[i]); 6309a0bf528SMauro Carvalho Chehab dprintk("\n"); 6319a0bf528SMauro Carvalho Chehab #endif 6329a0bf528SMauro Carvalho Chehab } else { 6333dd72262SMauro Carvalho Chehab dprintk("MBX: message is too big for message cache (%d), flushing message\n", size); 6349a0bf528SMauro Carvalho Chehab size--; /* Initial word already read */ 6359a0bf528SMauro Carvalho Chehab while (size--) 6369a0bf528SMauro Carvalho Chehab dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr); 6379a0bf528SMauro Carvalho Chehab } 6389a0bf528SMauro Carvalho Chehab /* Update register nb_mes_in_TX */ 6399a0bf528SMauro Carvalho Chehab dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr); 6409a0bf528SMauro Carvalho Chehab 6419a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mbx_if_lock); 6429a0bf528SMauro Carvalho Chehab 6439a0bf528SMauro Carvalho Chehab return size + 1; 6449a0bf528SMauro Carvalho Chehab } 6459a0bf528SMauro Carvalho Chehab 6469a0bf528SMauro Carvalho Chehab static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size) 6479a0bf528SMauro Carvalho Chehab { 6489a0bf528SMauro Carvalho Chehab u32 ts = data[1] << 16 | data[0]; 6499a0bf528SMauro Carvalho Chehab char *b = (char *)&data[2]; 6509a0bf528SMauro Carvalho Chehab 6519a0bf528SMauro Carvalho Chehab b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */ 6529a0bf528SMauro Carvalho Chehab if (*b == '~') { 6539a0bf528SMauro Carvalho Chehab b++; 6543dd72262SMauro Carvalho Chehab dprintk("%s\n", b); 6559a0bf528SMauro Carvalho Chehab } else 6563dd72262SMauro Carvalho Chehab dprintk("RISC%d: %d.%04d %s\n", 6573dd72262SMauro Carvalho Chehab state->fe_id, 6583dd72262SMauro Carvalho Chehab ts / 10000, ts % 10000, *b ? b : "<empty>"); 6599a0bf528SMauro Carvalho Chehab return 1; 6609a0bf528SMauro Carvalho Chehab } 6619a0bf528SMauro Carvalho Chehab 6629a0bf528SMauro Carvalho Chehab static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) 6639a0bf528SMauro Carvalho Chehab { 6649a0bf528SMauro Carvalho Chehab int i; 6659a0bf528SMauro Carvalho Chehab u8 size; 6669a0bf528SMauro Carvalho Chehab u16 *block; 6679a0bf528SMauro Carvalho Chehab /* find a free slot */ 6689a0bf528SMauro Carvalho Chehab for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { 6699a0bf528SMauro Carvalho Chehab block = state->platform.risc.message_cache[i]; 6709a0bf528SMauro Carvalho Chehab if (*block == 0) { 6719a0bf528SMauro Carvalho Chehab size = dib9000_mbx_read(state, block, 1, attr); 6729a0bf528SMauro Carvalho Chehab 6733dd72262SMauro Carvalho Chehab /* dprintk( "MBX: fetched %04x message to cache\n", *block); */ 6749a0bf528SMauro Carvalho Chehab 6759a0bf528SMauro Carvalho Chehab switch (*block >> 8) { 6769a0bf528SMauro Carvalho Chehab case IN_MSG_DEBUG_BUF: 6779a0bf528SMauro Carvalho Chehab dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */ 6789a0bf528SMauro Carvalho Chehab *block = 0; /* free the block */ 6799a0bf528SMauro Carvalho Chehab break; 6809a0bf528SMauro Carvalho Chehab #if 0 6819a0bf528SMauro Carvalho Chehab case IN_MSG_DATA: /* FE-TRACE */ 6829a0bf528SMauro Carvalho Chehab dib9000_risc_data_process(state, block + 1, size); 6839a0bf528SMauro Carvalho Chehab *block = 0; 6849a0bf528SMauro Carvalho Chehab break; 6859a0bf528SMauro Carvalho Chehab #endif 6869a0bf528SMauro Carvalho Chehab default: 6879a0bf528SMauro Carvalho Chehab break; 6889a0bf528SMauro Carvalho Chehab } 6899a0bf528SMauro Carvalho Chehab 6909a0bf528SMauro Carvalho Chehab return 1; 6919a0bf528SMauro Carvalho Chehab } 6929a0bf528SMauro Carvalho Chehab } 6933dd72262SMauro Carvalho Chehab dprintk("MBX: no free cache-slot found for new message...\n"); 6949a0bf528SMauro Carvalho Chehab return -1; 6959a0bf528SMauro Carvalho Chehab } 6969a0bf528SMauro Carvalho Chehab 6979a0bf528SMauro Carvalho Chehab static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr) 6989a0bf528SMauro Carvalho Chehab { 6999a0bf528SMauro Carvalho Chehab if (risc_id == 0) 7009a0bf528SMauro Carvalho Chehab return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f; /* 5 bit field */ 7019a0bf528SMauro Carvalho Chehab else 7029a0bf528SMauro Carvalho Chehab return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f; /* 7 bit field */ 7039a0bf528SMauro Carvalho Chehab } 7049a0bf528SMauro Carvalho Chehab 7059a0bf528SMauro Carvalho Chehab static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) 7069a0bf528SMauro Carvalho Chehab { 7079a0bf528SMauro Carvalho Chehab int ret = 0; 7089a0bf528SMauro Carvalho Chehab 7099a0bf528SMauro Carvalho Chehab if (!state->platform.risc.fw_is_running) 7109a0bf528SMauro Carvalho Chehab return -1; 7119a0bf528SMauro Carvalho Chehab 7129a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) { 7133dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 7149a0bf528SMauro Carvalho Chehab return -1; 7159a0bf528SMauro Carvalho Chehab } 7169a0bf528SMauro Carvalho Chehab 7179a0bf528SMauro Carvalho Chehab if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ 7189a0bf528SMauro Carvalho Chehab ret = dib9000_mbx_fetch_to_cache(state, attr); 7199a0bf528SMauro Carvalho Chehab 7209a0bf528SMauro Carvalho Chehab dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ 7219a0bf528SMauro Carvalho Chehab /* if (tmp) */ 7223dd72262SMauro Carvalho Chehab /* dprintk( "cleared IRQ: %x\n", tmp); */ 7239a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mbx_lock); 7249a0bf528SMauro Carvalho Chehab 7259a0bf528SMauro Carvalho Chehab return ret; 7269a0bf528SMauro Carvalho Chehab } 7279a0bf528SMauro Carvalho Chehab 7289a0bf528SMauro Carvalho Chehab static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr) 7299a0bf528SMauro Carvalho Chehab { 7309a0bf528SMauro Carvalho Chehab u8 i; 7319a0bf528SMauro Carvalho Chehab u16 *block; 7329a0bf528SMauro Carvalho Chehab u16 timeout = 30; 7339a0bf528SMauro Carvalho Chehab 7349a0bf528SMauro Carvalho Chehab *msg = 0; 7359a0bf528SMauro Carvalho Chehab do { 7369a0bf528SMauro Carvalho Chehab /* dib9000_mbx_get_from_cache(); */ 7379a0bf528SMauro Carvalho Chehab for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { 7389a0bf528SMauro Carvalho Chehab block = state->platform.risc.message_cache[i]; 7399a0bf528SMauro Carvalho Chehab if ((*block >> 8) == id) { 7409a0bf528SMauro Carvalho Chehab *size = (*block & 0xff) - 1; 7419a0bf528SMauro Carvalho Chehab memcpy(msg, block + 1, (*size) * 2); 7429a0bf528SMauro Carvalho Chehab *block = 0; /* free the block */ 7439a0bf528SMauro Carvalho Chehab i = 0; /* signal that we found a message */ 7449a0bf528SMauro Carvalho Chehab break; 7459a0bf528SMauro Carvalho Chehab } 7469a0bf528SMauro Carvalho Chehab } 7479a0bf528SMauro Carvalho Chehab 7489a0bf528SMauro Carvalho Chehab if (i == 0) 7499a0bf528SMauro Carvalho Chehab break; 7509a0bf528SMauro Carvalho Chehab 7519a0bf528SMauro Carvalho Chehab if (dib9000_mbx_process(state, attr) == -1) /* try to fetch one message - if any */ 7529a0bf528SMauro Carvalho Chehab return -1; 7539a0bf528SMauro Carvalho Chehab 7549a0bf528SMauro Carvalho Chehab } while (--timeout); 7559a0bf528SMauro Carvalho Chehab 7569a0bf528SMauro Carvalho Chehab if (timeout == 0) { 7573dd72262SMauro Carvalho Chehab dprintk("waiting for message %d timed out\n", id); 7589a0bf528SMauro Carvalho Chehab return -1; 7599a0bf528SMauro Carvalho Chehab } 7609a0bf528SMauro Carvalho Chehab 7619a0bf528SMauro Carvalho Chehab return i == 0; 7629a0bf528SMauro Carvalho Chehab } 7639a0bf528SMauro Carvalho Chehab 7649a0bf528SMauro Carvalho Chehab static int dib9000_risc_check_version(struct dib9000_state *state) 7659a0bf528SMauro Carvalho Chehab { 7669a0bf528SMauro Carvalho Chehab u8 r[4]; 7679a0bf528SMauro Carvalho Chehab u8 size; 7689a0bf528SMauro Carvalho Chehab u16 fw_version = 0; 7699a0bf528SMauro Carvalho Chehab 7709a0bf528SMauro Carvalho Chehab if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0) 7719a0bf528SMauro Carvalho Chehab return -EIO; 7729a0bf528SMauro Carvalho Chehab 7739a0bf528SMauro Carvalho Chehab if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0) 7749a0bf528SMauro Carvalho Chehab return -EIO; 7759a0bf528SMauro Carvalho Chehab 7769a0bf528SMauro Carvalho Chehab fw_version = (r[0] << 8) | r[1]; 7773dd72262SMauro Carvalho Chehab dprintk("RISC: ver: %d.%02d (IC: %d)\n", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]); 7789a0bf528SMauro Carvalho Chehab 7799a0bf528SMauro Carvalho Chehab if ((fw_version >> 10) != 7) 7809a0bf528SMauro Carvalho Chehab return -EINVAL; 7819a0bf528SMauro Carvalho Chehab 7829a0bf528SMauro Carvalho Chehab switch (fw_version & 0x3ff) { 7839a0bf528SMauro Carvalho Chehab case 11: 7849a0bf528SMauro Carvalho Chehab case 12: 7859a0bf528SMauro Carvalho Chehab case 14: 7869a0bf528SMauro Carvalho Chehab case 15: 7879a0bf528SMauro Carvalho Chehab case 16: 7889a0bf528SMauro Carvalho Chehab case 17: 7899a0bf528SMauro Carvalho Chehab break; 7909a0bf528SMauro Carvalho Chehab default: 7919a0bf528SMauro Carvalho Chehab dprintk("RISC: invalid firmware version"); 7929a0bf528SMauro Carvalho Chehab return -EINVAL; 7939a0bf528SMauro Carvalho Chehab } 7949a0bf528SMauro Carvalho Chehab 7959a0bf528SMauro Carvalho Chehab dprintk("RISC: valid firmware version"); 7969a0bf528SMauro Carvalho Chehab return 0; 7979a0bf528SMauro Carvalho Chehab } 7989a0bf528SMauro Carvalho Chehab 7999a0bf528SMauro Carvalho Chehab static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB) 8009a0bf528SMauro Carvalho Chehab { 8019a0bf528SMauro Carvalho Chehab /* Reconfig pool mac ram */ 8029a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1225, 0x02); /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */ 8039a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1226, 0x05); 8049a0bf528SMauro Carvalho Chehab 8059a0bf528SMauro Carvalho Chehab /* Toggles IP crypto to Host APB interface. */ 8069a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1542, 1); 8079a0bf528SMauro Carvalho Chehab 8089a0bf528SMauro Carvalho Chehab /* Set jump and no jump in the dma box */ 8099a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1074, 0); 8109a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1075, 0); 8119a0bf528SMauro Carvalho Chehab 8129a0bf528SMauro Carvalho Chehab /* Set MAC as APB Master. */ 8139a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1237, 0); 8149a0bf528SMauro Carvalho Chehab 8159a0bf528SMauro Carvalho Chehab /* Reset the RISCs */ 8169a0bf528SMauro Carvalho Chehab if (codeA != NULL) 8179a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1024, 2); 8189a0bf528SMauro Carvalho Chehab else 8199a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1024, 15); 8209a0bf528SMauro Carvalho Chehab if (codeB != NULL) 8219a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1040, 2); 8229a0bf528SMauro Carvalho Chehab 8239a0bf528SMauro Carvalho Chehab if (codeA != NULL) 8249a0bf528SMauro Carvalho Chehab dib9000_firmware_download(state, 0, 0x1234, codeA, lenA); 8259a0bf528SMauro Carvalho Chehab if (codeB != NULL) 8269a0bf528SMauro Carvalho Chehab dib9000_firmware_download(state, 1, 0x1234, codeB, lenB); 8279a0bf528SMauro Carvalho Chehab 8289a0bf528SMauro Carvalho Chehab /* Run the RISCs */ 8299a0bf528SMauro Carvalho Chehab if (codeA != NULL) 8309a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1024, 0); 8319a0bf528SMauro Carvalho Chehab if (codeB != NULL) 8329a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1040, 0); 8339a0bf528SMauro Carvalho Chehab 8349a0bf528SMauro Carvalho Chehab if (codeA != NULL) 8359a0bf528SMauro Carvalho Chehab if (dib9000_mbx_host_init(state, 0) != 0) 8369a0bf528SMauro Carvalho Chehab return -EIO; 8379a0bf528SMauro Carvalho Chehab if (codeB != NULL) 8389a0bf528SMauro Carvalho Chehab if (dib9000_mbx_host_init(state, 1) != 0) 8399a0bf528SMauro Carvalho Chehab return -EIO; 8409a0bf528SMauro Carvalho Chehab 8419a0bf528SMauro Carvalho Chehab msleep(100); 8429a0bf528SMauro Carvalho Chehab state->platform.risc.fw_is_running = 1; 8439a0bf528SMauro Carvalho Chehab 8449a0bf528SMauro Carvalho Chehab if (dib9000_risc_check_version(state) != 0) 8459a0bf528SMauro Carvalho Chehab return -EINVAL; 8469a0bf528SMauro Carvalho Chehab 8479a0bf528SMauro Carvalho Chehab state->platform.risc.memcmd = 0xff; 8489a0bf528SMauro Carvalho Chehab return 0; 8499a0bf528SMauro Carvalho Chehab } 8509a0bf528SMauro Carvalho Chehab 8519a0bf528SMauro Carvalho Chehab static u16 dib9000_identify(struct i2c_device *client) 8529a0bf528SMauro Carvalho Chehab { 8539a0bf528SMauro Carvalho Chehab u16 value; 8549a0bf528SMauro Carvalho Chehab 8559a0bf528SMauro Carvalho Chehab value = dib9000_i2c_read16(client, 896); 8569a0bf528SMauro Carvalho Chehab if (value != 0x01b3) { 8573dd72262SMauro Carvalho Chehab dprintk("wrong Vendor ID (0x%x)\n", value); 8589a0bf528SMauro Carvalho Chehab return 0; 8599a0bf528SMauro Carvalho Chehab } 8609a0bf528SMauro Carvalho Chehab 8619a0bf528SMauro Carvalho Chehab value = dib9000_i2c_read16(client, 897); 8629a0bf528SMauro Carvalho Chehab if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) { 8633dd72262SMauro Carvalho Chehab dprintk("wrong Device ID (0x%x)\n", value); 8649a0bf528SMauro Carvalho Chehab return 0; 8659a0bf528SMauro Carvalho Chehab } 8669a0bf528SMauro Carvalho Chehab 8679a0bf528SMauro Carvalho Chehab /* protect this driver to be used with 7000PC */ 8689a0bf528SMauro Carvalho Chehab if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) { 8693dd72262SMauro Carvalho Chehab dprintk("this driver does not work with DiB7000PC\n"); 8709a0bf528SMauro Carvalho Chehab return 0; 8719a0bf528SMauro Carvalho Chehab } 8729a0bf528SMauro Carvalho Chehab 8739a0bf528SMauro Carvalho Chehab switch (value) { 8749a0bf528SMauro Carvalho Chehab case 0x4000: 8753dd72262SMauro Carvalho Chehab dprintk("found DiB7000MA/PA/MB/PB\n"); 8769a0bf528SMauro Carvalho Chehab break; 8779a0bf528SMauro Carvalho Chehab case 0x4001: 8783dd72262SMauro Carvalho Chehab dprintk("found DiB7000HC\n"); 8799a0bf528SMauro Carvalho Chehab break; 8809a0bf528SMauro Carvalho Chehab case 0x4002: 8813dd72262SMauro Carvalho Chehab dprintk("found DiB7000MC\n"); 8829a0bf528SMauro Carvalho Chehab break; 8839a0bf528SMauro Carvalho Chehab case 0x4003: 8843dd72262SMauro Carvalho Chehab dprintk("found DiB9000A\n"); 8859a0bf528SMauro Carvalho Chehab break; 8869a0bf528SMauro Carvalho Chehab case 0x4004: 8873dd72262SMauro Carvalho Chehab dprintk("found DiB9000H\n"); 8889a0bf528SMauro Carvalho Chehab break; 8899a0bf528SMauro Carvalho Chehab case 0x4005: 8903dd72262SMauro Carvalho Chehab dprintk("found DiB9000M\n"); 8919a0bf528SMauro Carvalho Chehab break; 8929a0bf528SMauro Carvalho Chehab } 8939a0bf528SMauro Carvalho Chehab 8949a0bf528SMauro Carvalho Chehab return value; 8959a0bf528SMauro Carvalho Chehab } 8969a0bf528SMauro Carvalho Chehab 8979a0bf528SMauro Carvalho Chehab static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode) 8989a0bf528SMauro Carvalho Chehab { 8999a0bf528SMauro Carvalho Chehab /* by default everything is going to be powered off */ 9009a0bf528SMauro Carvalho Chehab u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906; 9019a0bf528SMauro Carvalho Chehab u8 offset; 9029a0bf528SMauro Carvalho Chehab 9039a0bf528SMauro Carvalho Chehab if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005) 9049a0bf528SMauro Carvalho Chehab offset = 1; 9059a0bf528SMauro Carvalho Chehab else 9069a0bf528SMauro Carvalho Chehab offset = 0; 9079a0bf528SMauro Carvalho Chehab 9089a0bf528SMauro Carvalho Chehab reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */ 9099a0bf528SMauro Carvalho Chehab 9109a0bf528SMauro Carvalho Chehab /* now, depending on the requested mode, we power on */ 9119a0bf528SMauro Carvalho Chehab switch (mode) { 9129a0bf528SMauro Carvalho Chehab /* power up everything in the demod */ 9139a0bf528SMauro Carvalho Chehab case DIB9000_POWER_ALL: 9149a0bf528SMauro Carvalho Chehab reg_903 = 0x0000; 9159a0bf528SMauro Carvalho Chehab reg_904 = 0x0000; 9169a0bf528SMauro Carvalho Chehab reg_905 = 0x0000; 9179a0bf528SMauro Carvalho Chehab reg_906 = 0x0000; 9189a0bf528SMauro Carvalho Chehab break; 9199a0bf528SMauro Carvalho Chehab 9209a0bf528SMauro Carvalho Chehab /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ 9219a0bf528SMauro Carvalho Chehab case DIB9000_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ 9229a0bf528SMauro Carvalho Chehab reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); 9239a0bf528SMauro Carvalho Chehab break; 9249a0bf528SMauro Carvalho Chehab 9259a0bf528SMauro Carvalho Chehab case DIB9000_POWER_INTERF_ANALOG_AGC: 9269a0bf528SMauro Carvalho Chehab reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); 9279a0bf528SMauro Carvalho Chehab reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); 9289a0bf528SMauro Carvalho Chehab reg_906 &= ~((1 << 0)); 9299a0bf528SMauro Carvalho Chehab break; 9309a0bf528SMauro Carvalho Chehab 9319a0bf528SMauro Carvalho Chehab case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: 9329a0bf528SMauro Carvalho Chehab reg_903 = 0x0000; 9339a0bf528SMauro Carvalho Chehab reg_904 = 0x801f; 9349a0bf528SMauro Carvalho Chehab reg_905 = 0x0000; 9359a0bf528SMauro Carvalho Chehab reg_906 &= ~((1 << 0)); 9369a0bf528SMauro Carvalho Chehab break; 9379a0bf528SMauro Carvalho Chehab 9389a0bf528SMauro Carvalho Chehab case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD: 9399a0bf528SMauro Carvalho Chehab reg_903 = 0x0000; 9409a0bf528SMauro Carvalho Chehab reg_904 = 0x8000; 9419a0bf528SMauro Carvalho Chehab reg_905 = 0x010b; 9429a0bf528SMauro Carvalho Chehab reg_906 &= ~((1 << 0)); 9439a0bf528SMauro Carvalho Chehab break; 9449a0bf528SMauro Carvalho Chehab default: 9459a0bf528SMauro Carvalho Chehab case DIB9000_POWER_NO: 9469a0bf528SMauro Carvalho Chehab break; 9479a0bf528SMauro Carvalho Chehab } 9489a0bf528SMauro Carvalho Chehab 9499a0bf528SMauro Carvalho Chehab /* always power down unused parts */ 9509a0bf528SMauro Carvalho Chehab if (!state->platform.host.mobile_mode) 9519a0bf528SMauro Carvalho Chehab reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); 9529a0bf528SMauro Carvalho Chehab 9539a0bf528SMauro Carvalho Chehab /* P_sdio_select_clk = 0 on MC and after */ 9549a0bf528SMauro Carvalho Chehab if (state->revision != 0x4000) 9559a0bf528SMauro Carvalho Chehab reg_906 <<= 1; 9569a0bf528SMauro Carvalho Chehab 9579a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 903 + offset, reg_903); 9589a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 904 + offset, reg_904); 9599a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 905 + offset, reg_905); 9609a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 906 + offset, reg_906); 9619a0bf528SMauro Carvalho Chehab } 9629a0bf528SMauro Carvalho Chehab 9639a0bf528SMauro Carvalho Chehab static int dib9000_fw_reset(struct dvb_frontend *fe) 9649a0bf528SMauro Carvalho Chehab { 9659a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 9669a0bf528SMauro Carvalho Chehab 9679a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1817, 0x0003); 9689a0bf528SMauro Carvalho Chehab 9699a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1227, 1); 9709a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1227, 0); 9719a0bf528SMauro Carvalho Chehab 9729a0bf528SMauro Carvalho Chehab switch ((state->revision = dib9000_identify(&state->i2c))) { 9739a0bf528SMauro Carvalho Chehab case 0x4003: 9749a0bf528SMauro Carvalho Chehab case 0x4004: 9759a0bf528SMauro Carvalho Chehab case 0x4005: 9769a0bf528SMauro Carvalho Chehab state->reg_offs = 1; 9779a0bf528SMauro Carvalho Chehab break; 9789a0bf528SMauro Carvalho Chehab default: 9799a0bf528SMauro Carvalho Chehab return -EINVAL; 9809a0bf528SMauro Carvalho Chehab } 9819a0bf528SMauro Carvalho Chehab 9829a0bf528SMauro Carvalho Chehab /* reset the i2c-master to use the host interface */ 9839a0bf528SMauro Carvalho Chehab dibx000_reset_i2c_master(&state->i2c_master); 9849a0bf528SMauro Carvalho Chehab 9859a0bf528SMauro Carvalho Chehab dib9000_set_power_mode(state, DIB9000_POWER_ALL); 9869a0bf528SMauro Carvalho Chehab 9879a0bf528SMauro Carvalho Chehab /* unforce divstr regardless whether i2c enumeration was done or not */ 9889a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1)); 9899a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1796, 0); 9909a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1805, 0x805); 9919a0bf528SMauro Carvalho Chehab 9929a0bf528SMauro Carvalho Chehab /* restart all parts */ 9939a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 898, 0xffff); 9949a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 899, 0xffff); 9959a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 900, 0x0001); 9969a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 901, 0xff19); 9979a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 902, 0x003c); 9989a0bf528SMauro Carvalho Chehab 9999a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 898, 0); 10009a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 899, 0); 10019a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 900, 0); 10029a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 901, 0); 10039a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 902, 0); 10049a0bf528SMauro Carvalho Chehab 10059a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives); 10069a0bf528SMauro Carvalho Chehab 10079a0bf528SMauro Carvalho Chehab dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY); 10089a0bf528SMauro Carvalho Chehab 10099a0bf528SMauro Carvalho Chehab return 0; 10109a0bf528SMauro Carvalho Chehab } 10119a0bf528SMauro Carvalho Chehab 10129a0bf528SMauro Carvalho Chehab static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len) 10139a0bf528SMauro Carvalho Chehab { 10149a0bf528SMauro Carvalho Chehab u16 mb[10]; 10159a0bf528SMauro Carvalho Chehab u8 i, s; 10169a0bf528SMauro Carvalho Chehab 10179a0bf528SMauro Carvalho Chehab if (address >= 1024 || !state->platform.risc.fw_is_running) 10189a0bf528SMauro Carvalho Chehab return -EINVAL; 10199a0bf528SMauro Carvalho Chehab 1020868c9a17SMauro Carvalho Chehab /* dprintk( "APB access through rd fw %d %x\n", address, attribute); */ 10219a0bf528SMauro Carvalho Chehab 10229a0bf528SMauro Carvalho Chehab mb[0] = (u16) address; 10239a0bf528SMauro Carvalho Chehab mb[1] = len / 2; 10249a0bf528SMauro Carvalho Chehab dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute); 10259a0bf528SMauro Carvalho Chehab switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) { 10269a0bf528SMauro Carvalho Chehab case 1: 10279a0bf528SMauro Carvalho Chehab s--; 10289a0bf528SMauro Carvalho Chehab for (i = 0; i < s; i++) { 10299a0bf528SMauro Carvalho Chehab b[i * 2] = (mb[i + 1] >> 8) & 0xff; 10309a0bf528SMauro Carvalho Chehab b[i * 2 + 1] = (mb[i + 1]) & 0xff; 10319a0bf528SMauro Carvalho Chehab } 10329a0bf528SMauro Carvalho Chehab return 0; 10339a0bf528SMauro Carvalho Chehab default: 10349a0bf528SMauro Carvalho Chehab return -EIO; 10359a0bf528SMauro Carvalho Chehab } 10369a0bf528SMauro Carvalho Chehab return -EIO; 10379a0bf528SMauro Carvalho Chehab } 10389a0bf528SMauro Carvalho Chehab 10399a0bf528SMauro Carvalho Chehab static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len) 10409a0bf528SMauro Carvalho Chehab { 10419a0bf528SMauro Carvalho Chehab u16 mb[10]; 10429a0bf528SMauro Carvalho Chehab u8 s, i; 10439a0bf528SMauro Carvalho Chehab 10449a0bf528SMauro Carvalho Chehab if (address >= 1024 || !state->platform.risc.fw_is_running) 10459a0bf528SMauro Carvalho Chehab return -EINVAL; 10469a0bf528SMauro Carvalho Chehab 104718d75a09SHeinrich Schuchardt if (len > 18) 104818d75a09SHeinrich Schuchardt return -EINVAL; 104918d75a09SHeinrich Schuchardt 1050868c9a17SMauro Carvalho Chehab /* dprintk( "APB access through wr fw %d %x\n", address, attribute); */ 10519a0bf528SMauro Carvalho Chehab 105218d75a09SHeinrich Schuchardt mb[0] = (u16)address; 105318d75a09SHeinrich Schuchardt for (i = 0; i + 1 < len; i += 2) 105418d75a09SHeinrich Schuchardt mb[1 + i / 2] = b[i] << 8 | b[i + 1]; 105518d75a09SHeinrich Schuchardt if (len & 1) 105618d75a09SHeinrich Schuchardt mb[1 + len / 2] = b[len - 1] << 8; 10579a0bf528SMauro Carvalho Chehab 105818d75a09SHeinrich Schuchardt dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, (3 + len) / 2, attribute); 10599a0bf528SMauro Carvalho Chehab return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL; 10609a0bf528SMauro Carvalho Chehab } 10619a0bf528SMauro Carvalho Chehab 10629a0bf528SMauro Carvalho Chehab static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i) 10639a0bf528SMauro Carvalho Chehab { 10649a0bf528SMauro Carvalho Chehab u8 index_loop = 10; 10659a0bf528SMauro Carvalho Chehab 10669a0bf528SMauro Carvalho Chehab if (!state->platform.risc.fw_is_running) 10679a0bf528SMauro Carvalho Chehab return 0; 10689a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i); 10699a0bf528SMauro Carvalho Chehab do { 10709a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1); 10719a0bf528SMauro Carvalho Chehab } while (state->i2c_read_buffer[0] && index_loop--); 10729a0bf528SMauro Carvalho Chehab 10739a0bf528SMauro Carvalho Chehab if (index_loop > 0) 10749a0bf528SMauro Carvalho Chehab return 0; 10759a0bf528SMauro Carvalho Chehab return -EIO; 10769a0bf528SMauro Carvalho Chehab } 10779a0bf528SMauro Carvalho Chehab 10789a0bf528SMauro Carvalho Chehab static int dib9000_fw_init(struct dib9000_state *state) 10799a0bf528SMauro Carvalho Chehab { 10809a0bf528SMauro Carvalho Chehab struct dibGPIOFunction *f; 10819a0bf528SMauro Carvalho Chehab u16 b[40] = { 0 }; 10829a0bf528SMauro Carvalho Chehab u8 i; 10839a0bf528SMauro Carvalho Chehab u8 size; 10849a0bf528SMauro Carvalho Chehab 10859a0bf528SMauro Carvalho Chehab if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0) 10869a0bf528SMauro Carvalho Chehab return -EIO; 10879a0bf528SMauro Carvalho Chehab 10889a0bf528SMauro Carvalho Chehab /* initialize the firmware */ 10899a0bf528SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) { 10909a0bf528SMauro Carvalho Chehab f = &state->chip.d9.cfg.gpio_function[i]; 10919a0bf528SMauro Carvalho Chehab if (f->mask) { 10929a0bf528SMauro Carvalho Chehab switch (f->function) { 10939a0bf528SMauro Carvalho Chehab case BOARD_GPIO_FUNCTION_COMPONENT_ON: 10949a0bf528SMauro Carvalho Chehab b[0] = (u16) f->mask; 10959a0bf528SMauro Carvalho Chehab b[1] = (u16) f->direction; 10969a0bf528SMauro Carvalho Chehab b[2] = (u16) f->value; 10979a0bf528SMauro Carvalho Chehab break; 10989a0bf528SMauro Carvalho Chehab case BOARD_GPIO_FUNCTION_COMPONENT_OFF: 10999a0bf528SMauro Carvalho Chehab b[3] = (u16) f->mask; 11009a0bf528SMauro Carvalho Chehab b[4] = (u16) f->direction; 11019a0bf528SMauro Carvalho Chehab b[5] = (u16) f->value; 11029a0bf528SMauro Carvalho Chehab break; 11039a0bf528SMauro Carvalho Chehab } 11049a0bf528SMauro Carvalho Chehab } 11059a0bf528SMauro Carvalho Chehab } 11069a0bf528SMauro Carvalho Chehab if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0) 11079a0bf528SMauro Carvalho Chehab return -EIO; 11089a0bf528SMauro Carvalho Chehab 11099a0bf528SMauro Carvalho Chehab /* subband */ 11109a0bf528SMauro Carvalho Chehab b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */ 11119a0bf528SMauro Carvalho Chehab for (i = 0; i < state->chip.d9.cfg.subband.size; i++) { 11129a0bf528SMauro Carvalho Chehab b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz; 11139a0bf528SMauro Carvalho Chehab b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask; 11149a0bf528SMauro Carvalho Chehab b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction; 11159a0bf528SMauro Carvalho Chehab b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value; 11169a0bf528SMauro Carvalho Chehab } 11179a0bf528SMauro Carvalho Chehab b[1 + i * 4] = 0; /* fe_id */ 11189a0bf528SMauro Carvalho Chehab if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0) 11199a0bf528SMauro Carvalho Chehab return -EIO; 11209a0bf528SMauro Carvalho Chehab 11219a0bf528SMauro Carvalho Chehab /* 0 - id, 1 - no_of_frontends */ 11229a0bf528SMauro Carvalho Chehab b[0] = (0 << 8) | 1; 11239a0bf528SMauro Carvalho Chehab /* 0 = i2c-address demod, 0 = tuner */ 11249a0bf528SMauro Carvalho Chehab b[1] = (0 << 8) | (0); 11259a0bf528SMauro Carvalho Chehab b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff); 11269a0bf528SMauro Carvalho Chehab b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff); 11279a0bf528SMauro Carvalho Chehab b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff); 11289a0bf528SMauro Carvalho Chehab b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff); 11299a0bf528SMauro Carvalho Chehab b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff); 11309a0bf528SMauro Carvalho Chehab b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff); 11319a0bf528SMauro Carvalho Chehab b[29] = state->chip.d9.cfg.if_drives; 11329a0bf528SMauro Carvalho Chehab if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0) 11339a0bf528SMauro Carvalho Chehab return -EIO; 11349a0bf528SMauro Carvalho Chehab 11359a0bf528SMauro Carvalho Chehab if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0) 11369a0bf528SMauro Carvalho Chehab return -EIO; 11379a0bf528SMauro Carvalho Chehab 11389a0bf528SMauro Carvalho Chehab if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0) 11399a0bf528SMauro Carvalho Chehab return -EIO; 11409a0bf528SMauro Carvalho Chehab 11419a0bf528SMauro Carvalho Chehab if (size > ARRAY_SIZE(b)) { 11429a0bf528SMauro Carvalho Chehab dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size, 11439a0bf528SMauro Carvalho Chehab (int)ARRAY_SIZE(b)); 11449a0bf528SMauro Carvalho Chehab return -EINVAL; 11459a0bf528SMauro Carvalho Chehab } 11469a0bf528SMauro Carvalho Chehab 11479a0bf528SMauro Carvalho Chehab for (i = 0; i < size; i += 2) { 11489a0bf528SMauro Carvalho Chehab state->platform.risc.fe_mm[i / 2].addr = b[i + 0]; 11499a0bf528SMauro Carvalho Chehab state->platform.risc.fe_mm[i / 2].size = b[i + 1]; 11509a0bf528SMauro Carvalho Chehab } 11519a0bf528SMauro Carvalho Chehab 11529a0bf528SMauro Carvalho Chehab return 0; 11539a0bf528SMauro Carvalho Chehab } 11549a0bf528SMauro Carvalho Chehab 11559a0bf528SMauro Carvalho Chehab static void dib9000_fw_set_channel_head(struct dib9000_state *state) 11569a0bf528SMauro Carvalho Chehab { 11579a0bf528SMauro Carvalho Chehab u8 b[9]; 11589a0bf528SMauro Carvalho Chehab u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000; 11599a0bf528SMauro Carvalho Chehab if (state->fe_id % 2) 11609a0bf528SMauro Carvalho Chehab freq += 101; 11619a0bf528SMauro Carvalho Chehab 11629a0bf528SMauro Carvalho Chehab b[0] = (u8) ((freq >> 0) & 0xff); 11639a0bf528SMauro Carvalho Chehab b[1] = (u8) ((freq >> 8) & 0xff); 11649a0bf528SMauro Carvalho Chehab b[2] = (u8) ((freq >> 16) & 0xff); 11659a0bf528SMauro Carvalho Chehab b[3] = (u8) ((freq >> 24) & 0xff); 11669a0bf528SMauro Carvalho Chehab b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff); 11679a0bf528SMauro Carvalho Chehab b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff); 11689a0bf528SMauro Carvalho Chehab b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff); 11699a0bf528SMauro Carvalho Chehab b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff); 11709a0bf528SMauro Carvalho Chehab b[8] = 0x80; /* do not wait for CELL ID when doing autosearch */ 11719a0bf528SMauro Carvalho Chehab if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT) 11729a0bf528SMauro Carvalho Chehab b[8] |= 1; 11739a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b); 11749a0bf528SMauro Carvalho Chehab } 11759a0bf528SMauro Carvalho Chehab 11769a0bf528SMauro Carvalho Chehab static int dib9000_fw_get_channel(struct dvb_frontend *fe) 11779a0bf528SMauro Carvalho Chehab { 11789a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 11799a0bf528SMauro Carvalho Chehab struct dibDVBTChannel { 11809a0bf528SMauro Carvalho Chehab s8 spectrum_inversion; 11819a0bf528SMauro Carvalho Chehab 11829a0bf528SMauro Carvalho Chehab s8 nfft; 11839a0bf528SMauro Carvalho Chehab s8 guard; 11849a0bf528SMauro Carvalho Chehab s8 constellation; 11859a0bf528SMauro Carvalho Chehab 11869a0bf528SMauro Carvalho Chehab s8 hrch; 11879a0bf528SMauro Carvalho Chehab s8 alpha; 11889a0bf528SMauro Carvalho Chehab s8 code_rate_hp; 11899a0bf528SMauro Carvalho Chehab s8 code_rate_lp; 11909a0bf528SMauro Carvalho Chehab s8 select_hp; 11919a0bf528SMauro Carvalho Chehab 11929a0bf528SMauro Carvalho Chehab s8 intlv_native; 11939a0bf528SMauro Carvalho Chehab }; 11949a0bf528SMauro Carvalho Chehab struct dibDVBTChannel *ch; 11959a0bf528SMauro Carvalho Chehab int ret = 0; 11969a0bf528SMauro Carvalho Chehab 11979a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 11983dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 11999a0bf528SMauro Carvalho Chehab return -EINTR; 12009a0bf528SMauro Carvalho Chehab } 12019a0bf528SMauro Carvalho Chehab if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 12029a0bf528SMauro Carvalho Chehab ret = -EIO; 12039a0bf528SMauro Carvalho Chehab goto error; 12049a0bf528SMauro Carvalho Chehab } 12059a0bf528SMauro Carvalho Chehab 12069a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, 12079a0bf528SMauro Carvalho Chehab state->i2c_read_buffer, sizeof(struct dibDVBTChannel)); 12089a0bf528SMauro Carvalho Chehab ch = (struct dibDVBTChannel *)state->i2c_read_buffer; 12099a0bf528SMauro Carvalho Chehab 12109a0bf528SMauro Carvalho Chehab 12119a0bf528SMauro Carvalho Chehab switch (ch->spectrum_inversion & 0x7) { 12129a0bf528SMauro Carvalho Chehab case 1: 12139a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.inversion = INVERSION_ON; 12149a0bf528SMauro Carvalho Chehab break; 12159a0bf528SMauro Carvalho Chehab case 0: 12169a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF; 12179a0bf528SMauro Carvalho Chehab break; 12189a0bf528SMauro Carvalho Chehab default: 12199a0bf528SMauro Carvalho Chehab case -1: 12209a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO; 12219a0bf528SMauro Carvalho Chehab break; 12229a0bf528SMauro Carvalho Chehab } 12239a0bf528SMauro Carvalho Chehab switch (ch->nfft) { 12249a0bf528SMauro Carvalho Chehab case 0: 12259a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; 12269a0bf528SMauro Carvalho Chehab break; 12279a0bf528SMauro Carvalho Chehab case 2: 12289a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K; 12299a0bf528SMauro Carvalho Chehab break; 12309a0bf528SMauro Carvalho Chehab case 1: 12319a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; 12329a0bf528SMauro Carvalho Chehab break; 12339a0bf528SMauro Carvalho Chehab default: 12349a0bf528SMauro Carvalho Chehab case -1: 12359a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; 12369a0bf528SMauro Carvalho Chehab break; 12379a0bf528SMauro Carvalho Chehab } 12389a0bf528SMauro Carvalho Chehab switch (ch->guard) { 12399a0bf528SMauro Carvalho Chehab case 0: 12409a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; 12419a0bf528SMauro Carvalho Chehab break; 12429a0bf528SMauro Carvalho Chehab case 1: 12439a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; 12449a0bf528SMauro Carvalho Chehab break; 12459a0bf528SMauro Carvalho Chehab case 2: 12469a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; 12479a0bf528SMauro Carvalho Chehab break; 12489a0bf528SMauro Carvalho Chehab case 3: 12499a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; 12509a0bf528SMauro Carvalho Chehab break; 12519a0bf528SMauro Carvalho Chehab default: 12529a0bf528SMauro Carvalho Chehab case -1: 12539a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; 12549a0bf528SMauro Carvalho Chehab break; 12559a0bf528SMauro Carvalho Chehab } 12569a0bf528SMauro Carvalho Chehab switch (ch->constellation) { 12579a0bf528SMauro Carvalho Chehab case 2: 12589a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.modulation = QAM_64; 12599a0bf528SMauro Carvalho Chehab break; 12609a0bf528SMauro Carvalho Chehab case 1: 12619a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.modulation = QAM_16; 12629a0bf528SMauro Carvalho Chehab break; 12639a0bf528SMauro Carvalho Chehab case 0: 12649a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.modulation = QPSK; 12659a0bf528SMauro Carvalho Chehab break; 12669a0bf528SMauro Carvalho Chehab default: 12679a0bf528SMauro Carvalho Chehab case -1: 12689a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.modulation = QAM_AUTO; 12699a0bf528SMauro Carvalho Chehab break; 12709a0bf528SMauro Carvalho Chehab } 12719a0bf528SMauro Carvalho Chehab switch (ch->hrch) { 12729a0bf528SMauro Carvalho Chehab case 0: 12739a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE; 12749a0bf528SMauro Carvalho Chehab break; 12759a0bf528SMauro Carvalho Chehab case 1: 12769a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1; 12779a0bf528SMauro Carvalho Chehab break; 12789a0bf528SMauro Carvalho Chehab default: 12799a0bf528SMauro Carvalho Chehab case -1: 12809a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO; 12819a0bf528SMauro Carvalho Chehab break; 12829a0bf528SMauro Carvalho Chehab } 12839a0bf528SMauro Carvalho Chehab switch (ch->code_rate_hp) { 12849a0bf528SMauro Carvalho Chehab case 1: 12859a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2; 12869a0bf528SMauro Carvalho Chehab break; 12879a0bf528SMauro Carvalho Chehab case 2: 12889a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3; 12899a0bf528SMauro Carvalho Chehab break; 12909a0bf528SMauro Carvalho Chehab case 3: 12919a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4; 12929a0bf528SMauro Carvalho Chehab break; 12939a0bf528SMauro Carvalho Chehab case 5: 12949a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6; 12959a0bf528SMauro Carvalho Chehab break; 12969a0bf528SMauro Carvalho Chehab case 7: 12979a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8; 12989a0bf528SMauro Carvalho Chehab break; 12999a0bf528SMauro Carvalho Chehab default: 13009a0bf528SMauro Carvalho Chehab case -1: 13019a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO; 13029a0bf528SMauro Carvalho Chehab break; 13039a0bf528SMauro Carvalho Chehab } 13049a0bf528SMauro Carvalho Chehab switch (ch->code_rate_lp) { 13059a0bf528SMauro Carvalho Chehab case 1: 13069a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2; 13079a0bf528SMauro Carvalho Chehab break; 13089a0bf528SMauro Carvalho Chehab case 2: 13099a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3; 13109a0bf528SMauro Carvalho Chehab break; 13119a0bf528SMauro Carvalho Chehab case 3: 13129a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4; 13139a0bf528SMauro Carvalho Chehab break; 13149a0bf528SMauro Carvalho Chehab case 5: 13159a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6; 13169a0bf528SMauro Carvalho Chehab break; 13179a0bf528SMauro Carvalho Chehab case 7: 13189a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8; 13199a0bf528SMauro Carvalho Chehab break; 13209a0bf528SMauro Carvalho Chehab default: 13219a0bf528SMauro Carvalho Chehab case -1: 13229a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO; 13239a0bf528SMauro Carvalho Chehab break; 13249a0bf528SMauro Carvalho Chehab } 13259a0bf528SMauro Carvalho Chehab 13269a0bf528SMauro Carvalho Chehab error: 13279a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 13289a0bf528SMauro Carvalho Chehab return ret; 13299a0bf528SMauro Carvalho Chehab } 13309a0bf528SMauro Carvalho Chehab 13319a0bf528SMauro Carvalho Chehab static int dib9000_fw_set_channel_union(struct dvb_frontend *fe) 13329a0bf528SMauro Carvalho Chehab { 13339a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 13349a0bf528SMauro Carvalho Chehab struct dibDVBTChannel { 13359a0bf528SMauro Carvalho Chehab s8 spectrum_inversion; 13369a0bf528SMauro Carvalho Chehab 13379a0bf528SMauro Carvalho Chehab s8 nfft; 13389a0bf528SMauro Carvalho Chehab s8 guard; 13399a0bf528SMauro Carvalho Chehab s8 constellation; 13409a0bf528SMauro Carvalho Chehab 13419a0bf528SMauro Carvalho Chehab s8 hrch; 13429a0bf528SMauro Carvalho Chehab s8 alpha; 13439a0bf528SMauro Carvalho Chehab s8 code_rate_hp; 13449a0bf528SMauro Carvalho Chehab s8 code_rate_lp; 13459a0bf528SMauro Carvalho Chehab s8 select_hp; 13469a0bf528SMauro Carvalho Chehab 13479a0bf528SMauro Carvalho Chehab s8 intlv_native; 13489a0bf528SMauro Carvalho Chehab }; 13499a0bf528SMauro Carvalho Chehab struct dibDVBTChannel ch; 13509a0bf528SMauro Carvalho Chehab 13519a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.inversion) { 13529a0bf528SMauro Carvalho Chehab case INVERSION_ON: 13539a0bf528SMauro Carvalho Chehab ch.spectrum_inversion = 1; 13549a0bf528SMauro Carvalho Chehab break; 13559a0bf528SMauro Carvalho Chehab case INVERSION_OFF: 13569a0bf528SMauro Carvalho Chehab ch.spectrum_inversion = 0; 13579a0bf528SMauro Carvalho Chehab break; 13589a0bf528SMauro Carvalho Chehab default: 13599a0bf528SMauro Carvalho Chehab case INVERSION_AUTO: 13609a0bf528SMauro Carvalho Chehab ch.spectrum_inversion = -1; 13619a0bf528SMauro Carvalho Chehab break; 13629a0bf528SMauro Carvalho Chehab } 13639a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.transmission_mode) { 13649a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 13659a0bf528SMauro Carvalho Chehab ch.nfft = 0; 13669a0bf528SMauro Carvalho Chehab break; 13679a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_4K: 13689a0bf528SMauro Carvalho Chehab ch.nfft = 2; 13699a0bf528SMauro Carvalho Chehab break; 13709a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 13719a0bf528SMauro Carvalho Chehab ch.nfft = 1; 13729a0bf528SMauro Carvalho Chehab break; 13739a0bf528SMauro Carvalho Chehab default: 13749a0bf528SMauro Carvalho Chehab case TRANSMISSION_MODE_AUTO: 13759a0bf528SMauro Carvalho Chehab ch.nfft = 1; 13769a0bf528SMauro Carvalho Chehab break; 13779a0bf528SMauro Carvalho Chehab } 13789a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.guard_interval) { 13799a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 13809a0bf528SMauro Carvalho Chehab ch.guard = 0; 13819a0bf528SMauro Carvalho Chehab break; 13829a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 13839a0bf528SMauro Carvalho Chehab ch.guard = 1; 13849a0bf528SMauro Carvalho Chehab break; 13859a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 13869a0bf528SMauro Carvalho Chehab ch.guard = 2; 13879a0bf528SMauro Carvalho Chehab break; 13889a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 13899a0bf528SMauro Carvalho Chehab ch.guard = 3; 13909a0bf528SMauro Carvalho Chehab break; 13919a0bf528SMauro Carvalho Chehab default: 13929a0bf528SMauro Carvalho Chehab case GUARD_INTERVAL_AUTO: 13939a0bf528SMauro Carvalho Chehab ch.guard = -1; 13949a0bf528SMauro Carvalho Chehab break; 13959a0bf528SMauro Carvalho Chehab } 13969a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.modulation) { 13979a0bf528SMauro Carvalho Chehab case QAM_64: 13989a0bf528SMauro Carvalho Chehab ch.constellation = 2; 13999a0bf528SMauro Carvalho Chehab break; 14009a0bf528SMauro Carvalho Chehab case QAM_16: 14019a0bf528SMauro Carvalho Chehab ch.constellation = 1; 14029a0bf528SMauro Carvalho Chehab break; 14039a0bf528SMauro Carvalho Chehab case QPSK: 14049a0bf528SMauro Carvalho Chehab ch.constellation = 0; 14059a0bf528SMauro Carvalho Chehab break; 14069a0bf528SMauro Carvalho Chehab default: 14079a0bf528SMauro Carvalho Chehab case QAM_AUTO: 14089a0bf528SMauro Carvalho Chehab ch.constellation = -1; 14099a0bf528SMauro Carvalho Chehab break; 14109a0bf528SMauro Carvalho Chehab } 14119a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.hierarchy) { 14129a0bf528SMauro Carvalho Chehab case HIERARCHY_NONE: 14139a0bf528SMauro Carvalho Chehab ch.hrch = 0; 14149a0bf528SMauro Carvalho Chehab break; 14159a0bf528SMauro Carvalho Chehab case HIERARCHY_1: 14169a0bf528SMauro Carvalho Chehab case HIERARCHY_2: 14179a0bf528SMauro Carvalho Chehab case HIERARCHY_4: 14189a0bf528SMauro Carvalho Chehab ch.hrch = 1; 14199a0bf528SMauro Carvalho Chehab break; 14209a0bf528SMauro Carvalho Chehab default: 14219a0bf528SMauro Carvalho Chehab case HIERARCHY_AUTO: 14229a0bf528SMauro Carvalho Chehab ch.hrch = -1; 14239a0bf528SMauro Carvalho Chehab break; 14249a0bf528SMauro Carvalho Chehab } 14259a0bf528SMauro Carvalho Chehab ch.alpha = 1; 14269a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.code_rate_HP) { 14279a0bf528SMauro Carvalho Chehab case FEC_1_2: 14289a0bf528SMauro Carvalho Chehab ch.code_rate_hp = 1; 14299a0bf528SMauro Carvalho Chehab break; 14309a0bf528SMauro Carvalho Chehab case FEC_2_3: 14319a0bf528SMauro Carvalho Chehab ch.code_rate_hp = 2; 14329a0bf528SMauro Carvalho Chehab break; 14339a0bf528SMauro Carvalho Chehab case FEC_3_4: 14349a0bf528SMauro Carvalho Chehab ch.code_rate_hp = 3; 14359a0bf528SMauro Carvalho Chehab break; 14369a0bf528SMauro Carvalho Chehab case FEC_5_6: 14379a0bf528SMauro Carvalho Chehab ch.code_rate_hp = 5; 14389a0bf528SMauro Carvalho Chehab break; 14399a0bf528SMauro Carvalho Chehab case FEC_7_8: 14409a0bf528SMauro Carvalho Chehab ch.code_rate_hp = 7; 14419a0bf528SMauro Carvalho Chehab break; 14429a0bf528SMauro Carvalho Chehab default: 14439a0bf528SMauro Carvalho Chehab case FEC_AUTO: 14449a0bf528SMauro Carvalho Chehab ch.code_rate_hp = -1; 14459a0bf528SMauro Carvalho Chehab break; 14469a0bf528SMauro Carvalho Chehab } 14479a0bf528SMauro Carvalho Chehab switch (state->fe[0]->dtv_property_cache.code_rate_LP) { 14489a0bf528SMauro Carvalho Chehab case FEC_1_2: 14499a0bf528SMauro Carvalho Chehab ch.code_rate_lp = 1; 14509a0bf528SMauro Carvalho Chehab break; 14519a0bf528SMauro Carvalho Chehab case FEC_2_3: 14529a0bf528SMauro Carvalho Chehab ch.code_rate_lp = 2; 14539a0bf528SMauro Carvalho Chehab break; 14549a0bf528SMauro Carvalho Chehab case FEC_3_4: 14559a0bf528SMauro Carvalho Chehab ch.code_rate_lp = 3; 14569a0bf528SMauro Carvalho Chehab break; 14579a0bf528SMauro Carvalho Chehab case FEC_5_6: 14589a0bf528SMauro Carvalho Chehab ch.code_rate_lp = 5; 14599a0bf528SMauro Carvalho Chehab break; 14609a0bf528SMauro Carvalho Chehab case FEC_7_8: 14619a0bf528SMauro Carvalho Chehab ch.code_rate_lp = 7; 14629a0bf528SMauro Carvalho Chehab break; 14639a0bf528SMauro Carvalho Chehab default: 14649a0bf528SMauro Carvalho Chehab case FEC_AUTO: 14659a0bf528SMauro Carvalho Chehab ch.code_rate_lp = -1; 14669a0bf528SMauro Carvalho Chehab break; 14679a0bf528SMauro Carvalho Chehab } 14689a0bf528SMauro Carvalho Chehab ch.select_hp = 1; 14699a0bf528SMauro Carvalho Chehab ch.intlv_native = 1; 14709a0bf528SMauro Carvalho Chehab 14719a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch); 14729a0bf528SMauro Carvalho Chehab 14739a0bf528SMauro Carvalho Chehab return 0; 14749a0bf528SMauro Carvalho Chehab } 14759a0bf528SMauro Carvalho Chehab 14769a0bf528SMauro Carvalho Chehab static int dib9000_fw_tune(struct dvb_frontend *fe) 14779a0bf528SMauro Carvalho Chehab { 14789a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 14799a0bf528SMauro Carvalho Chehab int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN; 14809a0bf528SMauro Carvalho Chehab s8 i; 14819a0bf528SMauro Carvalho Chehab 14829a0bf528SMauro Carvalho Chehab switch (state->tune_state) { 14839a0bf528SMauro Carvalho Chehab case CT_DEMOD_START: 14849a0bf528SMauro Carvalho Chehab dib9000_fw_set_channel_head(state); 14859a0bf528SMauro Carvalho Chehab 14869a0bf528SMauro Carvalho Chehab /* write the channel context - a channel is initialized to 0, so it is OK */ 14879a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info); 14889a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info); 14899a0bf528SMauro Carvalho Chehab 14909a0bf528SMauro Carvalho Chehab if (search) 14919a0bf528SMauro Carvalho Chehab dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0); 14929a0bf528SMauro Carvalho Chehab else { 14939a0bf528SMauro Carvalho Chehab dib9000_fw_set_channel_union(fe); 14949a0bf528SMauro Carvalho Chehab dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0); 14959a0bf528SMauro Carvalho Chehab } 14969a0bf528SMauro Carvalho Chehab state->tune_state = CT_DEMOD_STEP_1; 14979a0bf528SMauro Carvalho Chehab break; 14989a0bf528SMauro Carvalho Chehab case CT_DEMOD_STEP_1: 14999a0bf528SMauro Carvalho Chehab if (search) 15009a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1); 15019a0bf528SMauro Carvalho Chehab else 15029a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1); 15039a0bf528SMauro Carvalho Chehab i = (s8)state->i2c_read_buffer[0]; 15049a0bf528SMauro Carvalho Chehab switch (i) { /* something happened */ 15059a0bf528SMauro Carvalho Chehab case 0: 15069a0bf528SMauro Carvalho Chehab break; 15079a0bf528SMauro Carvalho Chehab case -2: /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */ 15089a0bf528SMauro Carvalho Chehab if (search) 15099a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_DEMOD_SUCCESS; 15109a0bf528SMauro Carvalho Chehab else { 15119a0bf528SMauro Carvalho Chehab state->tune_state = CT_DEMOD_STOP; 15129a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_LOCKED; 15139a0bf528SMauro Carvalho Chehab } 15149a0bf528SMauro Carvalho Chehab break; 15159a0bf528SMauro Carvalho Chehab default: 15169a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_TUNE_FAILED; 15179a0bf528SMauro Carvalho Chehab state->tune_state = CT_DEMOD_STOP; 15189a0bf528SMauro Carvalho Chehab break; 15199a0bf528SMauro Carvalho Chehab } 15209a0bf528SMauro Carvalho Chehab break; 15219a0bf528SMauro Carvalho Chehab default: 15229a0bf528SMauro Carvalho Chehab ret = FE_CALLBACK_TIME_NEVER; 15239a0bf528SMauro Carvalho Chehab break; 15249a0bf528SMauro Carvalho Chehab } 15259a0bf528SMauro Carvalho Chehab 15269a0bf528SMauro Carvalho Chehab return ret; 15279a0bf528SMauro Carvalho Chehab } 15289a0bf528SMauro Carvalho Chehab 15299a0bf528SMauro Carvalho Chehab static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff) 15309a0bf528SMauro Carvalho Chehab { 15319a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 15329a0bf528SMauro Carvalho Chehab u16 mode = (u16) onoff; 15339a0bf528SMauro Carvalho Chehab return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1); 15349a0bf528SMauro Carvalho Chehab } 15359a0bf528SMauro Carvalho Chehab 15369a0bf528SMauro Carvalho Chehab static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) 15379a0bf528SMauro Carvalho Chehab { 15389a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 15399a0bf528SMauro Carvalho Chehab u16 outreg, smo_mode; 15409a0bf528SMauro Carvalho Chehab 15413dd72262SMauro Carvalho Chehab dprintk("setting output mode for demod %p to %d\n", fe, mode); 15429a0bf528SMauro Carvalho Chehab 15439a0bf528SMauro Carvalho Chehab switch (mode) { 15449a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 15459a0bf528SMauro Carvalho Chehab outreg = (1 << 10); /* 0x0400 */ 15469a0bf528SMauro Carvalho Chehab break; 15479a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: 15489a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (1 << 6); /* 0x0440 */ 15499a0bf528SMauro Carvalho Chehab break; 15509a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 15519a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ 15529a0bf528SMauro Carvalho Chehab break; 15539a0bf528SMauro Carvalho Chehab case OUTMODE_DIVERSITY: 15549a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (4 << 6); /* 0x0500 */ 15559a0bf528SMauro Carvalho Chehab break; 15569a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: 15579a0bf528SMauro Carvalho Chehab outreg = (1 << 10) | (5 << 6); 15589a0bf528SMauro Carvalho Chehab break; 15599a0bf528SMauro Carvalho Chehab case OUTMODE_HIGH_Z: 15609a0bf528SMauro Carvalho Chehab outreg = 0; 15619a0bf528SMauro Carvalho Chehab break; 15629a0bf528SMauro Carvalho Chehab default: 15633dd72262SMauro Carvalho Chehab dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->fe[0]); 15649a0bf528SMauro Carvalho Chehab return -EINVAL; 15659a0bf528SMauro Carvalho Chehab } 15669a0bf528SMauro Carvalho Chehab 15679a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 1795, outreg); 15689a0bf528SMauro Carvalho Chehab 15699a0bf528SMauro Carvalho Chehab switch (mode) { 15709a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_GATED_CLK: 15719a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_PAR_CONT_CLK: 15729a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_SERIAL: 15739a0bf528SMauro Carvalho Chehab case OUTMODE_MPEG2_FIFO: 15749a0bf528SMauro Carvalho Chehab smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1); 15759a0bf528SMauro Carvalho Chehab if (state->chip.d9.cfg.output_mpeg2_in_188_bytes) 15769a0bf528SMauro Carvalho Chehab smo_mode |= (1 << 5); 15779a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 295, smo_mode); 15789a0bf528SMauro Carvalho Chehab break; 15799a0bf528SMauro Carvalho Chehab } 15809a0bf528SMauro Carvalho Chehab 15819a0bf528SMauro Carvalho Chehab outreg = to_fw_output_mode(mode); 15829a0bf528SMauro Carvalho Chehab return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1); 15839a0bf528SMauro Carvalho Chehab } 15849a0bf528SMauro Carvalho Chehab 15859a0bf528SMauro Carvalho Chehab static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 15869a0bf528SMauro Carvalho Chehab { 15879a0bf528SMauro Carvalho Chehab struct dib9000_state *state = i2c_get_adapdata(i2c_adap); 15889a0bf528SMauro Carvalho Chehab u16 i, len, t, index_msg; 15899a0bf528SMauro Carvalho Chehab 15909a0bf528SMauro Carvalho Chehab for (index_msg = 0; index_msg < num; index_msg++) { 15919a0bf528SMauro Carvalho Chehab if (msg[index_msg].flags & I2C_M_RD) { /* read */ 15929a0bf528SMauro Carvalho Chehab len = msg[index_msg].len; 15939a0bf528SMauro Carvalho Chehab if (len > 16) 15949a0bf528SMauro Carvalho Chehab len = 16; 15959a0bf528SMauro Carvalho Chehab 15969a0bf528SMauro Carvalho Chehab if (dib9000_read_word(state, 790) != 0) 15973dd72262SMauro Carvalho Chehab dprintk("TunerITF: read busy\n"); 15989a0bf528SMauro Carvalho Chehab 15999a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 784, (u16) (msg[index_msg].addr)); 16009a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 787, (len / 2) - 1); 16019a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 786, 1); /* start read */ 16029a0bf528SMauro Carvalho Chehab 16039a0bf528SMauro Carvalho Chehab i = 1000; 16049a0bf528SMauro Carvalho Chehab while (dib9000_read_word(state, 790) != (len / 2) && i) 16059a0bf528SMauro Carvalho Chehab i--; 16069a0bf528SMauro Carvalho Chehab 16079a0bf528SMauro Carvalho Chehab if (i == 0) 16083dd72262SMauro Carvalho Chehab dprintk("TunerITF: read failed\n"); 16099a0bf528SMauro Carvalho Chehab 16109a0bf528SMauro Carvalho Chehab for (i = 0; i < len; i += 2) { 16119a0bf528SMauro Carvalho Chehab t = dib9000_read_word(state, 785); 16129a0bf528SMauro Carvalho Chehab msg[index_msg].buf[i] = (t >> 8) & 0xff; 16139a0bf528SMauro Carvalho Chehab msg[index_msg].buf[i + 1] = (t) & 0xff; 16149a0bf528SMauro Carvalho Chehab } 16159a0bf528SMauro Carvalho Chehab if (dib9000_read_word(state, 790) != 0) 16163dd72262SMauro Carvalho Chehab dprintk("TunerITF: read more data than expected\n"); 16179a0bf528SMauro Carvalho Chehab } else { 16189a0bf528SMauro Carvalho Chehab i = 1000; 16199a0bf528SMauro Carvalho Chehab while (dib9000_read_word(state, 789) && i) 16209a0bf528SMauro Carvalho Chehab i--; 16219a0bf528SMauro Carvalho Chehab if (i == 0) 16223dd72262SMauro Carvalho Chehab dprintk("TunerITF: write busy\n"); 16239a0bf528SMauro Carvalho Chehab 16249a0bf528SMauro Carvalho Chehab len = msg[index_msg].len; 16259a0bf528SMauro Carvalho Chehab if (len > 16) 16269a0bf528SMauro Carvalho Chehab len = 16; 16279a0bf528SMauro Carvalho Chehab 16289a0bf528SMauro Carvalho Chehab for (i = 0; i < len; i += 2) 16299a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]); 16309a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 784, (u16) msg[index_msg].addr); 16319a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 787, (len / 2) - 1); 16329a0bf528SMauro Carvalho Chehab dib9000_write_word(state, 786, 0); /* start write */ 16339a0bf528SMauro Carvalho Chehab 16349a0bf528SMauro Carvalho Chehab i = 1000; 16359a0bf528SMauro Carvalho Chehab while (dib9000_read_word(state, 791) > 0 && i) 16369a0bf528SMauro Carvalho Chehab i--; 16379a0bf528SMauro Carvalho Chehab if (i == 0) 16383dd72262SMauro Carvalho Chehab dprintk("TunerITF: write failed\n"); 16399a0bf528SMauro Carvalho Chehab } 16409a0bf528SMauro Carvalho Chehab } 16419a0bf528SMauro Carvalho Chehab return num; 16429a0bf528SMauro Carvalho Chehab } 16439a0bf528SMauro Carvalho Chehab 16449a0bf528SMauro Carvalho Chehab int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) 16459a0bf528SMauro Carvalho Chehab { 16469a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 16479a0bf528SMauro Carvalho Chehab 16489a0bf528SMauro Carvalho Chehab state->component_bus_speed = speed; 16499a0bf528SMauro Carvalho Chehab return 0; 16509a0bf528SMauro Carvalho Chehab } 16519a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed); 16529a0bf528SMauro Carvalho Chehab 16539a0bf528SMauro Carvalho Chehab static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 16549a0bf528SMauro Carvalho Chehab { 16559a0bf528SMauro Carvalho Chehab struct dib9000_state *state = i2c_get_adapdata(i2c_adap); 16569a0bf528SMauro Carvalho Chehab u8 type = 0; /* I2C */ 16579a0bf528SMauro Carvalho Chehab u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4; 16589a0bf528SMauro Carvalho Chehab u16 scl = state->component_bus_speed; /* SCL frequency */ 16599a0bf528SMauro Carvalho Chehab struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER]; 16609a0bf528SMauro Carvalho Chehab u8 p[13] = { 0 }; 16619a0bf528SMauro Carvalho Chehab 16629a0bf528SMauro Carvalho Chehab p[0] = type; 16639a0bf528SMauro Carvalho Chehab p[1] = port; 16649a0bf528SMauro Carvalho Chehab p[2] = msg[0].addr << 1; 16659a0bf528SMauro Carvalho Chehab 16669a0bf528SMauro Carvalho Chehab p[3] = (u8) scl & 0xff; /* scl */ 16679a0bf528SMauro Carvalho Chehab p[4] = (u8) (scl >> 8); 16689a0bf528SMauro Carvalho Chehab 16699a0bf528SMauro Carvalho Chehab p[7] = 0; 16709a0bf528SMauro Carvalho Chehab p[8] = 0; 16719a0bf528SMauro Carvalho Chehab 16729a0bf528SMauro Carvalho Chehab p[9] = (u8) (msg[0].len); 16739a0bf528SMauro Carvalho Chehab p[10] = (u8) (msg[0].len >> 8); 16749a0bf528SMauro Carvalho Chehab if ((num > 1) && (msg[1].flags & I2C_M_RD)) { 16759a0bf528SMauro Carvalho Chehab p[11] = (u8) (msg[1].len); 16769a0bf528SMauro Carvalho Chehab p[12] = (u8) (msg[1].len >> 8); 16779a0bf528SMauro Carvalho Chehab } else { 16789a0bf528SMauro Carvalho Chehab p[11] = 0; 16799a0bf528SMauro Carvalho Chehab p[12] = 0; 16809a0bf528SMauro Carvalho Chehab } 16819a0bf528SMauro Carvalho Chehab 16829a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 16833dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 16849a0bf528SMauro Carvalho Chehab return 0; 16859a0bf528SMauro Carvalho Chehab } 16869a0bf528SMauro Carvalho Chehab 16879a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); 16889a0bf528SMauro Carvalho Chehab 16899a0bf528SMauro Carvalho Chehab { /* write-part */ 16909a0bf528SMauro Carvalho Chehab dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0); 16919a0bf528SMauro Carvalho Chehab dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len); 16929a0bf528SMauro Carvalho Chehab } 16939a0bf528SMauro Carvalho Chehab 16949a0bf528SMauro Carvalho Chehab /* do the transaction */ 16959a0bf528SMauro Carvalho Chehab if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) { 16969a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 16979a0bf528SMauro Carvalho Chehab return 0; 16989a0bf528SMauro Carvalho Chehab } 16999a0bf528SMauro Carvalho Chehab 17009a0bf528SMauro Carvalho Chehab /* read back any possible result */ 17019a0bf528SMauro Carvalho Chehab if ((num > 1) && (msg[1].flags & I2C_M_RD)) 17029a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len); 17039a0bf528SMauro Carvalho Chehab 17049a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 17059a0bf528SMauro Carvalho Chehab 17069a0bf528SMauro Carvalho Chehab return num; 17079a0bf528SMauro Carvalho Chehab } 17089a0bf528SMauro Carvalho Chehab 17099a0bf528SMauro Carvalho Chehab static u32 dib9000_i2c_func(struct i2c_adapter *adapter) 17109a0bf528SMauro Carvalho Chehab { 17119a0bf528SMauro Carvalho Chehab return I2C_FUNC_I2C; 17129a0bf528SMauro Carvalho Chehab } 17139a0bf528SMauro Carvalho Chehab 171419779f40SGustavo A. R. Silva static const struct i2c_algorithm dib9000_tuner_algo = { 17159a0bf528SMauro Carvalho Chehab .master_xfer = dib9000_tuner_xfer, 17169a0bf528SMauro Carvalho Chehab .functionality = dib9000_i2c_func, 17179a0bf528SMauro Carvalho Chehab }; 17189a0bf528SMauro Carvalho Chehab 171919779f40SGustavo A. R. Silva static const struct i2c_algorithm dib9000_component_bus_algo = { 17209a0bf528SMauro Carvalho Chehab .master_xfer = dib9000_fw_component_bus_xfer, 17219a0bf528SMauro Carvalho Chehab .functionality = dib9000_i2c_func, 17229a0bf528SMauro Carvalho Chehab }; 17239a0bf528SMauro Carvalho Chehab 17249a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) 17259a0bf528SMauro Carvalho Chehab { 17269a0bf528SMauro Carvalho Chehab struct dib9000_state *st = fe->demodulator_priv; 17279a0bf528SMauro Carvalho Chehab return &st->tuner_adap; 17289a0bf528SMauro Carvalho Chehab } 17299a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_get_tuner_interface); 17309a0bf528SMauro Carvalho Chehab 17319a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) 17329a0bf528SMauro Carvalho Chehab { 17339a0bf528SMauro Carvalho Chehab struct dib9000_state *st = fe->demodulator_priv; 17349a0bf528SMauro Carvalho Chehab return &st->component_bus; 17359a0bf528SMauro Carvalho Chehab } 17369a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_get_component_bus_interface); 17379a0bf528SMauro Carvalho Chehab 17389a0bf528SMauro Carvalho Chehab struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) 17399a0bf528SMauro Carvalho Chehab { 17409a0bf528SMauro Carvalho Chehab struct dib9000_state *st = fe->demodulator_priv; 17419a0bf528SMauro Carvalho Chehab return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); 17429a0bf528SMauro Carvalho Chehab } 17439a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_get_i2c_master); 17449a0bf528SMauro Carvalho Chehab 17459a0bf528SMauro Carvalho Chehab int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) 17469a0bf528SMauro Carvalho Chehab { 17479a0bf528SMauro Carvalho Chehab struct dib9000_state *st = fe->demodulator_priv; 17489a0bf528SMauro Carvalho Chehab 17499a0bf528SMauro Carvalho Chehab st->i2c.i2c_adap = i2c; 17509a0bf528SMauro Carvalho Chehab return 0; 17519a0bf528SMauro Carvalho Chehab } 17529a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_set_i2c_adapter); 17539a0bf528SMauro Carvalho Chehab 17549a0bf528SMauro Carvalho Chehab static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val) 17559a0bf528SMauro Carvalho Chehab { 17569a0bf528SMauro Carvalho Chehab st->gpio_dir = dib9000_read_word(st, 773); 17579a0bf528SMauro Carvalho Chehab st->gpio_dir &= ~(1 << num); /* reset the direction bit */ 17589a0bf528SMauro Carvalho Chehab st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ 17599a0bf528SMauro Carvalho Chehab dib9000_write_word(st, 773, st->gpio_dir); 17609a0bf528SMauro Carvalho Chehab 17619a0bf528SMauro Carvalho Chehab st->gpio_val = dib9000_read_word(st, 774); 17629a0bf528SMauro Carvalho Chehab st->gpio_val &= ~(1 << num); /* reset the direction bit */ 17639a0bf528SMauro Carvalho Chehab st->gpio_val |= (val & 0x01) << num; /* set the new value */ 17649a0bf528SMauro Carvalho Chehab dib9000_write_word(st, 774, st->gpio_val); 17659a0bf528SMauro Carvalho Chehab 17663dd72262SMauro Carvalho Chehab dprintk("gpio dir: %04x: gpio val: %04x\n", st->gpio_dir, st->gpio_val); 17679a0bf528SMauro Carvalho Chehab 17689a0bf528SMauro Carvalho Chehab return 0; 17699a0bf528SMauro Carvalho Chehab } 17709a0bf528SMauro Carvalho Chehab 17719a0bf528SMauro Carvalho Chehab int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) 17729a0bf528SMauro Carvalho Chehab { 17739a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 17749a0bf528SMauro Carvalho Chehab return dib9000_cfg_gpio(state, num, dir, val); 17759a0bf528SMauro Carvalho Chehab } 17769a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_set_gpio); 17779a0bf528SMauro Carvalho Chehab 17789a0bf528SMauro Carvalho Chehab int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) 17799a0bf528SMauro Carvalho Chehab { 17809a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 17819a0bf528SMauro Carvalho Chehab u16 val; 17829a0bf528SMauro Carvalho Chehab int ret; 17839a0bf528SMauro Carvalho Chehab 17849a0bf528SMauro Carvalho Chehab if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) { 17859a0bf528SMauro Carvalho Chehab /* postpone the pid filtering cmd */ 17863dd72262SMauro Carvalho Chehab dprintk("pid filter cmd postpone\n"); 17879a0bf528SMauro Carvalho Chehab state->pid_ctrl_index++; 17889a0bf528SMauro Carvalho Chehab state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL; 17899a0bf528SMauro Carvalho Chehab state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; 17909a0bf528SMauro Carvalho Chehab return 0; 17919a0bf528SMauro Carvalho Chehab } 17929a0bf528SMauro Carvalho Chehab 17939a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 17943dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 17959a0bf528SMauro Carvalho Chehab return -EINTR; 17969a0bf528SMauro Carvalho Chehab } 17979a0bf528SMauro Carvalho Chehab 17989a0bf528SMauro Carvalho Chehab val = dib9000_read_word(state, 294 + 1) & 0xffef; 17999a0bf528SMauro Carvalho Chehab val |= (onoff & 0x1) << 4; 18009a0bf528SMauro Carvalho Chehab 18013dd72262SMauro Carvalho Chehab dprintk("PID filter enabled %d\n", onoff); 18029a0bf528SMauro Carvalho Chehab ret = dib9000_write_word(state, 294 + 1, val); 18039a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 18049a0bf528SMauro Carvalho Chehab return ret; 18059a0bf528SMauro Carvalho Chehab 18069a0bf528SMauro Carvalho Chehab } 18079a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); 18089a0bf528SMauro Carvalho Chehab 18099a0bf528SMauro Carvalho Chehab int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) 18109a0bf528SMauro Carvalho Chehab { 18119a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 18129a0bf528SMauro Carvalho Chehab int ret; 18139a0bf528SMauro Carvalho Chehab 18149a0bf528SMauro Carvalho Chehab if (state->pid_ctrl_index != -2) { 18159a0bf528SMauro Carvalho Chehab /* postpone the pid filtering cmd */ 18163dd72262SMauro Carvalho Chehab dprintk("pid filter postpone\n"); 18179a0bf528SMauro Carvalho Chehab if (state->pid_ctrl_index < 9) { 18189a0bf528SMauro Carvalho Chehab state->pid_ctrl_index++; 18199a0bf528SMauro Carvalho Chehab state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER; 18209a0bf528SMauro Carvalho Chehab state->pid_ctrl[state->pid_ctrl_index].id = id; 18219a0bf528SMauro Carvalho Chehab state->pid_ctrl[state->pid_ctrl_index].pid = pid; 18229a0bf528SMauro Carvalho Chehab state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; 18239a0bf528SMauro Carvalho Chehab } else 18243dd72262SMauro Carvalho Chehab dprintk("can not add any more pid ctrl cmd\n"); 18259a0bf528SMauro Carvalho Chehab return 0; 18269a0bf528SMauro Carvalho Chehab } 18279a0bf528SMauro Carvalho Chehab 18289a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 18293dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 18309a0bf528SMauro Carvalho Chehab return -EINTR; 18319a0bf528SMauro Carvalho Chehab } 18323dd72262SMauro Carvalho Chehab dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff); 18339a0bf528SMauro Carvalho Chehab ret = dib9000_write_word(state, 300 + 1 + id, 18349a0bf528SMauro Carvalho Chehab onoff ? (1 << 13) | pid : 0); 18359a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 18369a0bf528SMauro Carvalho Chehab return ret; 18379a0bf528SMauro Carvalho Chehab } 18389a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_fw_pid_filter); 18399a0bf528SMauro Carvalho Chehab 18409a0bf528SMauro Carvalho Chehab int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) 18419a0bf528SMauro Carvalho Chehab { 18429a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 18439a0bf528SMauro Carvalho Chehab return dib9000_fw_init(state); 18449a0bf528SMauro Carvalho Chehab } 18459a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_firmware_post_pll_init); 18469a0bf528SMauro Carvalho Chehab 18479a0bf528SMauro Carvalho Chehab static void dib9000_release(struct dvb_frontend *demod) 18489a0bf528SMauro Carvalho Chehab { 18499a0bf528SMauro Carvalho Chehab struct dib9000_state *st = demod->demodulator_priv; 18509a0bf528SMauro Carvalho Chehab u8 index_frontend; 18519a0bf528SMauro Carvalho Chehab 18529a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) 18539a0bf528SMauro Carvalho Chehab dvb_frontend_detach(st->fe[index_frontend]); 18549a0bf528SMauro Carvalho Chehab 18559a0bf528SMauro Carvalho Chehab dibx000_exit_i2c_master(&st->i2c_master); 18569a0bf528SMauro Carvalho Chehab 18579a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->tuner_adap); 18589a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->component_bus); 18599a0bf528SMauro Carvalho Chehab kfree(st->fe[0]); 18609a0bf528SMauro Carvalho Chehab kfree(st); 18619a0bf528SMauro Carvalho Chehab } 18629a0bf528SMauro Carvalho Chehab 18639a0bf528SMauro Carvalho Chehab static int dib9000_wakeup(struct dvb_frontend *fe) 18649a0bf528SMauro Carvalho Chehab { 18659a0bf528SMauro Carvalho Chehab return 0; 18669a0bf528SMauro Carvalho Chehab } 18679a0bf528SMauro Carvalho Chehab 18689a0bf528SMauro Carvalho Chehab static int dib9000_sleep(struct dvb_frontend *fe) 18699a0bf528SMauro Carvalho Chehab { 18709a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 18719a0bf528SMauro Carvalho Chehab u8 index_frontend; 18729a0bf528SMauro Carvalho Chehab int ret = 0; 18739a0bf528SMauro Carvalho Chehab 18749a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 18753dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 18769a0bf528SMauro Carvalho Chehab return -EINTR; 18779a0bf528SMauro Carvalho Chehab } 18789a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 18799a0bf528SMauro Carvalho Chehab ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); 18809a0bf528SMauro Carvalho Chehab if (ret < 0) 18819a0bf528SMauro Carvalho Chehab goto error; 18829a0bf528SMauro Carvalho Chehab } 18839a0bf528SMauro Carvalho Chehab ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); 18849a0bf528SMauro Carvalho Chehab 18859a0bf528SMauro Carvalho Chehab error: 18869a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 18879a0bf528SMauro Carvalho Chehab return ret; 18889a0bf528SMauro Carvalho Chehab } 18899a0bf528SMauro Carvalho Chehab 18909a0bf528SMauro Carvalho Chehab static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) 18919a0bf528SMauro Carvalho Chehab { 18929a0bf528SMauro Carvalho Chehab tune->min_delay_ms = 1000; 18939a0bf528SMauro Carvalho Chehab return 0; 18949a0bf528SMauro Carvalho Chehab } 18959a0bf528SMauro Carvalho Chehab 18967e3e68bcSMauro Carvalho Chehab static int dib9000_get_frontend(struct dvb_frontend *fe, 18977e3e68bcSMauro Carvalho Chehab struct dtv_frontend_properties *c) 18989a0bf528SMauro Carvalho Chehab { 18999a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 19009a0bf528SMauro Carvalho Chehab u8 index_frontend, sub_index_frontend; 19010df289a2SMauro Carvalho Chehab enum fe_status stat; 19029a0bf528SMauro Carvalho Chehab int ret = 0; 19039a0bf528SMauro Carvalho Chehab 19049a0bf528SMauro Carvalho Chehab if (state->get_frontend_internal == 0) { 19059a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 19063dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 19079a0bf528SMauro Carvalho Chehab return -EINTR; 19089a0bf528SMauro Carvalho Chehab } 19099a0bf528SMauro Carvalho Chehab } 19109a0bf528SMauro Carvalho Chehab 19119a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 19129a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); 19139a0bf528SMauro Carvalho Chehab if (stat & FE_HAS_SYNC) { 19143dd72262SMauro Carvalho Chehab dprintk("TPS lock on the slave%i\n", index_frontend); 19159a0bf528SMauro Carvalho Chehab 19169a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 19177e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c); 19189a0bf528SMauro Carvalho Chehab for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); 19199a0bf528SMauro Carvalho Chehab sub_index_frontend++) { 19209a0bf528SMauro Carvalho Chehab if (sub_index_frontend != index_frontend) { 19219a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.modulation = 19229a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.modulation; 19239a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.inversion = 19249a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.inversion; 19259a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = 19269a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.transmission_mode; 19279a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = 19289a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.guard_interval; 19299a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.hierarchy = 19309a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.hierarchy; 19319a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP = 19329a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.code_rate_HP; 19339a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP = 19349a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.code_rate_LP; 19359a0bf528SMauro Carvalho Chehab state->fe[sub_index_frontend]->dtv_property_cache.rolloff = 19369a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.rolloff; 19379a0bf528SMauro Carvalho Chehab } 19389a0bf528SMauro Carvalho Chehab } 19399a0bf528SMauro Carvalho Chehab ret = 0; 19409a0bf528SMauro Carvalho Chehab goto return_value; 19419a0bf528SMauro Carvalho Chehab } 19429a0bf528SMauro Carvalho Chehab } 19439a0bf528SMauro Carvalho Chehab 19449a0bf528SMauro Carvalho Chehab /* get the channel from master chip */ 19459a0bf528SMauro Carvalho Chehab ret = dib9000_fw_get_channel(fe); 19469a0bf528SMauro Carvalho Chehab if (ret != 0) 19479a0bf528SMauro Carvalho Chehab goto return_value; 19489a0bf528SMauro Carvalho Chehab 19499a0bf528SMauro Carvalho Chehab /* synchronize the cache with the other frontends */ 19509a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 19517e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion; 19527e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode; 19537e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval; 19547e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.modulation = c->modulation; 19557e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.hierarchy = c->hierarchy; 19567e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.code_rate_HP = c->code_rate_HP; 19577e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.code_rate_LP = c->code_rate_LP; 19587e3e68bcSMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.rolloff = c->rolloff; 19599a0bf528SMauro Carvalho Chehab } 19609a0bf528SMauro Carvalho Chehab ret = 0; 19619a0bf528SMauro Carvalho Chehab 19629a0bf528SMauro Carvalho Chehab return_value: 19639a0bf528SMauro Carvalho Chehab if (state->get_frontend_internal == 0) 19649a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 19659a0bf528SMauro Carvalho Chehab return ret; 19669a0bf528SMauro Carvalho Chehab } 19679a0bf528SMauro Carvalho Chehab 19689a0bf528SMauro Carvalho Chehab static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) 19699a0bf528SMauro Carvalho Chehab { 19709a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 19719a0bf528SMauro Carvalho Chehab state->tune_state = tune_state; 19729a0bf528SMauro Carvalho Chehab if (tune_state == CT_DEMOD_START) 19739a0bf528SMauro Carvalho Chehab state->status = FE_STATUS_TUNE_PENDING; 19749a0bf528SMauro Carvalho Chehab 19759a0bf528SMauro Carvalho Chehab return 0; 19769a0bf528SMauro Carvalho Chehab } 19779a0bf528SMauro Carvalho Chehab 19789a0bf528SMauro Carvalho Chehab static u32 dib9000_get_status(struct dvb_frontend *fe) 19799a0bf528SMauro Carvalho Chehab { 19809a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 19819a0bf528SMauro Carvalho Chehab return state->status; 19829a0bf528SMauro Carvalho Chehab } 19839a0bf528SMauro Carvalho Chehab 19849a0bf528SMauro Carvalho Chehab static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status) 19859a0bf528SMauro Carvalho Chehab { 19869a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 19879a0bf528SMauro Carvalho Chehab 19889a0bf528SMauro Carvalho Chehab memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext)); 19899a0bf528SMauro Carvalho Chehab return 0; 19909a0bf528SMauro Carvalho Chehab } 19919a0bf528SMauro Carvalho Chehab 19929a0bf528SMauro Carvalho Chehab static int dib9000_set_frontend(struct dvb_frontend *fe) 19939a0bf528SMauro Carvalho Chehab { 19949a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 19959a0bf528SMauro Carvalho Chehab int sleep_time, sleep_time_slave; 19969a0bf528SMauro Carvalho Chehab u32 frontend_status; 19979a0bf528SMauro Carvalho Chehab u8 nbr_pending, exit_condition, index_frontend, index_frontend_success; 19989a0bf528SMauro Carvalho Chehab struct dvb_frontend_parametersContext channel_status; 19999a0bf528SMauro Carvalho Chehab 20009a0bf528SMauro Carvalho Chehab /* check that the correct parameters are set */ 20019a0bf528SMauro Carvalho Chehab if (state->fe[0]->dtv_property_cache.frequency == 0) { 20023dd72262SMauro Carvalho Chehab dprintk("dib9000: must specify frequency\n"); 20039a0bf528SMauro Carvalho Chehab return 0; 20049a0bf528SMauro Carvalho Chehab } 20059a0bf528SMauro Carvalho Chehab 20069a0bf528SMauro Carvalho Chehab if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { 20073dd72262SMauro Carvalho Chehab dprintk("dib9000: must specify bandwidth\n"); 20089a0bf528SMauro Carvalho Chehab return 0; 20099a0bf528SMauro Carvalho Chehab } 20109a0bf528SMauro Carvalho Chehab 20119a0bf528SMauro Carvalho Chehab state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ 20129a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 20133dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 20149a0bf528SMauro Carvalho Chehab return 0; 20159a0bf528SMauro Carvalho Chehab } 20169a0bf528SMauro Carvalho Chehab 20179a0bf528SMauro Carvalho Chehab fe->dtv_property_cache.delivery_system = SYS_DVBT; 20189a0bf528SMauro Carvalho Chehab 20199a0bf528SMauro Carvalho Chehab /* set the master status */ 20209a0bf528SMauro Carvalho Chehab if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO || 20219a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO || 20229a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.modulation == QAM_AUTO || 20239a0bf528SMauro Carvalho Chehab state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) { 20249a0bf528SMauro Carvalho Chehab /* no channel specified, autosearch the channel */ 20259a0bf528SMauro Carvalho Chehab state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; 20269a0bf528SMauro Carvalho Chehab } else 20279a0bf528SMauro Carvalho Chehab state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; 20289a0bf528SMauro Carvalho Chehab 20299a0bf528SMauro Carvalho Chehab /* set mode and status for the different frontends */ 20309a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20319a0bf528SMauro Carvalho Chehab dib9000_fw_set_diversity_in(state->fe[index_frontend], 1); 20329a0bf528SMauro Carvalho Chehab 20339a0bf528SMauro Carvalho Chehab /* synchronization of the cache */ 20349a0bf528SMauro Carvalho Chehab memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); 20359a0bf528SMauro Carvalho Chehab 20369a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT; 20379a0bf528SMauro Carvalho Chehab dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); 20389a0bf528SMauro Carvalho Chehab 20399a0bf528SMauro Carvalho Chehab dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status); 20409a0bf528SMauro Carvalho Chehab dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); 20419a0bf528SMauro Carvalho Chehab } 20429a0bf528SMauro Carvalho Chehab 20439a0bf528SMauro Carvalho Chehab /* actual tune */ 20449a0bf528SMauro Carvalho Chehab exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ 20459a0bf528SMauro Carvalho Chehab index_frontend_success = 0; 20469a0bf528SMauro Carvalho Chehab do { 20479a0bf528SMauro Carvalho Chehab sleep_time = dib9000_fw_tune(state->fe[0]); 20489a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20499a0bf528SMauro Carvalho Chehab sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); 20509a0bf528SMauro Carvalho Chehab if (sleep_time == FE_CALLBACK_TIME_NEVER) 20519a0bf528SMauro Carvalho Chehab sleep_time = sleep_time_slave; 20529a0bf528SMauro Carvalho Chehab else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) 20539a0bf528SMauro Carvalho Chehab sleep_time = sleep_time_slave; 20549a0bf528SMauro Carvalho Chehab } 20559a0bf528SMauro Carvalho Chehab if (sleep_time != FE_CALLBACK_TIME_NEVER) 20569a0bf528SMauro Carvalho Chehab msleep(sleep_time / 10); 20579a0bf528SMauro Carvalho Chehab else 20589a0bf528SMauro Carvalho Chehab break; 20599a0bf528SMauro Carvalho Chehab 20609a0bf528SMauro Carvalho Chehab nbr_pending = 0; 20619a0bf528SMauro Carvalho Chehab exit_condition = 0; 20629a0bf528SMauro Carvalho Chehab index_frontend_success = 0; 20639a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20649a0bf528SMauro Carvalho Chehab frontend_status = -dib9000_get_status(state->fe[index_frontend]); 20659a0bf528SMauro Carvalho Chehab if (frontend_status > -FE_STATUS_TUNE_PENDING) { 20669a0bf528SMauro Carvalho Chehab exit_condition = 2; /* tune success */ 20679a0bf528SMauro Carvalho Chehab index_frontend_success = index_frontend; 20689a0bf528SMauro Carvalho Chehab break; 20699a0bf528SMauro Carvalho Chehab } 20709a0bf528SMauro Carvalho Chehab if (frontend_status == -FE_STATUS_TUNE_PENDING) 20719a0bf528SMauro Carvalho Chehab nbr_pending++; /* some frontends are still tuning */ 20729a0bf528SMauro Carvalho Chehab } 20739a0bf528SMauro Carvalho Chehab if ((exit_condition != 2) && (nbr_pending == 0)) 20749a0bf528SMauro Carvalho Chehab exit_condition = 1; /* if all tune are done and no success, exit: tune failed */ 20759a0bf528SMauro Carvalho Chehab 20769a0bf528SMauro Carvalho Chehab } while (exit_condition == 0); 20779a0bf528SMauro Carvalho Chehab 20789a0bf528SMauro Carvalho Chehab /* check the tune result */ 20799a0bf528SMauro Carvalho Chehab if (exit_condition == 1) { /* tune failed */ 20803dd72262SMauro Carvalho Chehab dprintk("tune failed\n"); 20819a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 20829a0bf528SMauro Carvalho Chehab /* tune failed; put all the pid filtering cmd to junk */ 20839a0bf528SMauro Carvalho Chehab state->pid_ctrl_index = -1; 20849a0bf528SMauro Carvalho Chehab return 0; 20859a0bf528SMauro Carvalho Chehab } 20869a0bf528SMauro Carvalho Chehab 20873dd72262SMauro Carvalho Chehab dprintk("tune success on frontend%i\n", index_frontend_success); 20889a0bf528SMauro Carvalho Chehab 20899a0bf528SMauro Carvalho Chehab /* synchronize all the channel cache */ 20909a0bf528SMauro Carvalho Chehab state->get_frontend_internal = 1; 20917e3e68bcSMauro Carvalho Chehab dib9000_get_frontend(state->fe[0], &state->fe[0]->dtv_property_cache); 20929a0bf528SMauro Carvalho Chehab state->get_frontend_internal = 0; 20939a0bf528SMauro Carvalho Chehab 20949a0bf528SMauro Carvalho Chehab /* retune the other frontends with the found channel */ 20959a0bf528SMauro Carvalho Chehab channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; 20969a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20979a0bf528SMauro Carvalho Chehab /* only retune the frontends which was not tuned success */ 20989a0bf528SMauro Carvalho Chehab if (index_frontend != index_frontend_success) { 20999a0bf528SMauro Carvalho Chehab dib9000_set_channel_status(state->fe[index_frontend], &channel_status); 21009a0bf528SMauro Carvalho Chehab dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); 21019a0bf528SMauro Carvalho Chehab } 21029a0bf528SMauro Carvalho Chehab } 21039a0bf528SMauro Carvalho Chehab do { 21049a0bf528SMauro Carvalho Chehab sleep_time = FE_CALLBACK_TIME_NEVER; 21059a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 21069a0bf528SMauro Carvalho Chehab if (index_frontend != index_frontend_success) { 21079a0bf528SMauro Carvalho Chehab sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); 21089a0bf528SMauro Carvalho Chehab if (sleep_time == FE_CALLBACK_TIME_NEVER) 21099a0bf528SMauro Carvalho Chehab sleep_time = sleep_time_slave; 21109a0bf528SMauro Carvalho Chehab else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) 21119a0bf528SMauro Carvalho Chehab sleep_time = sleep_time_slave; 21129a0bf528SMauro Carvalho Chehab } 21139a0bf528SMauro Carvalho Chehab } 21149a0bf528SMauro Carvalho Chehab if (sleep_time != FE_CALLBACK_TIME_NEVER) 21159a0bf528SMauro Carvalho Chehab msleep(sleep_time / 10); 21169a0bf528SMauro Carvalho Chehab else 21179a0bf528SMauro Carvalho Chehab break; 21189a0bf528SMauro Carvalho Chehab 21199a0bf528SMauro Carvalho Chehab nbr_pending = 0; 21209a0bf528SMauro Carvalho Chehab for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 21219a0bf528SMauro Carvalho Chehab if (index_frontend != index_frontend_success) { 21229a0bf528SMauro Carvalho Chehab frontend_status = -dib9000_get_status(state->fe[index_frontend]); 21239a0bf528SMauro Carvalho Chehab if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING)) 21249a0bf528SMauro Carvalho Chehab nbr_pending++; /* some frontends are still tuning */ 21259a0bf528SMauro Carvalho Chehab } 21269a0bf528SMauro Carvalho Chehab } 21279a0bf528SMauro Carvalho Chehab } while (nbr_pending != 0); 21289a0bf528SMauro Carvalho Chehab 21299a0bf528SMauro Carvalho Chehab /* set the output mode */ 21309a0bf528SMauro Carvalho Chehab dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode); 21319a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 21329a0bf528SMauro Carvalho Chehab dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); 21339a0bf528SMauro Carvalho Chehab 21349a0bf528SMauro Carvalho Chehab /* turn off the diversity for the last frontend */ 21359a0bf528SMauro Carvalho Chehab dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); 21369a0bf528SMauro Carvalho Chehab 21379a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 21389a0bf528SMauro Carvalho Chehab if (state->pid_ctrl_index >= 0) { 21399a0bf528SMauro Carvalho Chehab u8 index_pid_filter_cmd; 21409a0bf528SMauro Carvalho Chehab u8 pid_ctrl_index = state->pid_ctrl_index; 21419a0bf528SMauro Carvalho Chehab 21429a0bf528SMauro Carvalho Chehab state->pid_ctrl_index = -2; 21439a0bf528SMauro Carvalho Chehab for (index_pid_filter_cmd = 0; 21449a0bf528SMauro Carvalho Chehab index_pid_filter_cmd <= pid_ctrl_index; 21459a0bf528SMauro Carvalho Chehab index_pid_filter_cmd++) { 21469a0bf528SMauro Carvalho Chehab if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL) 21479a0bf528SMauro Carvalho Chehab dib9000_fw_pid_filter_ctrl(state->fe[0], 21489a0bf528SMauro Carvalho Chehab state->pid_ctrl[index_pid_filter_cmd].onoff); 21499a0bf528SMauro Carvalho Chehab else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER) 21509a0bf528SMauro Carvalho Chehab dib9000_fw_pid_filter(state->fe[0], 21519a0bf528SMauro Carvalho Chehab state->pid_ctrl[index_pid_filter_cmd].id, 21529a0bf528SMauro Carvalho Chehab state->pid_ctrl[index_pid_filter_cmd].pid, 21539a0bf528SMauro Carvalho Chehab state->pid_ctrl[index_pid_filter_cmd].onoff); 21549a0bf528SMauro Carvalho Chehab } 21559a0bf528SMauro Carvalho Chehab } 21569a0bf528SMauro Carvalho Chehab /* do not postpone any more the pid filtering */ 21579a0bf528SMauro Carvalho Chehab state->pid_ctrl_index = -2; 21589a0bf528SMauro Carvalho Chehab 21599a0bf528SMauro Carvalho Chehab return 0; 21609a0bf528SMauro Carvalho Chehab } 21619a0bf528SMauro Carvalho Chehab 21629a0bf528SMauro Carvalho Chehab static u16 dib9000_read_lock(struct dvb_frontend *fe) 21639a0bf528SMauro Carvalho Chehab { 21649a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 21659a0bf528SMauro Carvalho Chehab 21669a0bf528SMauro Carvalho Chehab return dib9000_read_word(state, 535); 21679a0bf528SMauro Carvalho Chehab } 21689a0bf528SMauro Carvalho Chehab 21690df289a2SMauro Carvalho Chehab static int dib9000_read_status(struct dvb_frontend *fe, enum fe_status *stat) 21709a0bf528SMauro Carvalho Chehab { 21719a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 21729a0bf528SMauro Carvalho Chehab u8 index_frontend; 21739a0bf528SMauro Carvalho Chehab u16 lock = 0, lock_slave = 0; 21749a0bf528SMauro Carvalho Chehab 21759a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 21763dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 21779a0bf528SMauro Carvalho Chehab return -EINTR; 21789a0bf528SMauro Carvalho Chehab } 21799a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 21809a0bf528SMauro Carvalho Chehab lock_slave |= dib9000_read_lock(state->fe[index_frontend]); 21819a0bf528SMauro Carvalho Chehab 21829a0bf528SMauro Carvalho Chehab lock = dib9000_read_word(state, 535); 21839a0bf528SMauro Carvalho Chehab 21849a0bf528SMauro Carvalho Chehab *stat = 0; 21859a0bf528SMauro Carvalho Chehab 21869a0bf528SMauro Carvalho Chehab if ((lock & 0x8000) || (lock_slave & 0x8000)) 21879a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SIGNAL; 21889a0bf528SMauro Carvalho Chehab if ((lock & 0x3000) || (lock_slave & 0x3000)) 21899a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_CARRIER; 21909a0bf528SMauro Carvalho Chehab if ((lock & 0x0100) || (lock_slave & 0x0100)) 21919a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_VITERBI; 21929a0bf528SMauro Carvalho Chehab if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38)) 21939a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_SYNC; 21949a0bf528SMauro Carvalho Chehab if ((lock & 0x0008) || (lock_slave & 0x0008)) 21959a0bf528SMauro Carvalho Chehab *stat |= FE_HAS_LOCK; 21969a0bf528SMauro Carvalho Chehab 21979a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 21989a0bf528SMauro Carvalho Chehab 21999a0bf528SMauro Carvalho Chehab return 0; 22009a0bf528SMauro Carvalho Chehab } 22019a0bf528SMauro Carvalho Chehab 22029a0bf528SMauro Carvalho Chehab static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) 22039a0bf528SMauro Carvalho Chehab { 22049a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 22059a0bf528SMauro Carvalho Chehab u16 *c; 22069a0bf528SMauro Carvalho Chehab int ret = 0; 22079a0bf528SMauro Carvalho Chehab 22089a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 22093dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 22109a0bf528SMauro Carvalho Chehab return -EINTR; 22119a0bf528SMauro Carvalho Chehab } 22129a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 22133dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 22149a0bf528SMauro Carvalho Chehab ret = -EINTR; 22159a0bf528SMauro Carvalho Chehab goto error; 22169a0bf528SMauro Carvalho Chehab } 22179a0bf528SMauro Carvalho Chehab if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 22189a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 22199a0bf528SMauro Carvalho Chehab ret = -EIO; 22209a0bf528SMauro Carvalho Chehab goto error; 22219a0bf528SMauro Carvalho Chehab } 22229a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, 22239a0bf528SMauro Carvalho Chehab state->i2c_read_buffer, 16 * 2); 22249a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 22259a0bf528SMauro Carvalho Chehab 22269a0bf528SMauro Carvalho Chehab c = (u16 *)state->i2c_read_buffer; 22279a0bf528SMauro Carvalho Chehab 22289a0bf528SMauro Carvalho Chehab *ber = c[10] << 16 | c[11]; 22299a0bf528SMauro Carvalho Chehab 22309a0bf528SMauro Carvalho Chehab error: 22319a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 22329a0bf528SMauro Carvalho Chehab return ret; 22339a0bf528SMauro Carvalho Chehab } 22349a0bf528SMauro Carvalho Chehab 22359a0bf528SMauro Carvalho Chehab static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 22369a0bf528SMauro Carvalho Chehab { 22379a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 22389a0bf528SMauro Carvalho Chehab u8 index_frontend; 22399a0bf528SMauro Carvalho Chehab u16 *c = (u16 *)state->i2c_read_buffer; 22409a0bf528SMauro Carvalho Chehab u16 val; 22419a0bf528SMauro Carvalho Chehab int ret = 0; 22429a0bf528SMauro Carvalho Chehab 22439a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 22443dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 22459a0bf528SMauro Carvalho Chehab return -EINTR; 22469a0bf528SMauro Carvalho Chehab } 22479a0bf528SMauro Carvalho Chehab *strength = 0; 22489a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 22499a0bf528SMauro Carvalho Chehab state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); 22509a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 22519a0bf528SMauro Carvalho Chehab *strength = 65535; 22529a0bf528SMauro Carvalho Chehab else 22539a0bf528SMauro Carvalho Chehab *strength += val; 22549a0bf528SMauro Carvalho Chehab } 22559a0bf528SMauro Carvalho Chehab 22569a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 22573dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 22589a0bf528SMauro Carvalho Chehab ret = -EINTR; 22599a0bf528SMauro Carvalho Chehab goto error; 22609a0bf528SMauro Carvalho Chehab } 22619a0bf528SMauro Carvalho Chehab if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 22629a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 22639a0bf528SMauro Carvalho Chehab ret = -EIO; 22649a0bf528SMauro Carvalho Chehab goto error; 22659a0bf528SMauro Carvalho Chehab } 22669a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); 22679a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 22689a0bf528SMauro Carvalho Chehab 22699a0bf528SMauro Carvalho Chehab val = 65535 - c[4]; 22709a0bf528SMauro Carvalho Chehab if (val > 65535 - *strength) 22719a0bf528SMauro Carvalho Chehab *strength = 65535; 22729a0bf528SMauro Carvalho Chehab else 22739a0bf528SMauro Carvalho Chehab *strength += val; 22749a0bf528SMauro Carvalho Chehab 22759a0bf528SMauro Carvalho Chehab error: 22769a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 22779a0bf528SMauro Carvalho Chehab return ret; 22789a0bf528SMauro Carvalho Chehab } 22799a0bf528SMauro Carvalho Chehab 22809a0bf528SMauro Carvalho Chehab static u32 dib9000_get_snr(struct dvb_frontend *fe) 22819a0bf528SMauro Carvalho Chehab { 22829a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 22839a0bf528SMauro Carvalho Chehab u16 *c = (u16 *)state->i2c_read_buffer; 22849a0bf528SMauro Carvalho Chehab u32 n, s, exp; 22859a0bf528SMauro Carvalho Chehab u16 val; 22869a0bf528SMauro Carvalho Chehab 22879a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 22883dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 22899a0bf528SMauro Carvalho Chehab return 0; 22909a0bf528SMauro Carvalho Chehab } 22919a0bf528SMauro Carvalho Chehab if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 22929a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 22939a0bf528SMauro Carvalho Chehab return 0; 22949a0bf528SMauro Carvalho Chehab } 22959a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); 22969a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 22979a0bf528SMauro Carvalho Chehab 22989a0bf528SMauro Carvalho Chehab val = c[7]; 22999a0bf528SMauro Carvalho Chehab n = (val >> 4) & 0xff; 23009a0bf528SMauro Carvalho Chehab exp = ((val & 0xf) << 2); 23019a0bf528SMauro Carvalho Chehab val = c[8]; 23029a0bf528SMauro Carvalho Chehab exp += ((val >> 14) & 0x3); 23039a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 23049a0bf528SMauro Carvalho Chehab exp -= 0x40; 23059a0bf528SMauro Carvalho Chehab n <<= exp + 16; 23069a0bf528SMauro Carvalho Chehab 23079a0bf528SMauro Carvalho Chehab s = (val >> 6) & 0xFF; 23089a0bf528SMauro Carvalho Chehab exp = (val & 0x3F); 23099a0bf528SMauro Carvalho Chehab if ((exp & 0x20) != 0) 23109a0bf528SMauro Carvalho Chehab exp -= 0x40; 23119a0bf528SMauro Carvalho Chehab s <<= exp + 16; 23129a0bf528SMauro Carvalho Chehab 23139a0bf528SMauro Carvalho Chehab if (n > 0) { 23149a0bf528SMauro Carvalho Chehab u32 t = (s / n) << 16; 23159a0bf528SMauro Carvalho Chehab return t + ((s << 16) - n * t) / n; 23169a0bf528SMauro Carvalho Chehab } 23179a0bf528SMauro Carvalho Chehab return 0xffffffff; 23189a0bf528SMauro Carvalho Chehab } 23199a0bf528SMauro Carvalho Chehab 23209a0bf528SMauro Carvalho Chehab static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) 23219a0bf528SMauro Carvalho Chehab { 23229a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 23239a0bf528SMauro Carvalho Chehab u8 index_frontend; 23249a0bf528SMauro Carvalho Chehab u32 snr_master; 23259a0bf528SMauro Carvalho Chehab 23269a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 23273dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 23289a0bf528SMauro Carvalho Chehab return -EINTR; 23299a0bf528SMauro Carvalho Chehab } 23309a0bf528SMauro Carvalho Chehab snr_master = dib9000_get_snr(fe); 23319a0bf528SMauro Carvalho Chehab for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 23329a0bf528SMauro Carvalho Chehab snr_master += dib9000_get_snr(state->fe[index_frontend]); 23339a0bf528SMauro Carvalho Chehab 23349a0bf528SMauro Carvalho Chehab if ((snr_master >> 16) != 0) { 23359a0bf528SMauro Carvalho Chehab snr_master = 10 * intlog10(snr_master >> 16); 23369a0bf528SMauro Carvalho Chehab *snr = snr_master / ((1 << 24) / 10); 23379a0bf528SMauro Carvalho Chehab } else 23389a0bf528SMauro Carvalho Chehab *snr = 0; 23399a0bf528SMauro Carvalho Chehab 23409a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 23419a0bf528SMauro Carvalho Chehab 23429a0bf528SMauro Carvalho Chehab return 0; 23439a0bf528SMauro Carvalho Chehab } 23449a0bf528SMauro Carvalho Chehab 23459a0bf528SMauro Carvalho Chehab static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) 23469a0bf528SMauro Carvalho Chehab { 23479a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 23489a0bf528SMauro Carvalho Chehab u16 *c = (u16 *)state->i2c_read_buffer; 23499a0bf528SMauro Carvalho Chehab int ret = 0; 23509a0bf528SMauro Carvalho Chehab 23519a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->demod_lock) < 0) { 23523dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 23539a0bf528SMauro Carvalho Chehab return -EINTR; 23549a0bf528SMauro Carvalho Chehab } 23559a0bf528SMauro Carvalho Chehab if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 23563dd72262SMauro Carvalho Chehab dprintk("could not get the lock\n"); 23579a0bf528SMauro Carvalho Chehab ret = -EINTR; 23589a0bf528SMauro Carvalho Chehab goto error; 23599a0bf528SMauro Carvalho Chehab } 23609a0bf528SMauro Carvalho Chehab if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 23619a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 23629a0bf528SMauro Carvalho Chehab ret = -EIO; 23639a0bf528SMauro Carvalho Chehab goto error; 23649a0bf528SMauro Carvalho Chehab } 23659a0bf528SMauro Carvalho Chehab dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); 23669a0bf528SMauro Carvalho Chehab mutex_unlock(&state->platform.risc.mem_mbx_lock); 23679a0bf528SMauro Carvalho Chehab 23689a0bf528SMauro Carvalho Chehab *unc = c[12]; 23699a0bf528SMauro Carvalho Chehab 23709a0bf528SMauro Carvalho Chehab error: 23719a0bf528SMauro Carvalho Chehab mutex_unlock(&state->demod_lock); 23729a0bf528SMauro Carvalho Chehab return ret; 23739a0bf528SMauro Carvalho Chehab } 23749a0bf528SMauro Carvalho Chehab 23759a0bf528SMauro Carvalho Chehab int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) 23769a0bf528SMauro Carvalho Chehab { 23779a0bf528SMauro Carvalho Chehab int k = 0, ret = 0; 23789a0bf528SMauro Carvalho Chehab u8 new_addr = 0; 23799a0bf528SMauro Carvalho Chehab struct i2c_device client = {.i2c_adap = i2c }; 23809a0bf528SMauro Carvalho Chehab 23816396bb22SKees Cook client.i2c_write_buffer = kzalloc(4, GFP_KERNEL); 23829a0bf528SMauro Carvalho Chehab if (!client.i2c_write_buffer) { 23833dd72262SMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__); 23849a0bf528SMauro Carvalho Chehab return -ENOMEM; 23859a0bf528SMauro Carvalho Chehab } 23866396bb22SKees Cook client.i2c_read_buffer = kzalloc(4, GFP_KERNEL); 23879a0bf528SMauro Carvalho Chehab if (!client.i2c_read_buffer) { 23883dd72262SMauro Carvalho Chehab dprintk("%s: not enough memory\n", __func__); 23899a0bf528SMauro Carvalho Chehab ret = -ENOMEM; 23909a0bf528SMauro Carvalho Chehab goto error_memory; 23919a0bf528SMauro Carvalho Chehab } 23929a0bf528SMauro Carvalho Chehab 23939a0bf528SMauro Carvalho Chehab client.i2c_addr = default_addr + 16; 23949a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1796, 0x0); 23959a0bf528SMauro Carvalho Chehab 23969a0bf528SMauro Carvalho Chehab for (k = no_of_demods - 1; k >= 0; k--) { 23979a0bf528SMauro Carvalho Chehab /* designated i2c address */ 23989a0bf528SMauro Carvalho Chehab new_addr = first_addr + (k << 1); 23999a0bf528SMauro Carvalho Chehab client.i2c_addr = default_addr; 24009a0bf528SMauro Carvalho Chehab 24019a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1817, 3); 24029a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1796, 0); 24039a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1227, 1); 24049a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1227, 0); 24059a0bf528SMauro Carvalho Chehab 24069a0bf528SMauro Carvalho Chehab client.i2c_addr = new_addr; 24079a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1817, 3); 24089a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1796, 0); 24099a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1227, 1); 24109a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1227, 0); 24119a0bf528SMauro Carvalho Chehab 24129a0bf528SMauro Carvalho Chehab if (dib9000_identify(&client) == 0) { 24139a0bf528SMauro Carvalho Chehab client.i2c_addr = default_addr; 24149a0bf528SMauro Carvalho Chehab if (dib9000_identify(&client) == 0) { 24153dd72262SMauro Carvalho Chehab dprintk("DiB9000 #%d: not identified\n", k); 24169a0bf528SMauro Carvalho Chehab ret = -EIO; 24179a0bf528SMauro Carvalho Chehab goto error; 24189a0bf528SMauro Carvalho Chehab } 24199a0bf528SMauro Carvalho Chehab } 24209a0bf528SMauro Carvalho Chehab 24219a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6)); 24229a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2); 24239a0bf528SMauro Carvalho Chehab 24243dd72262SMauro Carvalho Chehab dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); 24259a0bf528SMauro Carvalho Chehab } 24269a0bf528SMauro Carvalho Chehab 24279a0bf528SMauro Carvalho Chehab for (k = 0; k < no_of_demods; k++) { 24289a0bf528SMauro Carvalho Chehab new_addr = first_addr | (k << 1); 24299a0bf528SMauro Carvalho Chehab client.i2c_addr = new_addr; 24309a0bf528SMauro Carvalho Chehab 24319a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1794, (new_addr << 2)); 24329a0bf528SMauro Carvalho Chehab dib9000_i2c_write16(&client, 1795, 0); 24339a0bf528SMauro Carvalho Chehab } 24349a0bf528SMauro Carvalho Chehab 24359a0bf528SMauro Carvalho Chehab error: 24369a0bf528SMauro Carvalho Chehab kfree(client.i2c_read_buffer); 24379a0bf528SMauro Carvalho Chehab error_memory: 24389a0bf528SMauro Carvalho Chehab kfree(client.i2c_write_buffer); 24399a0bf528SMauro Carvalho Chehab 24409a0bf528SMauro Carvalho Chehab return ret; 24419a0bf528SMauro Carvalho Chehab } 24429a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_i2c_enumeration); 24439a0bf528SMauro Carvalho Chehab 24449a0bf528SMauro Carvalho Chehab int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) 24459a0bf528SMauro Carvalho Chehab { 24469a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 24479a0bf528SMauro Carvalho Chehab u8 index_frontend = 1; 24489a0bf528SMauro Carvalho Chehab 24499a0bf528SMauro Carvalho Chehab while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 24509a0bf528SMauro Carvalho Chehab index_frontend++; 24519a0bf528SMauro Carvalho Chehab if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { 24523dd72262SMauro Carvalho Chehab dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend); 24539a0bf528SMauro Carvalho Chehab state->fe[index_frontend] = fe_slave; 24549a0bf528SMauro Carvalho Chehab return 0; 24559a0bf528SMauro Carvalho Chehab } 24569a0bf528SMauro Carvalho Chehab 24573dd72262SMauro Carvalho Chehab dprintk("too many slave frontend\n"); 24589a0bf528SMauro Carvalho Chehab return -ENOMEM; 24599a0bf528SMauro Carvalho Chehab } 24609a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_set_slave_frontend); 24619a0bf528SMauro Carvalho Chehab 24629a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) 24639a0bf528SMauro Carvalho Chehab { 24649a0bf528SMauro Carvalho Chehab struct dib9000_state *state = fe->demodulator_priv; 24659a0bf528SMauro Carvalho Chehab 24669a0bf528SMauro Carvalho Chehab if (slave_index >= MAX_NUMBER_OF_FRONTENDS) 24679a0bf528SMauro Carvalho Chehab return NULL; 24689a0bf528SMauro Carvalho Chehab return state->fe[slave_index]; 24699a0bf528SMauro Carvalho Chehab } 24709a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_get_slave_frontend); 24719a0bf528SMauro Carvalho Chehab 2472bd336e63SMax Kellermann static const struct dvb_frontend_ops dib9000_ops; 24739a0bf528SMauro Carvalho Chehab struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg) 24749a0bf528SMauro Carvalho Chehab { 24759a0bf528SMauro Carvalho Chehab struct dvb_frontend *fe; 24769a0bf528SMauro Carvalho Chehab struct dib9000_state *st; 24779a0bf528SMauro Carvalho Chehab st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL); 24789a0bf528SMauro Carvalho Chehab if (st == NULL) 24799a0bf528SMauro Carvalho Chehab return NULL; 24809a0bf528SMauro Carvalho Chehab fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); 24819a0bf528SMauro Carvalho Chehab if (fe == NULL) { 24829a0bf528SMauro Carvalho Chehab kfree(st); 24839a0bf528SMauro Carvalho Chehab return NULL; 24849a0bf528SMauro Carvalho Chehab } 24859a0bf528SMauro Carvalho Chehab 24869a0bf528SMauro Carvalho Chehab memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config)); 24879a0bf528SMauro Carvalho Chehab st->i2c.i2c_adap = i2c_adap; 24889a0bf528SMauro Carvalho Chehab st->i2c.i2c_addr = i2c_addr; 24899a0bf528SMauro Carvalho Chehab st->i2c.i2c_write_buffer = st->i2c_write_buffer; 24909a0bf528SMauro Carvalho Chehab st->i2c.i2c_read_buffer = st->i2c_read_buffer; 24919a0bf528SMauro Carvalho Chehab 24929a0bf528SMauro Carvalho Chehab st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS; 24939a0bf528SMauro Carvalho Chehab st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; 24949a0bf528SMauro Carvalho Chehab st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS; 24959a0bf528SMauro Carvalho Chehab 24969a0bf528SMauro Carvalho Chehab mutex_init(&st->platform.risc.mbx_if_lock); 24979a0bf528SMauro Carvalho Chehab mutex_init(&st->platform.risc.mbx_lock); 24989a0bf528SMauro Carvalho Chehab mutex_init(&st->platform.risc.mem_lock); 24999a0bf528SMauro Carvalho Chehab mutex_init(&st->platform.risc.mem_mbx_lock); 25009a0bf528SMauro Carvalho Chehab mutex_init(&st->demod_lock); 25019a0bf528SMauro Carvalho Chehab st->get_frontend_internal = 0; 25029a0bf528SMauro Carvalho Chehab 25039a0bf528SMauro Carvalho Chehab st->pid_ctrl_index = -2; 25049a0bf528SMauro Carvalho Chehab 25059a0bf528SMauro Carvalho Chehab st->fe[0] = fe; 25069a0bf528SMauro Carvalho Chehab fe->demodulator_priv = st; 25079a0bf528SMauro Carvalho Chehab memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops)); 25089a0bf528SMauro Carvalho Chehab 25099a0bf528SMauro Carvalho Chehab /* Ensure the output mode remains at the previous default if it's 25109a0bf528SMauro Carvalho Chehab * not specifically set by the caller. 25119a0bf528SMauro Carvalho Chehab */ 25129a0bf528SMauro Carvalho Chehab if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) 25139a0bf528SMauro Carvalho Chehab st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO; 25149a0bf528SMauro Carvalho Chehab 25159a0bf528SMauro Carvalho Chehab if (dib9000_identify(&st->i2c) == 0) 25169a0bf528SMauro Carvalho Chehab goto error; 25179a0bf528SMauro Carvalho Chehab 25189a0bf528SMauro Carvalho Chehab dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr); 25199a0bf528SMauro Carvalho Chehab 25209a0bf528SMauro Carvalho Chehab st->tuner_adap.dev.parent = i2c_adap->dev.parent; 252185709cbfSMauro Carvalho Chehab strscpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", 252285709cbfSMauro Carvalho Chehab sizeof(st->tuner_adap.name)); 25239a0bf528SMauro Carvalho Chehab st->tuner_adap.algo = &dib9000_tuner_algo; 25249a0bf528SMauro Carvalho Chehab st->tuner_adap.algo_data = NULL; 25259a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&st->tuner_adap, st); 25269a0bf528SMauro Carvalho Chehab if (i2c_add_adapter(&st->tuner_adap) < 0) 25279a0bf528SMauro Carvalho Chehab goto error; 25289a0bf528SMauro Carvalho Chehab 25299a0bf528SMauro Carvalho Chehab st->component_bus.dev.parent = i2c_adap->dev.parent; 253085709cbfSMauro Carvalho Chehab strscpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", 253185709cbfSMauro Carvalho Chehab sizeof(st->component_bus.name)); 25329a0bf528SMauro Carvalho Chehab st->component_bus.algo = &dib9000_component_bus_algo; 25339a0bf528SMauro Carvalho Chehab st->component_bus.algo_data = NULL; 25349a0bf528SMauro Carvalho Chehab st->component_bus_speed = 340; 25359a0bf528SMauro Carvalho Chehab i2c_set_adapdata(&st->component_bus, st); 25369a0bf528SMauro Carvalho Chehab if (i2c_add_adapter(&st->component_bus) < 0) 25379a0bf528SMauro Carvalho Chehab goto component_bus_add_error; 25389a0bf528SMauro Carvalho Chehab 25399a0bf528SMauro Carvalho Chehab dib9000_fw_reset(fe); 25409a0bf528SMauro Carvalho Chehab 25419a0bf528SMauro Carvalho Chehab return fe; 25429a0bf528SMauro Carvalho Chehab 25439a0bf528SMauro Carvalho Chehab component_bus_add_error: 25449a0bf528SMauro Carvalho Chehab i2c_del_adapter(&st->tuner_adap); 25459a0bf528SMauro Carvalho Chehab error: 25469a0bf528SMauro Carvalho Chehab kfree(st); 25479a0bf528SMauro Carvalho Chehab return NULL; 25489a0bf528SMauro Carvalho Chehab } 25499a0bf528SMauro Carvalho Chehab EXPORT_SYMBOL(dib9000_attach); 25509a0bf528SMauro Carvalho Chehab 2551bd336e63SMax Kellermann static const struct dvb_frontend_ops dib9000_ops = { 25529a0bf528SMauro Carvalho Chehab .delsys = { SYS_DVBT }, 25539a0bf528SMauro Carvalho Chehab .info = { 25549a0bf528SMauro Carvalho Chehab .name = "DiBcom 9000", 2555f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 44250 * kHz, 2556f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 867250 * kHz, 2557f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 62500, 25589a0bf528SMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | 25599a0bf528SMauro Carvalho Chehab FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 25609a0bf528SMauro Carvalho Chehab FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 25619a0bf528SMauro Carvalho Chehab FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 25629a0bf528SMauro Carvalho Chehab FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, 25639a0bf528SMauro Carvalho Chehab }, 25649a0bf528SMauro Carvalho Chehab 25659a0bf528SMauro Carvalho Chehab .release = dib9000_release, 25669a0bf528SMauro Carvalho Chehab 25679a0bf528SMauro Carvalho Chehab .init = dib9000_wakeup, 25689a0bf528SMauro Carvalho Chehab .sleep = dib9000_sleep, 25699a0bf528SMauro Carvalho Chehab 25709a0bf528SMauro Carvalho Chehab .set_frontend = dib9000_set_frontend, 25719a0bf528SMauro Carvalho Chehab .get_tune_settings = dib9000_fe_get_tune_settings, 25729a0bf528SMauro Carvalho Chehab .get_frontend = dib9000_get_frontend, 25739a0bf528SMauro Carvalho Chehab 25749a0bf528SMauro Carvalho Chehab .read_status = dib9000_read_status, 25759a0bf528SMauro Carvalho Chehab .read_ber = dib9000_read_ber, 25769a0bf528SMauro Carvalho Chehab .read_signal_strength = dib9000_read_signal_strength, 25779a0bf528SMauro Carvalho Chehab .read_snr = dib9000_read_snr, 25789a0bf528SMauro Carvalho Chehab .read_ucblocks = dib9000_read_unc_blocks, 25799a0bf528SMauro Carvalho Chehab }; 25809a0bf528SMauro Carvalho Chehab 258199e44da7SPatrick Boettcher MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 258299e44da7SPatrick Boettcher MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>"); 25839a0bf528SMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator"); 25849a0bf528SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 2585