18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/mutex.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <media/dvb_math.h> 158c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "dib9000.h" 188c2ecf20Sopenharmony_ci#include "dibx000_common.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int debug; 218c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do { \ 258c2ecf20Sopenharmony_ci if (debug) \ 268c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 278c2ecf20Sopenharmony_ci __func__, ##arg); \ 288c2ecf20Sopenharmony_ci} while (0) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define MAX_NUMBER_OF_FRONTENDS 6 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct i2c_device { 338c2ecf20Sopenharmony_ci struct i2c_adapter *i2c_adap; 348c2ecf20Sopenharmony_ci u8 i2c_addr; 358c2ecf20Sopenharmony_ci u8 *i2c_read_buffer; 368c2ecf20Sopenharmony_ci u8 *i2c_write_buffer; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct dib9000_pid_ctrl { 408c2ecf20Sopenharmony_ci#define DIB9000_PID_FILTER_CTRL 0 418c2ecf20Sopenharmony_ci#define DIB9000_PID_FILTER 1 428c2ecf20Sopenharmony_ci u8 cmd; 438c2ecf20Sopenharmony_ci u8 id; 448c2ecf20Sopenharmony_ci u16 pid; 458c2ecf20Sopenharmony_ci u8 onoff; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct dib9000_state { 498c2ecf20Sopenharmony_ci struct i2c_device i2c; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci struct dibx000_i2c_master i2c_master; 528c2ecf20Sopenharmony_ci struct i2c_adapter tuner_adap; 538c2ecf20Sopenharmony_ci struct i2c_adapter component_bus; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci u16 revision; 568c2ecf20Sopenharmony_ci u8 reg_offs; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci enum frontend_tune_state tune_state; 598c2ecf20Sopenharmony_ci u32 status; 608c2ecf20Sopenharmony_ci struct dvb_frontend_parametersContext channel_status; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci u8 fe_id; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff 658c2ecf20Sopenharmony_ci u16 gpio_dir; 668c2ecf20Sopenharmony_ci#define DIB9000_GPIO_DEFAULT_VALUES 0x0000 678c2ecf20Sopenharmony_ci u16 gpio_val; 688c2ecf20Sopenharmony_ci#define DIB9000_GPIO_DEFAULT_PWM_POS 0xffff 698c2ecf20Sopenharmony_ci u16 gpio_pwm_pos; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci union { /* common for all chips */ 728c2ecf20Sopenharmony_ci struct { 738c2ecf20Sopenharmony_ci u8 mobile_mode:1; 748c2ecf20Sopenharmony_ci } host; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci struct { 778c2ecf20Sopenharmony_ci struct dib9000_fe_memory_map { 788c2ecf20Sopenharmony_ci u16 addr; 798c2ecf20Sopenharmony_ci u16 size; 808c2ecf20Sopenharmony_ci } fe_mm[18]; 818c2ecf20Sopenharmony_ci u8 memcmd; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci struct mutex mbx_if_lock; /* to protect read/write operations */ 848c2ecf20Sopenharmony_ci struct mutex mbx_lock; /* to protect the whole mailbox handling */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci struct mutex mem_lock; /* to protect the memory accesses */ 878c2ecf20Sopenharmony_ci struct mutex mem_mbx_lock; /* to protect the memory-based mailbox */ 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define MBX_MAX_WORDS (256 - 200 - 2) 908c2ecf20Sopenharmony_ci#define DIB9000_MSG_CACHE_SIZE 2 918c2ecf20Sopenharmony_ci u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS]; 928c2ecf20Sopenharmony_ci u8 fw_is_running; 938c2ecf20Sopenharmony_ci } risc; 948c2ecf20Sopenharmony_ci } platform; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci union { /* common for all platforms */ 978c2ecf20Sopenharmony_ci struct { 988c2ecf20Sopenharmony_ci struct dib9000_config cfg; 998c2ecf20Sopenharmony_ci } d9; 1008c2ecf20Sopenharmony_ci } chip; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; 1038c2ecf20Sopenharmony_ci u16 component_bus_speed; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* for the I2C transfer */ 1068c2ecf20Sopenharmony_ci struct i2c_msg msg[2]; 1078c2ecf20Sopenharmony_ci u8 i2c_write_buffer[255]; 1088c2ecf20Sopenharmony_ci u8 i2c_read_buffer[255]; 1098c2ecf20Sopenharmony_ci struct mutex demod_lock; 1108c2ecf20Sopenharmony_ci u8 get_frontend_internal; 1118c2ecf20Sopenharmony_ci struct dib9000_pid_ctrl pid_ctrl[10]; 1128c2ecf20Sopenharmony_ci s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */ 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1168c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1178c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cienum dib9000_power_mode { 1218c2ecf20Sopenharmony_ci DIB9000_POWER_ALL = 0, 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci DIB9000_POWER_NO, 1248c2ecf20Sopenharmony_ci DIB9000_POWER_INTERF_ANALOG_AGC, 1258c2ecf20Sopenharmony_ci DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, 1268c2ecf20Sopenharmony_ci DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD, 1278c2ecf20Sopenharmony_ci DIB9000_POWER_INTERFACE_ONLY, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cienum dib9000_out_messages { 1318c2ecf20Sopenharmony_ci OUT_MSG_HBM_ACK, 1328c2ecf20Sopenharmony_ci OUT_MSG_HOST_BUF_FAIL, 1338c2ecf20Sopenharmony_ci OUT_MSG_REQ_VERSION, 1348c2ecf20Sopenharmony_ci OUT_MSG_BRIDGE_I2C_W, 1358c2ecf20Sopenharmony_ci OUT_MSG_BRIDGE_I2C_R, 1368c2ecf20Sopenharmony_ci OUT_MSG_BRIDGE_APB_W, 1378c2ecf20Sopenharmony_ci OUT_MSG_BRIDGE_APB_R, 1388c2ecf20Sopenharmony_ci OUT_MSG_SCAN_CHANNEL, 1398c2ecf20Sopenharmony_ci OUT_MSG_MONIT_DEMOD, 1408c2ecf20Sopenharmony_ci OUT_MSG_CONF_GPIO, 1418c2ecf20Sopenharmony_ci OUT_MSG_DEBUG_HELP, 1428c2ecf20Sopenharmony_ci OUT_MSG_SUBBAND_SEL, 1438c2ecf20Sopenharmony_ci OUT_MSG_ENABLE_TIME_SLICE, 1448c2ecf20Sopenharmony_ci OUT_MSG_FE_FW_DL, 1458c2ecf20Sopenharmony_ci OUT_MSG_FE_CHANNEL_SEARCH, 1468c2ecf20Sopenharmony_ci OUT_MSG_FE_CHANNEL_TUNE, 1478c2ecf20Sopenharmony_ci OUT_MSG_FE_SLEEP, 1488c2ecf20Sopenharmony_ci OUT_MSG_FE_SYNC, 1498c2ecf20Sopenharmony_ci OUT_MSG_CTL_MONIT, 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci OUT_MSG_CONF_SVC, 1528c2ecf20Sopenharmony_ci OUT_MSG_SET_HBM, 1538c2ecf20Sopenharmony_ci OUT_MSG_INIT_DEMOD, 1548c2ecf20Sopenharmony_ci OUT_MSG_ENABLE_DIVERSITY, 1558c2ecf20Sopenharmony_ci OUT_MSG_SET_OUTPUT_MODE, 1568c2ecf20Sopenharmony_ci OUT_MSG_SET_PRIORITARY_CHANNEL, 1578c2ecf20Sopenharmony_ci OUT_MSG_ACK_FRG, 1588c2ecf20Sopenharmony_ci OUT_MSG_INIT_PMU, 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cienum dib9000_in_messages { 1628c2ecf20Sopenharmony_ci IN_MSG_DATA, 1638c2ecf20Sopenharmony_ci IN_MSG_FRAME_INFO, 1648c2ecf20Sopenharmony_ci IN_MSG_CTL_MONIT, 1658c2ecf20Sopenharmony_ci IN_MSG_ACK_FREE_ITEM, 1668c2ecf20Sopenharmony_ci IN_MSG_DEBUG_BUF, 1678c2ecf20Sopenharmony_ci IN_MSG_MPE_MONITOR, 1688c2ecf20Sopenharmony_ci IN_MSG_RAWTS_MONITOR, 1698c2ecf20Sopenharmony_ci IN_MSG_END_BRIDGE_I2C_RW, 1708c2ecf20Sopenharmony_ci IN_MSG_END_BRIDGE_APB_RW, 1718c2ecf20Sopenharmony_ci IN_MSG_VERSION, 1728c2ecf20Sopenharmony_ci IN_MSG_END_OF_SCAN, 1738c2ecf20Sopenharmony_ci IN_MSG_MONIT_DEMOD, 1748c2ecf20Sopenharmony_ci IN_MSG_ERROR, 1758c2ecf20Sopenharmony_ci IN_MSG_FE_FW_DL_DONE, 1768c2ecf20Sopenharmony_ci IN_MSG_EVENT, 1778c2ecf20Sopenharmony_ci IN_MSG_ACK_CHANGE_SVC, 1788c2ecf20Sopenharmony_ci IN_MSG_HBM_PROF, 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* memory_access requests */ 1828c2ecf20Sopenharmony_ci#define FE_MM_W_CHANNEL 0 1838c2ecf20Sopenharmony_ci#define FE_MM_W_FE_INFO 1 1848c2ecf20Sopenharmony_ci#define FE_MM_RW_SYNC 2 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#define FE_SYNC_CHANNEL 1 1878c2ecf20Sopenharmony_ci#define FE_SYNC_W_GENERIC_MONIT 2 1888c2ecf20Sopenharmony_ci#define FE_SYNC_COMPONENT_ACCESS 3 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define FE_MM_R_CHANNEL_SEARCH_STATE 3 1918c2ecf20Sopenharmony_ci#define FE_MM_R_CHANNEL_UNION_CONTEXT 4 1928c2ecf20Sopenharmony_ci#define FE_MM_R_FE_INFO 5 1938c2ecf20Sopenharmony_ci#define FE_MM_R_FE_MONITOR 6 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define FE_MM_W_CHANNEL_HEAD 7 1968c2ecf20Sopenharmony_ci#define FE_MM_W_CHANNEL_UNION 8 1978c2ecf20Sopenharmony_ci#define FE_MM_W_CHANNEL_CONTEXT 9 1988c2ecf20Sopenharmony_ci#define FE_MM_R_CHANNEL_UNION 10 1998c2ecf20Sopenharmony_ci#define FE_MM_R_CHANNEL_CONTEXT 11 2008c2ecf20Sopenharmony_ci#define FE_MM_R_CHANNEL_TUNE_STATE 12 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci#define FE_MM_R_GENERIC_MONITORING_SIZE 13 2038c2ecf20Sopenharmony_ci#define FE_MM_W_GENERIC_MONITORING 14 2048c2ecf20Sopenharmony_ci#define FE_MM_R_GENERIC_MONITORING 15 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#define FE_MM_W_COMPONENT_ACCESS 16 2078c2ecf20Sopenharmony_ci#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17 2088c2ecf20Sopenharmony_cistatic int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len); 2098c2ecf20Sopenharmony_cistatic int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic u16 to_fw_output_mode(u16 mode) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci switch (mode) { 2148c2ecf20Sopenharmony_ci case OUTMODE_HIGH_Z: 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_GATED_CLK: 2178c2ecf20Sopenharmony_ci return 4; 2188c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_CONT_CLK: 2198c2ecf20Sopenharmony_ci return 8; 2208c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_SERIAL: 2218c2ecf20Sopenharmony_ci return 16; 2228c2ecf20Sopenharmony_ci case OUTMODE_DIVERSITY: 2238c2ecf20Sopenharmony_ci return 128; 2248c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_FIFO: 2258c2ecf20Sopenharmony_ci return 2; 2268c2ecf20Sopenharmony_ci case OUTMODE_ANALOG_ADC: 2278c2ecf20Sopenharmony_ci return 1; 2288c2ecf20Sopenharmony_ci default: 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 *b, u32 len, u16 attribute) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci u32 chunk_size = 126; 2368c2ecf20Sopenharmony_ci u32 l; 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (state->platform.risc.fw_is_running && (reg < 1024)) 2408c2ecf20Sopenharmony_ci return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 2438c2ecf20Sopenharmony_ci state->msg[0].addr = state->i2c.i2c_addr >> 1; 2448c2ecf20Sopenharmony_ci state->msg[0].flags = 0; 2458c2ecf20Sopenharmony_ci state->msg[0].buf = state->i2c_write_buffer; 2468c2ecf20Sopenharmony_ci state->msg[0].len = 2; 2478c2ecf20Sopenharmony_ci state->msg[1].addr = state->i2c.i2c_addr >> 1; 2488c2ecf20Sopenharmony_ci state->msg[1].flags = I2C_M_RD; 2498c2ecf20Sopenharmony_ci state->msg[1].buf = b; 2508c2ecf20Sopenharmony_ci state->msg[1].len = len; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] = reg >> 8; 2538c2ecf20Sopenharmony_ci state->i2c_write_buffer[1] = reg & 0xff; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (attribute & DATA_BUS_ACCESS_MODE_8BIT) 2568c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] |= (1 << 5); 2578c2ecf20Sopenharmony_ci if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 2588c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] |= (1 << 4); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci do { 2618c2ecf20Sopenharmony_ci l = len < chunk_size ? len : chunk_size; 2628c2ecf20Sopenharmony_ci state->msg[1].len = l; 2638c2ecf20Sopenharmony_ci state->msg[1].buf = b; 2648c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0; 2658c2ecf20Sopenharmony_ci if (ret != 0) { 2668c2ecf20Sopenharmony_ci dprintk("i2c read error on %d\n", reg); 2678c2ecf20Sopenharmony_ci return -EREMOTEIO; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci b += l; 2718c2ecf20Sopenharmony_ci len -= l; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) 2748c2ecf20Sopenharmony_ci reg += l / 2; 2758c2ecf20Sopenharmony_ci } while ((ret == 0) && len); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 2838c2ecf20Sopenharmony_ci {.addr = i2c->i2c_addr >> 1, .flags = 0, 2848c2ecf20Sopenharmony_ci .buf = i2c->i2c_write_buffer, .len = 2}, 2858c2ecf20Sopenharmony_ci {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, 2868c2ecf20Sopenharmony_ci .buf = i2c->i2c_read_buffer, .len = 2}, 2878c2ecf20Sopenharmony_ci }; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci i2c->i2c_write_buffer[0] = reg >> 8; 2908c2ecf20Sopenharmony_ci i2c->i2c_write_buffer[1] = reg & 0xff; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { 2938c2ecf20Sopenharmony_ci dprintk("read register %x error\n", reg); 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1]; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0) 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 3108c2ecf20Sopenharmony_ci attribute) != 0) 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci#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) 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *buf, u32 len, u16 attribute) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci u32 chunk_size = 126; 3208c2ecf20Sopenharmony_ci u32 l; 3218c2ecf20Sopenharmony_ci int ret; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (state->platform.risc.fw_is_running && (reg < 1024)) { 3248c2ecf20Sopenharmony_ci if (dib9000_risc_apb_access_write 3258c2ecf20Sopenharmony_ci (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) 3268c2ecf20Sopenharmony_ci return -EINVAL; 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci memset(&state->msg[0], 0, sizeof(struct i2c_msg)); 3318c2ecf20Sopenharmony_ci state->msg[0].addr = state->i2c.i2c_addr >> 1; 3328c2ecf20Sopenharmony_ci state->msg[0].flags = 0; 3338c2ecf20Sopenharmony_ci state->msg[0].buf = state->i2c_write_buffer; 3348c2ecf20Sopenharmony_ci state->msg[0].len = len + 2; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] = (reg >> 8) & 0xff; 3378c2ecf20Sopenharmony_ci state->i2c_write_buffer[1] = (reg) & 0xff; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (attribute & DATA_BUS_ACCESS_MODE_8BIT) 3408c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] |= (1 << 5); 3418c2ecf20Sopenharmony_ci if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 3428c2ecf20Sopenharmony_ci state->i2c_write_buffer[0] |= (1 << 4); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci do { 3458c2ecf20Sopenharmony_ci l = len < chunk_size ? len : chunk_size; 3468c2ecf20Sopenharmony_ci state->msg[0].len = l + 2; 3478c2ecf20Sopenharmony_ci memcpy(&state->i2c_write_buffer[2], buf, l); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci buf += l; 3528c2ecf20Sopenharmony_ci len -= l; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) 3558c2ecf20Sopenharmony_ci reg += l / 2; 3568c2ecf20Sopenharmony_ci } while ((ret == 0) && len); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return ret; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct i2c_msg msg = { 3648c2ecf20Sopenharmony_ci .addr = i2c->i2c_addr >> 1, .flags = 0, 3658c2ecf20Sopenharmony_ci .buf = i2c->i2c_write_buffer, .len = 4 3668c2ecf20Sopenharmony_ci }; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff; 3698c2ecf20Sopenharmony_ci i2c->i2c_write_buffer[1] = reg & 0xff; 3708c2ecf20Sopenharmony_ci i2c->i2c_write_buffer[2] = (val >> 8) & 0xff; 3718c2ecf20Sopenharmony_ci i2c->i2c_write_buffer[3] = val & 0xff; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci u8 b[2] = { val >> 8, val & 0xff }; 3798c2ecf20Sopenharmony_ci return dib9000_write16_attr(state, reg, b, 2, 0); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci u8 b[2] = { val >> 8, val & 0xff }; 3858c2ecf20Sopenharmony_ci return dib9000_write16_attr(state, reg, b, 2, attribute); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0) 3898c2ecf20Sopenharmony_ci#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) 3908c2ecf20Sopenharmony_ci#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)) 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0) 3938c2ecf20Sopenharmony_ci#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0) 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci#define MAC_IRQ (1 << 1) 3968c2ecf20Sopenharmony_ci#define IRQ_POL_MSK (1 << 4) 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci#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) 3998c2ecf20Sopenharmony_ci#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) 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci u8 b[14] = { 0 }; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */ 4068c2ecf20Sopenharmony_ci/* b[0] = 0 << 7; */ 4078c2ecf20Sopenharmony_ci b[1] = 1; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* b[2] = 0; */ 4108c2ecf20Sopenharmony_ci/* b[3] = 0; */ 4118c2ecf20Sopenharmony_ci b[4] = (u8) (addr >> 8); 4128c2ecf20Sopenharmony_ci b[5] = (u8) (addr & 0xff); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/* b[10] = 0; */ 4158c2ecf20Sopenharmony_ci/* b[11] = 0; */ 4168c2ecf20Sopenharmony_ci b[12] = (u8) (addr >> 8); 4178c2ecf20Sopenharmony_ci b[13] = (u8) (addr & 0xff); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci addr += len; 4208c2ecf20Sopenharmony_ci/* b[6] = 0; */ 4218c2ecf20Sopenharmony_ci/* b[7] = 0; */ 4228c2ecf20Sopenharmony_ci b[8] = (u8) (addr >> 8); 4238c2ecf20Sopenharmony_ci b[9] = (u8) (addr & 0xff); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci dib9000_write(state, 1056, b, 14); 4268c2ecf20Sopenharmony_ci if (reading) 4278c2ecf20Sopenharmony_ci dib9000_write_word(state, 1056, (1 << 15) | 1); 4288c2ecf20Sopenharmony_ci state->platform.risc.memcmd = -1; /* if it was called directly reset it - to force a future setup-call to set it */ 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f]; 4348c2ecf20Sopenharmony_ci /* decide whether we need to "refresh" the memory controller */ 4358c2ecf20Sopenharmony_ci if (state->platform.risc.memcmd == cmd && /* same command */ 4368c2ecf20Sopenharmony_ci !(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 */ 4378c2ecf20Sopenharmony_ci return; 4388c2ecf20Sopenharmony_ci dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80); 4398c2ecf20Sopenharmony_ci state->platform.risc.memcmd = cmd; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci if (!state->platform.risc.fw_is_running) 4458c2ecf20Sopenharmony_ci return -EIO; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { 4488c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 4498c2ecf20Sopenharmony_ci return -EINTR; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci dib9000_risc_mem_setup(state, cmd | 0x80); 4528c2ecf20Sopenharmony_ci dib9000_risc_mem_read_chunks(state, b, len); 4538c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_lock); 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd]; 4608c2ecf20Sopenharmony_ci if (!state->platform.risc.fw_is_running) 4618c2ecf20Sopenharmony_ci return -EIO; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { 4648c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 4658c2ecf20Sopenharmony_ci return -EINTR; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci dib9000_risc_mem_setup(state, cmd); 4688c2ecf20Sopenharmony_ci dib9000_risc_mem_write_chunks(state, b, m->size); 4698c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_lock); 4708c2ecf20Sopenharmony_ci return 0; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci u16 offs; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (risc_id == 1) 4788c2ecf20Sopenharmony_ci offs = 16; 4798c2ecf20Sopenharmony_ci else 4808c2ecf20Sopenharmony_ci offs = 0; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* config crtl reg */ 4838c2ecf20Sopenharmony_ci dib9000_write_word(state, 1024 + offs, 0x000f); 4848c2ecf20Sopenharmony_ci dib9000_write_word(state, 1025 + offs, 0); 4858c2ecf20Sopenharmony_ci dib9000_write_word(state, 1031 + offs, key); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci dprintk("going to download %dB of microcode\n", len); 4888c2ecf20Sopenharmony_ci if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) { 4898c2ecf20Sopenharmony_ci dprintk("error while downloading microcode for RISC %c\n", 'A' + risc_id); 4908c2ecf20Sopenharmony_ci return -EIO; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci dprintk("Microcode for RISC %c loaded\n", 'A' + risc_id); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci u16 mbox_offs; 5018c2ecf20Sopenharmony_ci u16 reset_reg; 5028c2ecf20Sopenharmony_ci u16 tries = 1000; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (risc_id == 1) 5058c2ecf20Sopenharmony_ci mbox_offs = 16; 5068c2ecf20Sopenharmony_ci else 5078c2ecf20Sopenharmony_ci mbox_offs = 0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* Reset mailbox */ 5108c2ecf20Sopenharmony_ci dib9000_write_word(state, 1027 + mbox_offs, 0x8000); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Read reset status */ 5138c2ecf20Sopenharmony_ci do { 5148c2ecf20Sopenharmony_ci reset_reg = dib9000_read_word(state, 1027 + mbox_offs); 5158c2ecf20Sopenharmony_ci msleep(100); 5168c2ecf20Sopenharmony_ci } while ((reset_reg & 0x8000) && --tries); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (reset_reg & 0x8000) { 5198c2ecf20Sopenharmony_ci dprintk("MBX: init ERROR, no response from RISC %c\n", 'A' + risc_id); 5208c2ecf20Sopenharmony_ci return -EIO; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci dprintk("MBX: initialized\n"); 5238c2ecf20Sopenharmony_ci return 0; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci#define MAX_MAILBOX_TRY 100 5278c2ecf20Sopenharmony_cistatic int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci u8 *d, b[2]; 5308c2ecf20Sopenharmony_ci u16 tmp; 5318c2ecf20Sopenharmony_ci u16 size; 5328c2ecf20Sopenharmony_ci u32 i; 5338c2ecf20Sopenharmony_ci int ret = 0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (!state->platform.risc.fw_is_running) 5368c2ecf20Sopenharmony_ci return -EINVAL; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { 5398c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 5408c2ecf20Sopenharmony_ci return -EINTR; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci tmp = MAX_MAILBOX_TRY; 5438c2ecf20Sopenharmony_ci do { 5448c2ecf20Sopenharmony_ci size = dib9000_read_word_attr(state, 1043, attr) & 0xff; 5458c2ecf20Sopenharmony_ci if ((size + len + 1) > MBX_MAX_WORDS && --tmp) { 5468c2ecf20Sopenharmony_ci dprintk("MBX: RISC mbx full, retrying\n"); 5478c2ecf20Sopenharmony_ci msleep(100); 5488c2ecf20Sopenharmony_ci } else 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } while (1); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /*dprintk( "MBX: size: %d\n", size); */ 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (tmp == 0) { 5558c2ecf20Sopenharmony_ci ret = -EINVAL; 5568c2ecf20Sopenharmony_ci goto out; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci#ifdef DUMP_MSG 5598c2ecf20Sopenharmony_ci dprintk("--> %02x %d %*ph\n", id, len + 1, len, data); 5608c2ecf20Sopenharmony_ci#endif 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* byte-order conversion - works on big (where it is not necessary) or little endian */ 5638c2ecf20Sopenharmony_ci d = (u8 *) data; 5648c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 5658c2ecf20Sopenharmony_ci tmp = data[i]; 5668c2ecf20Sopenharmony_ci *d++ = tmp >> 8; 5678c2ecf20Sopenharmony_ci *d++ = tmp & 0xff; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* write msg */ 5718c2ecf20Sopenharmony_ci b[0] = id; 5728c2ecf20Sopenharmony_ci b[1] = len + 1; 5738c2ecf20Sopenharmony_ci if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) { 5748c2ecf20Sopenharmony_ci ret = -EIO; 5758c2ecf20Sopenharmony_ci goto out; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* update register nb_mes_in_RX */ 5798c2ecf20Sopenharmony_ci ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ciout: 5828c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mbx_if_lock); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return ret; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci#ifdef DUMP_MSG 5908c2ecf20Sopenharmony_ci u16 *d = data; 5918c2ecf20Sopenharmony_ci#endif 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci u16 tmp, i; 5948c2ecf20Sopenharmony_ci u8 size; 5958c2ecf20Sopenharmony_ci u8 mc_base; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (!state->platform.risc.fw_is_running) 5988c2ecf20Sopenharmony_ci return 0; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { 6018c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci if (risc_id == 1) 6058c2ecf20Sopenharmony_ci mc_base = 16; 6068c2ecf20Sopenharmony_ci else 6078c2ecf20Sopenharmony_ci mc_base = 0; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* Length and type in the first word */ 6108c2ecf20Sopenharmony_ci *data = dib9000_read_word_attr(state, 1029 + mc_base, attr); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci size = *data & 0xff; 6138c2ecf20Sopenharmony_ci if (size <= MBX_MAX_WORDS) { 6148c2ecf20Sopenharmony_ci data++; 6158c2ecf20Sopenharmony_ci size--; /* Initial word already read */ 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* to word conversion */ 6208c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 6218c2ecf20Sopenharmony_ci tmp = *data; 6228c2ecf20Sopenharmony_ci *data = (tmp >> 8) | (tmp << 8); 6238c2ecf20Sopenharmony_ci data++; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci#ifdef DUMP_MSG 6278c2ecf20Sopenharmony_ci dprintk("<--\n"); 6288c2ecf20Sopenharmony_ci for (i = 0; i < size + 1; i++) 6298c2ecf20Sopenharmony_ci dprintk("%04x\n", d[i]); 6308c2ecf20Sopenharmony_ci dprintk("\n"); 6318c2ecf20Sopenharmony_ci#endif 6328c2ecf20Sopenharmony_ci } else { 6338c2ecf20Sopenharmony_ci dprintk("MBX: message is too big for message cache (%d), flushing message\n", size); 6348c2ecf20Sopenharmony_ci size--; /* Initial word already read */ 6358c2ecf20Sopenharmony_ci while (size--) 6368c2ecf20Sopenharmony_ci dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci /* Update register nb_mes_in_TX */ 6398c2ecf20Sopenharmony_ci dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mbx_if_lock); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return size + 1; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci u32 ts = data[1] << 16 | data[0]; 6498c2ecf20Sopenharmony_ci char *b = (char *)&data[2]; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */ 6528c2ecf20Sopenharmony_ci if (*b == '~') { 6538c2ecf20Sopenharmony_ci b++; 6548c2ecf20Sopenharmony_ci dprintk("%s\n", b); 6558c2ecf20Sopenharmony_ci } else 6568c2ecf20Sopenharmony_ci dprintk("RISC%d: %d.%04d %s\n", 6578c2ecf20Sopenharmony_ci state->fe_id, 6588c2ecf20Sopenharmony_ci ts / 10000, ts % 10000, *b ? b : "<empty>"); 6598c2ecf20Sopenharmony_ci return 1; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci int i; 6658c2ecf20Sopenharmony_ci u8 size; 6668c2ecf20Sopenharmony_ci u16 *block; 6678c2ecf20Sopenharmony_ci /* find a free slot */ 6688c2ecf20Sopenharmony_ci for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { 6698c2ecf20Sopenharmony_ci block = state->platform.risc.message_cache[i]; 6708c2ecf20Sopenharmony_ci if (*block == 0) { 6718c2ecf20Sopenharmony_ci size = dib9000_mbx_read(state, block, 1, attr); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci/* dprintk( "MBX: fetched %04x message to cache\n", *block); */ 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci switch (*block >> 8) { 6768c2ecf20Sopenharmony_ci case IN_MSG_DEBUG_BUF: 6778c2ecf20Sopenharmony_ci dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */ 6788c2ecf20Sopenharmony_ci *block = 0; /* free the block */ 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci#if 0 6818c2ecf20Sopenharmony_ci case IN_MSG_DATA: /* FE-TRACE */ 6828c2ecf20Sopenharmony_ci dib9000_risc_data_process(state, block + 1, size); 6838c2ecf20Sopenharmony_ci *block = 0; 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci#endif 6868c2ecf20Sopenharmony_ci default: 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return 1; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci dprintk("MBX: no free cache-slot found for new message...\n"); 6948c2ecf20Sopenharmony_ci return -1; 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci if (risc_id == 0) 7008c2ecf20Sopenharmony_ci return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f; /* 5 bit field */ 7018c2ecf20Sopenharmony_ci else 7028c2ecf20Sopenharmony_ci return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f; /* 7 bit field */ 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic int dib9000_mbx_process(struct dib9000_state *state, u16 attr) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci int ret = 0; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (!state->platform.risc.fw_is_running) 7108c2ecf20Sopenharmony_ci return -1; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) { 7138c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 7148c2ecf20Sopenharmony_ci return -1; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ 7188c2ecf20Sopenharmony_ci ret = dib9000_mbx_fetch_to_cache(state, attr); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ 7218c2ecf20Sopenharmony_ci/* if (tmp) */ 7228c2ecf20Sopenharmony_ci/* dprintk( "cleared IRQ: %x\n", tmp); */ 7238c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mbx_lock); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return ret; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci u8 i; 7318c2ecf20Sopenharmony_ci u16 *block; 7328c2ecf20Sopenharmony_ci u16 timeout = 30; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci *msg = 0; 7358c2ecf20Sopenharmony_ci do { 7368c2ecf20Sopenharmony_ci /* dib9000_mbx_get_from_cache(); */ 7378c2ecf20Sopenharmony_ci for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { 7388c2ecf20Sopenharmony_ci block = state->platform.risc.message_cache[i]; 7398c2ecf20Sopenharmony_ci if ((*block >> 8) == id) { 7408c2ecf20Sopenharmony_ci *size = (*block & 0xff) - 1; 7418c2ecf20Sopenharmony_ci memcpy(msg, block + 1, (*size) * 2); 7428c2ecf20Sopenharmony_ci *block = 0; /* free the block */ 7438c2ecf20Sopenharmony_ci i = 0; /* signal that we found a message */ 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (i == 0) 7498c2ecf20Sopenharmony_ci break; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (dib9000_mbx_process(state, attr) == -1) /* try to fetch one message - if any */ 7528c2ecf20Sopenharmony_ci return -1; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci } while (--timeout); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (timeout == 0) { 7578c2ecf20Sopenharmony_ci dprintk("waiting for message %d timed out\n", id); 7588c2ecf20Sopenharmony_ci return -1; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return i == 0; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int dib9000_risc_check_version(struct dib9000_state *state) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci u8 r[4]; 7678c2ecf20Sopenharmony_ci u8 size; 7688c2ecf20Sopenharmony_ci u16 fw_version = 0; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0) 7718c2ecf20Sopenharmony_ci return -EIO; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0) 7748c2ecf20Sopenharmony_ci return -EIO; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci fw_version = (r[0] << 8) | r[1]; 7778c2ecf20Sopenharmony_ci dprintk("RISC: ver: %d.%02d (IC: %d)\n", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if ((fw_version >> 10) != 7) 7808c2ecf20Sopenharmony_ci return -EINVAL; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci switch (fw_version & 0x3ff) { 7838c2ecf20Sopenharmony_ci case 11: 7848c2ecf20Sopenharmony_ci case 12: 7858c2ecf20Sopenharmony_ci case 14: 7868c2ecf20Sopenharmony_ci case 15: 7878c2ecf20Sopenharmony_ci case 16: 7888c2ecf20Sopenharmony_ci case 17: 7898c2ecf20Sopenharmony_ci break; 7908c2ecf20Sopenharmony_ci default: 7918c2ecf20Sopenharmony_ci dprintk("RISC: invalid firmware version"); 7928c2ecf20Sopenharmony_ci return -EINVAL; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci dprintk("RISC: valid firmware version"); 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci /* Reconfig pool mac ram */ 8028c2ecf20Sopenharmony_ci dib9000_write_word(state, 1225, 0x02); /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */ 8038c2ecf20Sopenharmony_ci dib9000_write_word(state, 1226, 0x05); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* Toggles IP crypto to Host APB interface. */ 8068c2ecf20Sopenharmony_ci dib9000_write_word(state, 1542, 1); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Set jump and no jump in the dma box */ 8098c2ecf20Sopenharmony_ci dib9000_write_word(state, 1074, 0); 8108c2ecf20Sopenharmony_ci dib9000_write_word(state, 1075, 0); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* Set MAC as APB Master. */ 8138c2ecf20Sopenharmony_ci dib9000_write_word(state, 1237, 0); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Reset the RISCs */ 8168c2ecf20Sopenharmony_ci if (codeA != NULL) 8178c2ecf20Sopenharmony_ci dib9000_write_word(state, 1024, 2); 8188c2ecf20Sopenharmony_ci else 8198c2ecf20Sopenharmony_ci dib9000_write_word(state, 1024, 15); 8208c2ecf20Sopenharmony_ci if (codeB != NULL) 8218c2ecf20Sopenharmony_ci dib9000_write_word(state, 1040, 2); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (codeA != NULL) 8248c2ecf20Sopenharmony_ci dib9000_firmware_download(state, 0, 0x1234, codeA, lenA); 8258c2ecf20Sopenharmony_ci if (codeB != NULL) 8268c2ecf20Sopenharmony_ci dib9000_firmware_download(state, 1, 0x1234, codeB, lenB); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* Run the RISCs */ 8298c2ecf20Sopenharmony_ci if (codeA != NULL) 8308c2ecf20Sopenharmony_ci dib9000_write_word(state, 1024, 0); 8318c2ecf20Sopenharmony_ci if (codeB != NULL) 8328c2ecf20Sopenharmony_ci dib9000_write_word(state, 1040, 0); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (codeA != NULL) 8358c2ecf20Sopenharmony_ci if (dib9000_mbx_host_init(state, 0) != 0) 8368c2ecf20Sopenharmony_ci return -EIO; 8378c2ecf20Sopenharmony_ci if (codeB != NULL) 8388c2ecf20Sopenharmony_ci if (dib9000_mbx_host_init(state, 1) != 0) 8398c2ecf20Sopenharmony_ci return -EIO; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci msleep(100); 8428c2ecf20Sopenharmony_ci state->platform.risc.fw_is_running = 1; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (dib9000_risc_check_version(state) != 0) 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci state->platform.risc.memcmd = 0xff; 8488c2ecf20Sopenharmony_ci return 0; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic u16 dib9000_identify(struct i2c_device *client) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci u16 value; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci value = dib9000_i2c_read16(client, 896); 8568c2ecf20Sopenharmony_ci if (value != 0x01b3) { 8578c2ecf20Sopenharmony_ci dprintk("wrong Vendor ID (0x%x)\n", value); 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci value = dib9000_i2c_read16(client, 897); 8628c2ecf20Sopenharmony_ci if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) { 8638c2ecf20Sopenharmony_ci dprintk("wrong Device ID (0x%x)\n", value); 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci /* protect this driver to be used with 7000PC */ 8688c2ecf20Sopenharmony_ci if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) { 8698c2ecf20Sopenharmony_ci dprintk("this driver does not work with DiB7000PC\n"); 8708c2ecf20Sopenharmony_ci return 0; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci switch (value) { 8748c2ecf20Sopenharmony_ci case 0x4000: 8758c2ecf20Sopenharmony_ci dprintk("found DiB7000MA/PA/MB/PB\n"); 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci case 0x4001: 8788c2ecf20Sopenharmony_ci dprintk("found DiB7000HC\n"); 8798c2ecf20Sopenharmony_ci break; 8808c2ecf20Sopenharmony_ci case 0x4002: 8818c2ecf20Sopenharmony_ci dprintk("found DiB7000MC\n"); 8828c2ecf20Sopenharmony_ci break; 8838c2ecf20Sopenharmony_ci case 0x4003: 8848c2ecf20Sopenharmony_ci dprintk("found DiB9000A\n"); 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci case 0x4004: 8878c2ecf20Sopenharmony_ci dprintk("found DiB9000H\n"); 8888c2ecf20Sopenharmony_ci break; 8898c2ecf20Sopenharmony_ci case 0x4005: 8908c2ecf20Sopenharmony_ci dprintk("found DiB9000M\n"); 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return value; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci /* by default everything is going to be powered off */ 9008c2ecf20Sopenharmony_ci u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906; 9018c2ecf20Sopenharmony_ci u8 offset; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005) 9048c2ecf20Sopenharmony_ci offset = 1; 9058c2ecf20Sopenharmony_ci else 9068c2ecf20Sopenharmony_ci offset = 0; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */ 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* now, depending on the requested mode, we power on */ 9118c2ecf20Sopenharmony_ci switch (mode) { 9128c2ecf20Sopenharmony_ci /* power up everything in the demod */ 9138c2ecf20Sopenharmony_ci case DIB9000_POWER_ALL: 9148c2ecf20Sopenharmony_ci reg_903 = 0x0000; 9158c2ecf20Sopenharmony_ci reg_904 = 0x0000; 9168c2ecf20Sopenharmony_ci reg_905 = 0x0000; 9178c2ecf20Sopenharmony_ci reg_906 = 0x0000; 9188c2ecf20Sopenharmony_ci break; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ 9218c2ecf20Sopenharmony_ci case DIB9000_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ 9228c2ecf20Sopenharmony_ci reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); 9238c2ecf20Sopenharmony_ci break; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci case DIB9000_POWER_INTERF_ANALOG_AGC: 9268c2ecf20Sopenharmony_ci reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); 9278c2ecf20Sopenharmony_ci reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); 9288c2ecf20Sopenharmony_ci reg_906 &= ~((1 << 0)); 9298c2ecf20Sopenharmony_ci break; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: 9328c2ecf20Sopenharmony_ci reg_903 = 0x0000; 9338c2ecf20Sopenharmony_ci reg_904 = 0x801f; 9348c2ecf20Sopenharmony_ci reg_905 = 0x0000; 9358c2ecf20Sopenharmony_ci reg_906 &= ~((1 << 0)); 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD: 9398c2ecf20Sopenharmony_ci reg_903 = 0x0000; 9408c2ecf20Sopenharmony_ci reg_904 = 0x8000; 9418c2ecf20Sopenharmony_ci reg_905 = 0x010b; 9428c2ecf20Sopenharmony_ci reg_906 &= ~((1 << 0)); 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci default: 9458c2ecf20Sopenharmony_ci case DIB9000_POWER_NO: 9468c2ecf20Sopenharmony_ci break; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* always power down unused parts */ 9508c2ecf20Sopenharmony_ci if (!state->platform.host.mobile_mode) 9518c2ecf20Sopenharmony_ci reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* P_sdio_select_clk = 0 on MC and after */ 9548c2ecf20Sopenharmony_ci if (state->revision != 0x4000) 9558c2ecf20Sopenharmony_ci reg_906 <<= 1; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci dib9000_write_word(state, 903 + offset, reg_903); 9588c2ecf20Sopenharmony_ci dib9000_write_word(state, 904 + offset, reg_904); 9598c2ecf20Sopenharmony_ci dib9000_write_word(state, 905 + offset, reg_905); 9608c2ecf20Sopenharmony_ci dib9000_write_word(state, 906 + offset, reg_906); 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int dib9000_fw_reset(struct dvb_frontend *fe) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci dib9000_write_word(state, 1817, 0x0003); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci dib9000_write_word(state, 1227, 1); 9708c2ecf20Sopenharmony_ci dib9000_write_word(state, 1227, 0); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci switch ((state->revision = dib9000_identify(&state->i2c))) { 9738c2ecf20Sopenharmony_ci case 0x4003: 9748c2ecf20Sopenharmony_ci case 0x4004: 9758c2ecf20Sopenharmony_ci case 0x4005: 9768c2ecf20Sopenharmony_ci state->reg_offs = 1; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci default: 9798c2ecf20Sopenharmony_ci return -EINVAL; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* reset the i2c-master to use the host interface */ 9838c2ecf20Sopenharmony_ci dibx000_reset_i2c_master(&state->i2c_master); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci dib9000_set_power_mode(state, DIB9000_POWER_ALL); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* unforce divstr regardless whether i2c enumeration was done or not */ 9888c2ecf20Sopenharmony_ci dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1)); 9898c2ecf20Sopenharmony_ci dib9000_write_word(state, 1796, 0); 9908c2ecf20Sopenharmony_ci dib9000_write_word(state, 1805, 0x805); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* restart all parts */ 9938c2ecf20Sopenharmony_ci dib9000_write_word(state, 898, 0xffff); 9948c2ecf20Sopenharmony_ci dib9000_write_word(state, 899, 0xffff); 9958c2ecf20Sopenharmony_ci dib9000_write_word(state, 900, 0x0001); 9968c2ecf20Sopenharmony_ci dib9000_write_word(state, 901, 0xff19); 9978c2ecf20Sopenharmony_ci dib9000_write_word(state, 902, 0x003c); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci dib9000_write_word(state, 898, 0); 10008c2ecf20Sopenharmony_ci dib9000_write_word(state, 899, 0); 10018c2ecf20Sopenharmony_ci dib9000_write_word(state, 900, 0); 10028c2ecf20Sopenharmony_ci dib9000_write_word(state, 901, 0); 10038c2ecf20Sopenharmony_ci dib9000_write_word(state, 902, 0); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci u16 mb[10]; 10158c2ecf20Sopenharmony_ci u8 i, s; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (address >= 1024 || !state->platform.risc.fw_is_running) 10188c2ecf20Sopenharmony_ci return -EINVAL; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* dprintk( "APB access through rd fw %d %x\n", address, attribute); */ 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci mb[0] = (u16) address; 10238c2ecf20Sopenharmony_ci mb[1] = len / 2; 10248c2ecf20Sopenharmony_ci dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute); 10258c2ecf20Sopenharmony_ci switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) { 10268c2ecf20Sopenharmony_ci case 1: 10278c2ecf20Sopenharmony_ci s--; 10288c2ecf20Sopenharmony_ci for (i = 0; i < s; i++) { 10298c2ecf20Sopenharmony_ci b[i * 2] = (mb[i + 1] >> 8) & 0xff; 10308c2ecf20Sopenharmony_ci b[i * 2 + 1] = (mb[i + 1]) & 0xff; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci default: 10348c2ecf20Sopenharmony_ci return -EIO; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci return -EIO; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci u16 mb[10]; 10428c2ecf20Sopenharmony_ci u8 s, i; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (address >= 1024 || !state->platform.risc.fw_is_running) 10458c2ecf20Sopenharmony_ci return -EINVAL; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (len > 18) 10488c2ecf20Sopenharmony_ci return -EINVAL; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* dprintk( "APB access through wr fw %d %x\n", address, attribute); */ 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci mb[0] = (u16)address; 10538c2ecf20Sopenharmony_ci for (i = 0; i + 1 < len; i += 2) 10548c2ecf20Sopenharmony_ci mb[1 + i / 2] = b[i] << 8 | b[i + 1]; 10558c2ecf20Sopenharmony_ci if (len & 1) 10568c2ecf20Sopenharmony_ci mb[1 + len / 2] = b[len - 1] << 8; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, (3 + len) / 2, attribute); 10598c2ecf20Sopenharmony_ci return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci u8 index_loop = 10; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (!state->platform.risc.fw_is_running) 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i); 10698c2ecf20Sopenharmony_ci do { 10708c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1); 10718c2ecf20Sopenharmony_ci } while (state->i2c_read_buffer[0] && index_loop--); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (index_loop > 0) 10748c2ecf20Sopenharmony_ci return 0; 10758c2ecf20Sopenharmony_ci return -EIO; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic int dib9000_fw_init(struct dib9000_state *state) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci struct dibGPIOFunction *f; 10818c2ecf20Sopenharmony_ci u16 b[40] = { 0 }; 10828c2ecf20Sopenharmony_ci u8 i; 10838c2ecf20Sopenharmony_ci u8 size; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0) 10868c2ecf20Sopenharmony_ci return -EIO; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* initialize the firmware */ 10898c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) { 10908c2ecf20Sopenharmony_ci f = &state->chip.d9.cfg.gpio_function[i]; 10918c2ecf20Sopenharmony_ci if (f->mask) { 10928c2ecf20Sopenharmony_ci switch (f->function) { 10938c2ecf20Sopenharmony_ci case BOARD_GPIO_FUNCTION_COMPONENT_ON: 10948c2ecf20Sopenharmony_ci b[0] = (u16) f->mask; 10958c2ecf20Sopenharmony_ci b[1] = (u16) f->direction; 10968c2ecf20Sopenharmony_ci b[2] = (u16) f->value; 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci case BOARD_GPIO_FUNCTION_COMPONENT_OFF: 10998c2ecf20Sopenharmony_ci b[3] = (u16) f->mask; 11008c2ecf20Sopenharmony_ci b[4] = (u16) f->direction; 11018c2ecf20Sopenharmony_ci b[5] = (u16) f->value; 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0) 11078c2ecf20Sopenharmony_ci return -EIO; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* subband */ 11108c2ecf20Sopenharmony_ci b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */ 11118c2ecf20Sopenharmony_ci for (i = 0; i < state->chip.d9.cfg.subband.size; i++) { 11128c2ecf20Sopenharmony_ci b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz; 11138c2ecf20Sopenharmony_ci b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask; 11148c2ecf20Sopenharmony_ci b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction; 11158c2ecf20Sopenharmony_ci b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci b[1 + i * 4] = 0; /* fe_id */ 11188c2ecf20Sopenharmony_ci if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0) 11198c2ecf20Sopenharmony_ci return -EIO; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* 0 - id, 1 - no_of_frontends */ 11228c2ecf20Sopenharmony_ci b[0] = (0 << 8) | 1; 11238c2ecf20Sopenharmony_ci /* 0 = i2c-address demod, 0 = tuner */ 11248c2ecf20Sopenharmony_ci b[1] = (0 << 8) | (0); 11258c2ecf20Sopenharmony_ci b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff); 11268c2ecf20Sopenharmony_ci b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff); 11278c2ecf20Sopenharmony_ci b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff); 11288c2ecf20Sopenharmony_ci b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff); 11298c2ecf20Sopenharmony_ci b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff); 11308c2ecf20Sopenharmony_ci b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff); 11318c2ecf20Sopenharmony_ci b[29] = state->chip.d9.cfg.if_drives; 11328c2ecf20Sopenharmony_ci if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0) 11338c2ecf20Sopenharmony_ci return -EIO; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0) 11368c2ecf20Sopenharmony_ci return -EIO; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0) 11398c2ecf20Sopenharmony_ci return -EIO; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (size > ARRAY_SIZE(b)) { 11428c2ecf20Sopenharmony_ci dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size, 11438c2ecf20Sopenharmony_ci (int)ARRAY_SIZE(b)); 11448c2ecf20Sopenharmony_ci return -EINVAL; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci for (i = 0; i < size; i += 2) { 11488c2ecf20Sopenharmony_ci state->platform.risc.fe_mm[i / 2].addr = b[i + 0]; 11498c2ecf20Sopenharmony_ci state->platform.risc.fe_mm[i / 2].size = b[i + 1]; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci return 0; 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic void dib9000_fw_set_channel_head(struct dib9000_state *state) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci u8 b[9]; 11588c2ecf20Sopenharmony_ci u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000; 11598c2ecf20Sopenharmony_ci if (state->fe_id % 2) 11608c2ecf20Sopenharmony_ci freq += 101; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci b[0] = (u8) ((freq >> 0) & 0xff); 11638c2ecf20Sopenharmony_ci b[1] = (u8) ((freq >> 8) & 0xff); 11648c2ecf20Sopenharmony_ci b[2] = (u8) ((freq >> 16) & 0xff); 11658c2ecf20Sopenharmony_ci b[3] = (u8) ((freq >> 24) & 0xff); 11668c2ecf20Sopenharmony_ci b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff); 11678c2ecf20Sopenharmony_ci b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff); 11688c2ecf20Sopenharmony_ci b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff); 11698c2ecf20Sopenharmony_ci b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff); 11708c2ecf20Sopenharmony_ci b[8] = 0x80; /* do not wait for CELL ID when doing autosearch */ 11718c2ecf20Sopenharmony_ci if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT) 11728c2ecf20Sopenharmony_ci b[8] |= 1; 11738c2ecf20Sopenharmony_ci dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b); 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic int dib9000_fw_get_channel(struct dvb_frontend *fe) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 11798c2ecf20Sopenharmony_ci struct dibDVBTChannel { 11808c2ecf20Sopenharmony_ci s8 spectrum_inversion; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci s8 nfft; 11838c2ecf20Sopenharmony_ci s8 guard; 11848c2ecf20Sopenharmony_ci s8 constellation; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci s8 hrch; 11878c2ecf20Sopenharmony_ci s8 alpha; 11888c2ecf20Sopenharmony_ci s8 code_rate_hp; 11898c2ecf20Sopenharmony_ci s8 code_rate_lp; 11908c2ecf20Sopenharmony_ci s8 select_hp; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci s8 intlv_native; 11938c2ecf20Sopenharmony_ci }; 11948c2ecf20Sopenharmony_ci struct dibDVBTChannel *ch; 11958c2ecf20Sopenharmony_ci int ret = 0; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 11988c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 11998c2ecf20Sopenharmony_ci return -EINTR; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 12028c2ecf20Sopenharmony_ci ret = -EIO; 12038c2ecf20Sopenharmony_ci goto error; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, 12078c2ecf20Sopenharmony_ci state->i2c_read_buffer, sizeof(struct dibDVBTChannel)); 12088c2ecf20Sopenharmony_ci ch = (struct dibDVBTChannel *)state->i2c_read_buffer; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci switch (ch->spectrum_inversion & 0x7) { 12128c2ecf20Sopenharmony_ci case 1: 12138c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.inversion = INVERSION_ON; 12148c2ecf20Sopenharmony_ci break; 12158c2ecf20Sopenharmony_ci case 0: 12168c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF; 12178c2ecf20Sopenharmony_ci break; 12188c2ecf20Sopenharmony_ci default: 12198c2ecf20Sopenharmony_ci case -1: 12208c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO; 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci switch (ch->nfft) { 12248c2ecf20Sopenharmony_ci case 0: 12258c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; 12268c2ecf20Sopenharmony_ci break; 12278c2ecf20Sopenharmony_ci case 2: 12288c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K; 12298c2ecf20Sopenharmony_ci break; 12308c2ecf20Sopenharmony_ci case 1: 12318c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; 12328c2ecf20Sopenharmony_ci break; 12338c2ecf20Sopenharmony_ci default: 12348c2ecf20Sopenharmony_ci case -1: 12358c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; 12368c2ecf20Sopenharmony_ci break; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci switch (ch->guard) { 12398c2ecf20Sopenharmony_ci case 0: 12408c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; 12418c2ecf20Sopenharmony_ci break; 12428c2ecf20Sopenharmony_ci case 1: 12438c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; 12448c2ecf20Sopenharmony_ci break; 12458c2ecf20Sopenharmony_ci case 2: 12468c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; 12478c2ecf20Sopenharmony_ci break; 12488c2ecf20Sopenharmony_ci case 3: 12498c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci default: 12528c2ecf20Sopenharmony_ci case -1: 12538c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; 12548c2ecf20Sopenharmony_ci break; 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci switch (ch->constellation) { 12578c2ecf20Sopenharmony_ci case 2: 12588c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.modulation = QAM_64; 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci case 1: 12618c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.modulation = QAM_16; 12628c2ecf20Sopenharmony_ci break; 12638c2ecf20Sopenharmony_ci case 0: 12648c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.modulation = QPSK; 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci default: 12678c2ecf20Sopenharmony_ci case -1: 12688c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.modulation = QAM_AUTO; 12698c2ecf20Sopenharmony_ci break; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci switch (ch->hrch) { 12728c2ecf20Sopenharmony_ci case 0: 12738c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE; 12748c2ecf20Sopenharmony_ci break; 12758c2ecf20Sopenharmony_ci case 1: 12768c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1; 12778c2ecf20Sopenharmony_ci break; 12788c2ecf20Sopenharmony_ci default: 12798c2ecf20Sopenharmony_ci case -1: 12808c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO; 12818c2ecf20Sopenharmony_ci break; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci switch (ch->code_rate_hp) { 12848c2ecf20Sopenharmony_ci case 1: 12858c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2; 12868c2ecf20Sopenharmony_ci break; 12878c2ecf20Sopenharmony_ci case 2: 12888c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3; 12898c2ecf20Sopenharmony_ci break; 12908c2ecf20Sopenharmony_ci case 3: 12918c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4; 12928c2ecf20Sopenharmony_ci break; 12938c2ecf20Sopenharmony_ci case 5: 12948c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6; 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci case 7: 12978c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8; 12988c2ecf20Sopenharmony_ci break; 12998c2ecf20Sopenharmony_ci default: 13008c2ecf20Sopenharmony_ci case -1: 13018c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO; 13028c2ecf20Sopenharmony_ci break; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci switch (ch->code_rate_lp) { 13058c2ecf20Sopenharmony_ci case 1: 13068c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2; 13078c2ecf20Sopenharmony_ci break; 13088c2ecf20Sopenharmony_ci case 2: 13098c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3; 13108c2ecf20Sopenharmony_ci break; 13118c2ecf20Sopenharmony_ci case 3: 13128c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4; 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci case 5: 13158c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6; 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci case 7: 13188c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8; 13198c2ecf20Sopenharmony_ci break; 13208c2ecf20Sopenharmony_ci default: 13218c2ecf20Sopenharmony_ci case -1: 13228c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO; 13238c2ecf20Sopenharmony_ci break; 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cierror: 13278c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 13288c2ecf20Sopenharmony_ci return ret; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic int dib9000_fw_set_channel_union(struct dvb_frontend *fe) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 13348c2ecf20Sopenharmony_ci struct dibDVBTChannel { 13358c2ecf20Sopenharmony_ci s8 spectrum_inversion; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci s8 nfft; 13388c2ecf20Sopenharmony_ci s8 guard; 13398c2ecf20Sopenharmony_ci s8 constellation; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci s8 hrch; 13428c2ecf20Sopenharmony_ci s8 alpha; 13438c2ecf20Sopenharmony_ci s8 code_rate_hp; 13448c2ecf20Sopenharmony_ci s8 code_rate_lp; 13458c2ecf20Sopenharmony_ci s8 select_hp; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci s8 intlv_native; 13488c2ecf20Sopenharmony_ci }; 13498c2ecf20Sopenharmony_ci struct dibDVBTChannel ch; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci switch (state->fe[0]->dtv_property_cache.inversion) { 13528c2ecf20Sopenharmony_ci case INVERSION_ON: 13538c2ecf20Sopenharmony_ci ch.spectrum_inversion = 1; 13548c2ecf20Sopenharmony_ci break; 13558c2ecf20Sopenharmony_ci case INVERSION_OFF: 13568c2ecf20Sopenharmony_ci ch.spectrum_inversion = 0; 13578c2ecf20Sopenharmony_ci break; 13588c2ecf20Sopenharmony_ci default: 13598c2ecf20Sopenharmony_ci case INVERSION_AUTO: 13608c2ecf20Sopenharmony_ci ch.spectrum_inversion = -1; 13618c2ecf20Sopenharmony_ci break; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci switch (state->fe[0]->dtv_property_cache.transmission_mode) { 13648c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_2K: 13658c2ecf20Sopenharmony_ci ch.nfft = 0; 13668c2ecf20Sopenharmony_ci break; 13678c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_4K: 13688c2ecf20Sopenharmony_ci ch.nfft = 2; 13698c2ecf20Sopenharmony_ci break; 13708c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_8K: 13718c2ecf20Sopenharmony_ci ch.nfft = 1; 13728c2ecf20Sopenharmony_ci break; 13738c2ecf20Sopenharmony_ci default: 13748c2ecf20Sopenharmony_ci case TRANSMISSION_MODE_AUTO: 13758c2ecf20Sopenharmony_ci ch.nfft = 1; 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci switch (state->fe[0]->dtv_property_cache.guard_interval) { 13798c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_32: 13808c2ecf20Sopenharmony_ci ch.guard = 0; 13818c2ecf20Sopenharmony_ci break; 13828c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_16: 13838c2ecf20Sopenharmony_ci ch.guard = 1; 13848c2ecf20Sopenharmony_ci break; 13858c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_8: 13868c2ecf20Sopenharmony_ci ch.guard = 2; 13878c2ecf20Sopenharmony_ci break; 13888c2ecf20Sopenharmony_ci case GUARD_INTERVAL_1_4: 13898c2ecf20Sopenharmony_ci ch.guard = 3; 13908c2ecf20Sopenharmony_ci break; 13918c2ecf20Sopenharmony_ci default: 13928c2ecf20Sopenharmony_ci case GUARD_INTERVAL_AUTO: 13938c2ecf20Sopenharmony_ci ch.guard = -1; 13948c2ecf20Sopenharmony_ci break; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci switch (state->fe[0]->dtv_property_cache.modulation) { 13978c2ecf20Sopenharmony_ci case QAM_64: 13988c2ecf20Sopenharmony_ci ch.constellation = 2; 13998c2ecf20Sopenharmony_ci break; 14008c2ecf20Sopenharmony_ci case QAM_16: 14018c2ecf20Sopenharmony_ci ch.constellation = 1; 14028c2ecf20Sopenharmony_ci break; 14038c2ecf20Sopenharmony_ci case QPSK: 14048c2ecf20Sopenharmony_ci ch.constellation = 0; 14058c2ecf20Sopenharmony_ci break; 14068c2ecf20Sopenharmony_ci default: 14078c2ecf20Sopenharmony_ci case QAM_AUTO: 14088c2ecf20Sopenharmony_ci ch.constellation = -1; 14098c2ecf20Sopenharmony_ci break; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci switch (state->fe[0]->dtv_property_cache.hierarchy) { 14128c2ecf20Sopenharmony_ci case HIERARCHY_NONE: 14138c2ecf20Sopenharmony_ci ch.hrch = 0; 14148c2ecf20Sopenharmony_ci break; 14158c2ecf20Sopenharmony_ci case HIERARCHY_1: 14168c2ecf20Sopenharmony_ci case HIERARCHY_2: 14178c2ecf20Sopenharmony_ci case HIERARCHY_4: 14188c2ecf20Sopenharmony_ci ch.hrch = 1; 14198c2ecf20Sopenharmony_ci break; 14208c2ecf20Sopenharmony_ci default: 14218c2ecf20Sopenharmony_ci case HIERARCHY_AUTO: 14228c2ecf20Sopenharmony_ci ch.hrch = -1; 14238c2ecf20Sopenharmony_ci break; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci ch.alpha = 1; 14268c2ecf20Sopenharmony_ci switch (state->fe[0]->dtv_property_cache.code_rate_HP) { 14278c2ecf20Sopenharmony_ci case FEC_1_2: 14288c2ecf20Sopenharmony_ci ch.code_rate_hp = 1; 14298c2ecf20Sopenharmony_ci break; 14308c2ecf20Sopenharmony_ci case FEC_2_3: 14318c2ecf20Sopenharmony_ci ch.code_rate_hp = 2; 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci case FEC_3_4: 14348c2ecf20Sopenharmony_ci ch.code_rate_hp = 3; 14358c2ecf20Sopenharmony_ci break; 14368c2ecf20Sopenharmony_ci case FEC_5_6: 14378c2ecf20Sopenharmony_ci ch.code_rate_hp = 5; 14388c2ecf20Sopenharmony_ci break; 14398c2ecf20Sopenharmony_ci case FEC_7_8: 14408c2ecf20Sopenharmony_ci ch.code_rate_hp = 7; 14418c2ecf20Sopenharmony_ci break; 14428c2ecf20Sopenharmony_ci default: 14438c2ecf20Sopenharmony_ci case FEC_AUTO: 14448c2ecf20Sopenharmony_ci ch.code_rate_hp = -1; 14458c2ecf20Sopenharmony_ci break; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci switch (state->fe[0]->dtv_property_cache.code_rate_LP) { 14488c2ecf20Sopenharmony_ci case FEC_1_2: 14498c2ecf20Sopenharmony_ci ch.code_rate_lp = 1; 14508c2ecf20Sopenharmony_ci break; 14518c2ecf20Sopenharmony_ci case FEC_2_3: 14528c2ecf20Sopenharmony_ci ch.code_rate_lp = 2; 14538c2ecf20Sopenharmony_ci break; 14548c2ecf20Sopenharmony_ci case FEC_3_4: 14558c2ecf20Sopenharmony_ci ch.code_rate_lp = 3; 14568c2ecf20Sopenharmony_ci break; 14578c2ecf20Sopenharmony_ci case FEC_5_6: 14588c2ecf20Sopenharmony_ci ch.code_rate_lp = 5; 14598c2ecf20Sopenharmony_ci break; 14608c2ecf20Sopenharmony_ci case FEC_7_8: 14618c2ecf20Sopenharmony_ci ch.code_rate_lp = 7; 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci default: 14648c2ecf20Sopenharmony_ci case FEC_AUTO: 14658c2ecf20Sopenharmony_ci ch.code_rate_lp = -1; 14668c2ecf20Sopenharmony_ci break; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci ch.select_hp = 1; 14698c2ecf20Sopenharmony_ci ch.intlv_native = 1; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci return 0; 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic int dib9000_fw_tune(struct dvb_frontend *fe) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 14798c2ecf20Sopenharmony_ci int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN; 14808c2ecf20Sopenharmony_ci s8 i; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci switch (state->tune_state) { 14838c2ecf20Sopenharmony_ci case CT_DEMOD_START: 14848c2ecf20Sopenharmony_ci dib9000_fw_set_channel_head(state); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* write the channel context - a channel is initialized to 0, so it is OK */ 14878c2ecf20Sopenharmony_ci dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info); 14888c2ecf20Sopenharmony_ci dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (search) 14918c2ecf20Sopenharmony_ci dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0); 14928c2ecf20Sopenharmony_ci else { 14938c2ecf20Sopenharmony_ci dib9000_fw_set_channel_union(fe); 14948c2ecf20Sopenharmony_ci dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0); 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci state->tune_state = CT_DEMOD_STEP_1; 14978c2ecf20Sopenharmony_ci break; 14988c2ecf20Sopenharmony_ci case CT_DEMOD_STEP_1: 14998c2ecf20Sopenharmony_ci if (search) 15008c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1); 15018c2ecf20Sopenharmony_ci else 15028c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1); 15038c2ecf20Sopenharmony_ci i = (s8)state->i2c_read_buffer[0]; 15048c2ecf20Sopenharmony_ci switch (i) { /* something happened */ 15058c2ecf20Sopenharmony_ci case 0: 15068c2ecf20Sopenharmony_ci break; 15078c2ecf20Sopenharmony_ci case -2: /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */ 15088c2ecf20Sopenharmony_ci if (search) 15098c2ecf20Sopenharmony_ci state->status = FE_STATUS_DEMOD_SUCCESS; 15108c2ecf20Sopenharmony_ci else { 15118c2ecf20Sopenharmony_ci state->tune_state = CT_DEMOD_STOP; 15128c2ecf20Sopenharmony_ci state->status = FE_STATUS_LOCKED; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci break; 15158c2ecf20Sopenharmony_ci default: 15168c2ecf20Sopenharmony_ci state->status = FE_STATUS_TUNE_FAILED; 15178c2ecf20Sopenharmony_ci state->tune_state = CT_DEMOD_STOP; 15188c2ecf20Sopenharmony_ci break; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci break; 15218c2ecf20Sopenharmony_ci default: 15228c2ecf20Sopenharmony_ci ret = FE_CALLBACK_TIME_NEVER; 15238c2ecf20Sopenharmony_ci break; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci return ret; 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 15328c2ecf20Sopenharmony_ci u16 mode = (u16) onoff; 15338c2ecf20Sopenharmony_ci return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1); 15348c2ecf20Sopenharmony_ci} 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_cistatic int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 15398c2ecf20Sopenharmony_ci u16 outreg, smo_mode; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci dprintk("setting output mode for demod %p to %d\n", fe, mode); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci switch (mode) { 15448c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_GATED_CLK: 15458c2ecf20Sopenharmony_ci outreg = (1 << 10); /* 0x0400 */ 15468c2ecf20Sopenharmony_ci break; 15478c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_CONT_CLK: 15488c2ecf20Sopenharmony_ci outreg = (1 << 10) | (1 << 6); /* 0x0440 */ 15498c2ecf20Sopenharmony_ci break; 15508c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_SERIAL: 15518c2ecf20Sopenharmony_ci outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ 15528c2ecf20Sopenharmony_ci break; 15538c2ecf20Sopenharmony_ci case OUTMODE_DIVERSITY: 15548c2ecf20Sopenharmony_ci outreg = (1 << 10) | (4 << 6); /* 0x0500 */ 15558c2ecf20Sopenharmony_ci break; 15568c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_FIFO: 15578c2ecf20Sopenharmony_ci outreg = (1 << 10) | (5 << 6); 15588c2ecf20Sopenharmony_ci break; 15598c2ecf20Sopenharmony_ci case OUTMODE_HIGH_Z: 15608c2ecf20Sopenharmony_ci outreg = 0; 15618c2ecf20Sopenharmony_ci break; 15628c2ecf20Sopenharmony_ci default: 15638c2ecf20Sopenharmony_ci dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->fe[0]); 15648c2ecf20Sopenharmony_ci return -EINVAL; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci dib9000_write_word(state, 1795, outreg); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci switch (mode) { 15708c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_GATED_CLK: 15718c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_PAR_CONT_CLK: 15728c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_SERIAL: 15738c2ecf20Sopenharmony_ci case OUTMODE_MPEG2_FIFO: 15748c2ecf20Sopenharmony_ci smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1); 15758c2ecf20Sopenharmony_ci if (state->chip.d9.cfg.output_mpeg2_in_188_bytes) 15768c2ecf20Sopenharmony_ci smo_mode |= (1 << 5); 15778c2ecf20Sopenharmony_ci dib9000_write_word(state, 295, smo_mode); 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci outreg = to_fw_output_mode(mode); 15828c2ecf20Sopenharmony_ci return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1); 15838c2ecf20Sopenharmony_ci} 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_cistatic int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 15868c2ecf20Sopenharmony_ci{ 15878c2ecf20Sopenharmony_ci struct dib9000_state *state = i2c_get_adapdata(i2c_adap); 15888c2ecf20Sopenharmony_ci u16 i, len, t, index_msg; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci for (index_msg = 0; index_msg < num; index_msg++) { 15918c2ecf20Sopenharmony_ci if (msg[index_msg].flags & I2C_M_RD) { /* read */ 15928c2ecf20Sopenharmony_ci len = msg[index_msg].len; 15938c2ecf20Sopenharmony_ci if (len > 16) 15948c2ecf20Sopenharmony_ci len = 16; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (dib9000_read_word(state, 790) != 0) 15978c2ecf20Sopenharmony_ci dprintk("TunerITF: read busy\n"); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci dib9000_write_word(state, 784, (u16) (msg[index_msg].addr)); 16008c2ecf20Sopenharmony_ci dib9000_write_word(state, 787, (len / 2) - 1); 16018c2ecf20Sopenharmony_ci dib9000_write_word(state, 786, 1); /* start read */ 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci i = 1000; 16048c2ecf20Sopenharmony_ci while (dib9000_read_word(state, 790) != (len / 2) && i) 16058c2ecf20Sopenharmony_ci i--; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (i == 0) 16088c2ecf20Sopenharmony_ci dprintk("TunerITF: read failed\n"); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci for (i = 0; i < len; i += 2) { 16118c2ecf20Sopenharmony_ci t = dib9000_read_word(state, 785); 16128c2ecf20Sopenharmony_ci msg[index_msg].buf[i] = (t >> 8) & 0xff; 16138c2ecf20Sopenharmony_ci msg[index_msg].buf[i + 1] = (t) & 0xff; 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci if (dib9000_read_word(state, 790) != 0) 16168c2ecf20Sopenharmony_ci dprintk("TunerITF: read more data than expected\n"); 16178c2ecf20Sopenharmony_ci } else { 16188c2ecf20Sopenharmony_ci i = 1000; 16198c2ecf20Sopenharmony_ci while (dib9000_read_word(state, 789) && i) 16208c2ecf20Sopenharmony_ci i--; 16218c2ecf20Sopenharmony_ci if (i == 0) 16228c2ecf20Sopenharmony_ci dprintk("TunerITF: write busy\n"); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci len = msg[index_msg].len; 16258c2ecf20Sopenharmony_ci if (len > 16) 16268c2ecf20Sopenharmony_ci len = 16; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci for (i = 0; i < len; i += 2) 16298c2ecf20Sopenharmony_ci dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]); 16308c2ecf20Sopenharmony_ci dib9000_write_word(state, 784, (u16) msg[index_msg].addr); 16318c2ecf20Sopenharmony_ci dib9000_write_word(state, 787, (len / 2) - 1); 16328c2ecf20Sopenharmony_ci dib9000_write_word(state, 786, 0); /* start write */ 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci i = 1000; 16358c2ecf20Sopenharmony_ci while (dib9000_read_word(state, 791) > 0 && i) 16368c2ecf20Sopenharmony_ci i--; 16378c2ecf20Sopenharmony_ci if (i == 0) 16388c2ecf20Sopenharmony_ci dprintk("TunerITF: write failed\n"); 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci return num; 16428c2ecf20Sopenharmony_ci} 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ciint dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) 16458c2ecf20Sopenharmony_ci{ 16468c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci state->component_bus_speed = speed; 16498c2ecf20Sopenharmony_ci return 0; 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_fw_set_component_bus_speed); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_cistatic int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci struct dib9000_state *state = i2c_get_adapdata(i2c_adap); 16568c2ecf20Sopenharmony_ci u8 type = 0; /* I2C */ 16578c2ecf20Sopenharmony_ci u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4; 16588c2ecf20Sopenharmony_ci u16 scl = state->component_bus_speed; /* SCL frequency */ 16598c2ecf20Sopenharmony_ci struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER]; 16608c2ecf20Sopenharmony_ci u8 p[13] = { 0 }; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci p[0] = type; 16638c2ecf20Sopenharmony_ci p[1] = port; 16648c2ecf20Sopenharmony_ci p[2] = msg[0].addr << 1; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci p[3] = (u8) scl & 0xff; /* scl */ 16678c2ecf20Sopenharmony_ci p[4] = (u8) (scl >> 8); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci p[7] = 0; 16708c2ecf20Sopenharmony_ci p[8] = 0; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci p[9] = (u8) (msg[0].len); 16738c2ecf20Sopenharmony_ci p[10] = (u8) (msg[0].len >> 8); 16748c2ecf20Sopenharmony_ci if ((num > 1) && (msg[1].flags & I2C_M_RD)) { 16758c2ecf20Sopenharmony_ci p[11] = (u8) (msg[1].len); 16768c2ecf20Sopenharmony_ci p[12] = (u8) (msg[1].len >> 8); 16778c2ecf20Sopenharmony_ci } else { 16788c2ecf20Sopenharmony_ci p[11] = 0; 16798c2ecf20Sopenharmony_ci p[12] = 0; 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 16838c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 16848c2ecf20Sopenharmony_ci return 0; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci { /* write-part */ 16908c2ecf20Sopenharmony_ci dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0); 16918c2ecf20Sopenharmony_ci dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len); 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci /* do the transaction */ 16958c2ecf20Sopenharmony_ci if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) { 16968c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 16978c2ecf20Sopenharmony_ci return 0; 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci /* read back any possible result */ 17018c2ecf20Sopenharmony_ci if ((num > 1) && (msg[1].flags & I2C_M_RD)) 17028c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci return num; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_cistatic u32 dib9000_i2c_func(struct i2c_adapter *adapter) 17108c2ecf20Sopenharmony_ci{ 17118c2ecf20Sopenharmony_ci return I2C_FUNC_I2C; 17128c2ecf20Sopenharmony_ci} 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_cistatic const struct i2c_algorithm dib9000_tuner_algo = { 17158c2ecf20Sopenharmony_ci .master_xfer = dib9000_tuner_xfer, 17168c2ecf20Sopenharmony_ci .functionality = dib9000_i2c_func, 17178c2ecf20Sopenharmony_ci}; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cistatic const struct i2c_algorithm dib9000_component_bus_algo = { 17208c2ecf20Sopenharmony_ci .master_xfer = dib9000_fw_component_bus_xfer, 17218c2ecf20Sopenharmony_ci .functionality = dib9000_i2c_func, 17228c2ecf20Sopenharmony_ci}; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_cistruct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) 17258c2ecf20Sopenharmony_ci{ 17268c2ecf20Sopenharmony_ci struct dib9000_state *st = fe->demodulator_priv; 17278c2ecf20Sopenharmony_ci return &st->tuner_adap; 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_get_tuner_interface); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_cistruct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci struct dib9000_state *st = fe->demodulator_priv; 17348c2ecf20Sopenharmony_ci return &st->component_bus; 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_get_component_bus_interface); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistruct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci struct dib9000_state *st = fe->demodulator_priv; 17418c2ecf20Sopenharmony_ci return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_get_i2c_master); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ciint dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci struct dib9000_state *st = fe->demodulator_priv; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci st->i2c.i2c_adap = i2c; 17508c2ecf20Sopenharmony_ci return 0; 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_set_i2c_adapter); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci st->gpio_dir = dib9000_read_word(st, 773); 17578c2ecf20Sopenharmony_ci st->gpio_dir &= ~(1 << num); /* reset the direction bit */ 17588c2ecf20Sopenharmony_ci st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ 17598c2ecf20Sopenharmony_ci dib9000_write_word(st, 773, st->gpio_dir); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci st->gpio_val = dib9000_read_word(st, 774); 17628c2ecf20Sopenharmony_ci st->gpio_val &= ~(1 << num); /* reset the direction bit */ 17638c2ecf20Sopenharmony_ci st->gpio_val |= (val & 0x01) << num; /* set the new value */ 17648c2ecf20Sopenharmony_ci dib9000_write_word(st, 774, st->gpio_val); 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci dprintk("gpio dir: %04x: gpio val: %04x\n", st->gpio_dir, st->gpio_val); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci return 0; 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ciint dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 17748c2ecf20Sopenharmony_ci return dib9000_cfg_gpio(state, num, dir, val); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_set_gpio); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ciint dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 17818c2ecf20Sopenharmony_ci u16 val; 17828c2ecf20Sopenharmony_ci int ret; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) { 17858c2ecf20Sopenharmony_ci /* postpone the pid filtering cmd */ 17868c2ecf20Sopenharmony_ci dprintk("pid filter cmd postpone\n"); 17878c2ecf20Sopenharmony_ci state->pid_ctrl_index++; 17888c2ecf20Sopenharmony_ci state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL; 17898c2ecf20Sopenharmony_ci state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; 17908c2ecf20Sopenharmony_ci return 0; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 17948c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 17958c2ecf20Sopenharmony_ci return -EINTR; 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci val = dib9000_read_word(state, 294 + 1) & 0xffef; 17998c2ecf20Sopenharmony_ci val |= (onoff & 0x1) << 4; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci dprintk("PID filter enabled %d\n", onoff); 18028c2ecf20Sopenharmony_ci ret = dib9000_write_word(state, 294 + 1, val); 18038c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 18048c2ecf20Sopenharmony_ci return ret; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ciint dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 18128c2ecf20Sopenharmony_ci int ret; 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci if (state->pid_ctrl_index != -2) { 18158c2ecf20Sopenharmony_ci /* postpone the pid filtering cmd */ 18168c2ecf20Sopenharmony_ci dprintk("pid filter postpone\n"); 18178c2ecf20Sopenharmony_ci if (state->pid_ctrl_index < 9) { 18188c2ecf20Sopenharmony_ci state->pid_ctrl_index++; 18198c2ecf20Sopenharmony_ci state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER; 18208c2ecf20Sopenharmony_ci state->pid_ctrl[state->pid_ctrl_index].id = id; 18218c2ecf20Sopenharmony_ci state->pid_ctrl[state->pid_ctrl_index].pid = pid; 18228c2ecf20Sopenharmony_ci state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; 18238c2ecf20Sopenharmony_ci } else 18248c2ecf20Sopenharmony_ci dprintk("can not add any more pid ctrl cmd\n"); 18258c2ecf20Sopenharmony_ci return 0; 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 18298c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 18308c2ecf20Sopenharmony_ci return -EINTR; 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff); 18338c2ecf20Sopenharmony_ci ret = dib9000_write_word(state, 300 + 1 + id, 18348c2ecf20Sopenharmony_ci onoff ? (1 << 13) | pid : 0); 18358c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 18368c2ecf20Sopenharmony_ci return ret; 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_fw_pid_filter); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ciint dib9000_firmware_post_pll_init(struct dvb_frontend *fe) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 18438c2ecf20Sopenharmony_ci return dib9000_fw_init(state); 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_firmware_post_pll_init); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_cistatic void dib9000_release(struct dvb_frontend *demod) 18488c2ecf20Sopenharmony_ci{ 18498c2ecf20Sopenharmony_ci struct dib9000_state *st = demod->demodulator_priv; 18508c2ecf20Sopenharmony_ci u8 index_frontend; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) 18538c2ecf20Sopenharmony_ci dvb_frontend_detach(st->fe[index_frontend]); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci dibx000_exit_i2c_master(&st->i2c_master); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci i2c_del_adapter(&st->tuner_adap); 18588c2ecf20Sopenharmony_ci i2c_del_adapter(&st->component_bus); 18598c2ecf20Sopenharmony_ci kfree(st->fe[0]); 18608c2ecf20Sopenharmony_ci kfree(st); 18618c2ecf20Sopenharmony_ci} 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_cistatic int dib9000_wakeup(struct dvb_frontend *fe) 18648c2ecf20Sopenharmony_ci{ 18658c2ecf20Sopenharmony_ci return 0; 18668c2ecf20Sopenharmony_ci} 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_cistatic int dib9000_sleep(struct dvb_frontend *fe) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 18718c2ecf20Sopenharmony_ci u8 index_frontend; 18728c2ecf20Sopenharmony_ci int ret = 0; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 18758c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 18768c2ecf20Sopenharmony_ci return -EINTR; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 18798c2ecf20Sopenharmony_ci ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); 18808c2ecf20Sopenharmony_ci if (ret < 0) 18818c2ecf20Sopenharmony_ci goto error; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_cierror: 18868c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 18878c2ecf20Sopenharmony_ci return ret; 18888c2ecf20Sopenharmony_ci} 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_cistatic int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) 18918c2ecf20Sopenharmony_ci{ 18928c2ecf20Sopenharmony_ci tune->min_delay_ms = 1000; 18938c2ecf20Sopenharmony_ci return 0; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic int dib9000_get_frontend(struct dvb_frontend *fe, 18978c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 19008c2ecf20Sopenharmony_ci u8 index_frontend, sub_index_frontend; 19018c2ecf20Sopenharmony_ci enum fe_status stat; 19028c2ecf20Sopenharmony_ci int ret = 0; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (state->get_frontend_internal == 0) { 19058c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 19068c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 19078c2ecf20Sopenharmony_ci return -EINTR; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci } 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 19128c2ecf20Sopenharmony_ci state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); 19138c2ecf20Sopenharmony_ci if (stat & FE_HAS_SYNC) { 19148c2ecf20Sopenharmony_ci dprintk("TPS lock on the slave%i\n", index_frontend); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci /* synchronize the cache with the other frontends */ 19178c2ecf20Sopenharmony_ci state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c); 19188c2ecf20Sopenharmony_ci for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); 19198c2ecf20Sopenharmony_ci sub_index_frontend++) { 19208c2ecf20Sopenharmony_ci if (sub_index_frontend != index_frontend) { 19218c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.modulation = 19228c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.modulation; 19238c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.inversion = 19248c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.inversion; 19258c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = 19268c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.transmission_mode; 19278c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = 19288c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.guard_interval; 19298c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.hierarchy = 19308c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.hierarchy; 19318c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP = 19328c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.code_rate_HP; 19338c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP = 19348c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.code_rate_LP; 19358c2ecf20Sopenharmony_ci state->fe[sub_index_frontend]->dtv_property_cache.rolloff = 19368c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.rolloff; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci ret = 0; 19408c2ecf20Sopenharmony_ci goto return_value; 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci /* get the channel from master chip */ 19458c2ecf20Sopenharmony_ci ret = dib9000_fw_get_channel(fe); 19468c2ecf20Sopenharmony_ci if (ret != 0) 19478c2ecf20Sopenharmony_ci goto return_value; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci /* synchronize the cache with the other frontends */ 19508c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 19518c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion; 19528c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode; 19538c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval; 19548c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.modulation = c->modulation; 19558c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.hierarchy = c->hierarchy; 19568c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.code_rate_HP = c->code_rate_HP; 19578c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.code_rate_LP = c->code_rate_LP; 19588c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.rolloff = c->rolloff; 19598c2ecf20Sopenharmony_ci } 19608c2ecf20Sopenharmony_ci ret = 0; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_cireturn_value: 19638c2ecf20Sopenharmony_ci if (state->get_frontend_internal == 0) 19648c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 19658c2ecf20Sopenharmony_ci return ret; 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_cistatic int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 19718c2ecf20Sopenharmony_ci state->tune_state = tune_state; 19728c2ecf20Sopenharmony_ci if (tune_state == CT_DEMOD_START) 19738c2ecf20Sopenharmony_ci state->status = FE_STATUS_TUNE_PENDING; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci return 0; 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_cistatic u32 dib9000_get_status(struct dvb_frontend *fe) 19798c2ecf20Sopenharmony_ci{ 19808c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 19818c2ecf20Sopenharmony_ci return state->status; 19828c2ecf20Sopenharmony_ci} 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_cistatic int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status) 19858c2ecf20Sopenharmony_ci{ 19868c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext)); 19898c2ecf20Sopenharmony_ci return 0; 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cistatic int dib9000_set_frontend(struct dvb_frontend *fe) 19938c2ecf20Sopenharmony_ci{ 19948c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 19958c2ecf20Sopenharmony_ci int sleep_time, sleep_time_slave; 19968c2ecf20Sopenharmony_ci u32 frontend_status; 19978c2ecf20Sopenharmony_ci u8 nbr_pending, exit_condition, index_frontend, index_frontend_success; 19988c2ecf20Sopenharmony_ci struct dvb_frontend_parametersContext channel_status; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci /* check that the correct parameters are set */ 20018c2ecf20Sopenharmony_ci if (state->fe[0]->dtv_property_cache.frequency == 0) { 20028c2ecf20Sopenharmony_ci dprintk("dib9000: must specify frequency\n"); 20038c2ecf20Sopenharmony_ci return 0; 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { 20078c2ecf20Sopenharmony_ci dprintk("dib9000: must specify bandwidth\n"); 20088c2ecf20Sopenharmony_ci return 0; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ 20128c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 20138c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 20148c2ecf20Sopenharmony_ci return 0; 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci fe->dtv_property_cache.delivery_system = SYS_DVBT; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci /* set the master status */ 20208c2ecf20Sopenharmony_ci if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO || 20218c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO || 20228c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.modulation == QAM_AUTO || 20238c2ecf20Sopenharmony_ci state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) { 20248c2ecf20Sopenharmony_ci /* no channel specified, autosearch the channel */ 20258c2ecf20Sopenharmony_ci state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; 20268c2ecf20Sopenharmony_ci } else 20278c2ecf20Sopenharmony_ci state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci /* set mode and status for the different frontends */ 20308c2ecf20Sopenharmony_ci for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20318c2ecf20Sopenharmony_ci dib9000_fw_set_diversity_in(state->fe[index_frontend], 1); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci /* synchronization of the cache */ 20348c2ecf20Sopenharmony_ci memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT; 20378c2ecf20Sopenharmony_ci dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status); 20408c2ecf20Sopenharmony_ci dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci /* actual tune */ 20448c2ecf20Sopenharmony_ci exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ 20458c2ecf20Sopenharmony_ci index_frontend_success = 0; 20468c2ecf20Sopenharmony_ci do { 20478c2ecf20Sopenharmony_ci sleep_time = dib9000_fw_tune(state->fe[0]); 20488c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20498c2ecf20Sopenharmony_ci sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); 20508c2ecf20Sopenharmony_ci if (sleep_time == FE_CALLBACK_TIME_NEVER) 20518c2ecf20Sopenharmony_ci sleep_time = sleep_time_slave; 20528c2ecf20Sopenharmony_ci else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) 20538c2ecf20Sopenharmony_ci sleep_time = sleep_time_slave; 20548c2ecf20Sopenharmony_ci } 20558c2ecf20Sopenharmony_ci if (sleep_time != FE_CALLBACK_TIME_NEVER) 20568c2ecf20Sopenharmony_ci msleep(sleep_time / 10); 20578c2ecf20Sopenharmony_ci else 20588c2ecf20Sopenharmony_ci break; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci nbr_pending = 0; 20618c2ecf20Sopenharmony_ci exit_condition = 0; 20628c2ecf20Sopenharmony_ci index_frontend_success = 0; 20638c2ecf20Sopenharmony_ci for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20648c2ecf20Sopenharmony_ci frontend_status = -dib9000_get_status(state->fe[index_frontend]); 20658c2ecf20Sopenharmony_ci if (frontend_status > -FE_STATUS_TUNE_PENDING) { 20668c2ecf20Sopenharmony_ci exit_condition = 2; /* tune success */ 20678c2ecf20Sopenharmony_ci index_frontend_success = index_frontend; 20688c2ecf20Sopenharmony_ci break; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci if (frontend_status == -FE_STATUS_TUNE_PENDING) 20718c2ecf20Sopenharmony_ci nbr_pending++; /* some frontends are still tuning */ 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci if ((exit_condition != 2) && (nbr_pending == 0)) 20748c2ecf20Sopenharmony_ci exit_condition = 1; /* if all tune are done and no success, exit: tune failed */ 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci } while (exit_condition == 0); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci /* check the tune result */ 20798c2ecf20Sopenharmony_ci if (exit_condition == 1) { /* tune failed */ 20808c2ecf20Sopenharmony_ci dprintk("tune failed\n"); 20818c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 20828c2ecf20Sopenharmony_ci /* tune failed; put all the pid filtering cmd to junk */ 20838c2ecf20Sopenharmony_ci state->pid_ctrl_index = -1; 20848c2ecf20Sopenharmony_ci return 0; 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci dprintk("tune success on frontend%i\n", index_frontend_success); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci /* synchronize all the channel cache */ 20908c2ecf20Sopenharmony_ci state->get_frontend_internal = 1; 20918c2ecf20Sopenharmony_ci dib9000_get_frontend(state->fe[0], &state->fe[0]->dtv_property_cache); 20928c2ecf20Sopenharmony_ci state->get_frontend_internal = 0; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci /* retune the other frontends with the found channel */ 20958c2ecf20Sopenharmony_ci channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; 20968c2ecf20Sopenharmony_ci for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 20978c2ecf20Sopenharmony_ci /* only retune the frontends which was not tuned success */ 20988c2ecf20Sopenharmony_ci if (index_frontend != index_frontend_success) { 20998c2ecf20Sopenharmony_ci dib9000_set_channel_status(state->fe[index_frontend], &channel_status); 21008c2ecf20Sopenharmony_ci dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); 21018c2ecf20Sopenharmony_ci } 21028c2ecf20Sopenharmony_ci } 21038c2ecf20Sopenharmony_ci do { 21048c2ecf20Sopenharmony_ci sleep_time = FE_CALLBACK_TIME_NEVER; 21058c2ecf20Sopenharmony_ci for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 21068c2ecf20Sopenharmony_ci if (index_frontend != index_frontend_success) { 21078c2ecf20Sopenharmony_ci sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); 21088c2ecf20Sopenharmony_ci if (sleep_time == FE_CALLBACK_TIME_NEVER) 21098c2ecf20Sopenharmony_ci sleep_time = sleep_time_slave; 21108c2ecf20Sopenharmony_ci else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) 21118c2ecf20Sopenharmony_ci sleep_time = sleep_time_slave; 21128c2ecf20Sopenharmony_ci } 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci if (sleep_time != FE_CALLBACK_TIME_NEVER) 21158c2ecf20Sopenharmony_ci msleep(sleep_time / 10); 21168c2ecf20Sopenharmony_ci else 21178c2ecf20Sopenharmony_ci break; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci nbr_pending = 0; 21208c2ecf20Sopenharmony_ci for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 21218c2ecf20Sopenharmony_ci if (index_frontend != index_frontend_success) { 21228c2ecf20Sopenharmony_ci frontend_status = -dib9000_get_status(state->fe[index_frontend]); 21238c2ecf20Sopenharmony_ci if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING)) 21248c2ecf20Sopenharmony_ci nbr_pending++; /* some frontends are still tuning */ 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci } while (nbr_pending != 0); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci /* set the output mode */ 21308c2ecf20Sopenharmony_ci dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode); 21318c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 21328c2ecf20Sopenharmony_ci dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci /* turn off the diversity for the last frontend */ 21358c2ecf20Sopenharmony_ci dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 21388c2ecf20Sopenharmony_ci if (state->pid_ctrl_index >= 0) { 21398c2ecf20Sopenharmony_ci u8 index_pid_filter_cmd; 21408c2ecf20Sopenharmony_ci u8 pid_ctrl_index = state->pid_ctrl_index; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci state->pid_ctrl_index = -2; 21438c2ecf20Sopenharmony_ci for (index_pid_filter_cmd = 0; 21448c2ecf20Sopenharmony_ci index_pid_filter_cmd <= pid_ctrl_index; 21458c2ecf20Sopenharmony_ci index_pid_filter_cmd++) { 21468c2ecf20Sopenharmony_ci if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL) 21478c2ecf20Sopenharmony_ci dib9000_fw_pid_filter_ctrl(state->fe[0], 21488c2ecf20Sopenharmony_ci state->pid_ctrl[index_pid_filter_cmd].onoff); 21498c2ecf20Sopenharmony_ci else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER) 21508c2ecf20Sopenharmony_ci dib9000_fw_pid_filter(state->fe[0], 21518c2ecf20Sopenharmony_ci state->pid_ctrl[index_pid_filter_cmd].id, 21528c2ecf20Sopenharmony_ci state->pid_ctrl[index_pid_filter_cmd].pid, 21538c2ecf20Sopenharmony_ci state->pid_ctrl[index_pid_filter_cmd].onoff); 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci /* do not postpone any more the pid filtering */ 21578c2ecf20Sopenharmony_ci state->pid_ctrl_index = -2; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci return 0; 21608c2ecf20Sopenharmony_ci} 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_cistatic u16 dib9000_read_lock(struct dvb_frontend *fe) 21638c2ecf20Sopenharmony_ci{ 21648c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci return dib9000_read_word(state, 535); 21678c2ecf20Sopenharmony_ci} 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_cistatic int dib9000_read_status(struct dvb_frontend *fe, enum fe_status *stat) 21708c2ecf20Sopenharmony_ci{ 21718c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 21728c2ecf20Sopenharmony_ci u8 index_frontend; 21738c2ecf20Sopenharmony_ci u16 lock = 0, lock_slave = 0; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 21768c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 21778c2ecf20Sopenharmony_ci return -EINTR; 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 21808c2ecf20Sopenharmony_ci lock_slave |= dib9000_read_lock(state->fe[index_frontend]); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci lock = dib9000_read_word(state, 535); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci *stat = 0; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if ((lock & 0x8000) || (lock_slave & 0x8000)) 21878c2ecf20Sopenharmony_ci *stat |= FE_HAS_SIGNAL; 21888c2ecf20Sopenharmony_ci if ((lock & 0x3000) || (lock_slave & 0x3000)) 21898c2ecf20Sopenharmony_ci *stat |= FE_HAS_CARRIER; 21908c2ecf20Sopenharmony_ci if ((lock & 0x0100) || (lock_slave & 0x0100)) 21918c2ecf20Sopenharmony_ci *stat |= FE_HAS_VITERBI; 21928c2ecf20Sopenharmony_ci if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38)) 21938c2ecf20Sopenharmony_ci *stat |= FE_HAS_SYNC; 21948c2ecf20Sopenharmony_ci if ((lock & 0x0008) || (lock_slave & 0x0008)) 21958c2ecf20Sopenharmony_ci *stat |= FE_HAS_LOCK; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci return 0; 22008c2ecf20Sopenharmony_ci} 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_cistatic int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 22058c2ecf20Sopenharmony_ci u16 *c; 22068c2ecf20Sopenharmony_ci int ret = 0; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 22098c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 22108c2ecf20Sopenharmony_ci return -EINTR; 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 22138c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 22148c2ecf20Sopenharmony_ci ret = -EINTR; 22158c2ecf20Sopenharmony_ci goto error; 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 22188c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 22198c2ecf20Sopenharmony_ci ret = -EIO; 22208c2ecf20Sopenharmony_ci goto error; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, 22238c2ecf20Sopenharmony_ci state->i2c_read_buffer, 16 * 2); 22248c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci c = (u16 *)state->i2c_read_buffer; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci *ber = c[10] << 16 | c[11]; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_cierror: 22318c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 22328c2ecf20Sopenharmony_ci return ret; 22338c2ecf20Sopenharmony_ci} 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_cistatic int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) 22368c2ecf20Sopenharmony_ci{ 22378c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 22388c2ecf20Sopenharmony_ci u8 index_frontend; 22398c2ecf20Sopenharmony_ci u16 *c = (u16 *)state->i2c_read_buffer; 22408c2ecf20Sopenharmony_ci u16 val; 22418c2ecf20Sopenharmony_ci int ret = 0; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 22448c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 22458c2ecf20Sopenharmony_ci return -EINTR; 22468c2ecf20Sopenharmony_ci } 22478c2ecf20Sopenharmony_ci *strength = 0; 22488c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { 22498c2ecf20Sopenharmony_ci state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); 22508c2ecf20Sopenharmony_ci if (val > 65535 - *strength) 22518c2ecf20Sopenharmony_ci *strength = 65535; 22528c2ecf20Sopenharmony_ci else 22538c2ecf20Sopenharmony_ci *strength += val; 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 22578c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 22588c2ecf20Sopenharmony_ci ret = -EINTR; 22598c2ecf20Sopenharmony_ci goto error; 22608c2ecf20Sopenharmony_ci } 22618c2ecf20Sopenharmony_ci if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 22628c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 22638c2ecf20Sopenharmony_ci ret = -EIO; 22648c2ecf20Sopenharmony_ci goto error; 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); 22678c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci val = 65535 - c[4]; 22708c2ecf20Sopenharmony_ci if (val > 65535 - *strength) 22718c2ecf20Sopenharmony_ci *strength = 65535; 22728c2ecf20Sopenharmony_ci else 22738c2ecf20Sopenharmony_ci *strength += val; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_cierror: 22768c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 22778c2ecf20Sopenharmony_ci return ret; 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_cistatic u32 dib9000_get_snr(struct dvb_frontend *fe) 22818c2ecf20Sopenharmony_ci{ 22828c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 22838c2ecf20Sopenharmony_ci u16 *c = (u16 *)state->i2c_read_buffer; 22848c2ecf20Sopenharmony_ci u32 n, s, exp; 22858c2ecf20Sopenharmony_ci u16 val; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 22888c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 22898c2ecf20Sopenharmony_ci return 0; 22908c2ecf20Sopenharmony_ci } 22918c2ecf20Sopenharmony_ci if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 22928c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 22938c2ecf20Sopenharmony_ci return 0; 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); 22968c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci val = c[7]; 22998c2ecf20Sopenharmony_ci n = (val >> 4) & 0xff; 23008c2ecf20Sopenharmony_ci exp = ((val & 0xf) << 2); 23018c2ecf20Sopenharmony_ci val = c[8]; 23028c2ecf20Sopenharmony_ci exp += ((val >> 14) & 0x3); 23038c2ecf20Sopenharmony_ci if ((exp & 0x20) != 0) 23048c2ecf20Sopenharmony_ci exp -= 0x40; 23058c2ecf20Sopenharmony_ci n <<= exp + 16; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci s = (val >> 6) & 0xFF; 23088c2ecf20Sopenharmony_ci exp = (val & 0x3F); 23098c2ecf20Sopenharmony_ci if ((exp & 0x20) != 0) 23108c2ecf20Sopenharmony_ci exp -= 0x40; 23118c2ecf20Sopenharmony_ci s <<= exp + 16; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (n > 0) { 23148c2ecf20Sopenharmony_ci u32 t = (s / n) << 16; 23158c2ecf20Sopenharmony_ci return t + ((s << 16) - n * t) / n; 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci return 0xffffffff; 23188c2ecf20Sopenharmony_ci} 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_cistatic int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) 23218c2ecf20Sopenharmony_ci{ 23228c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 23238c2ecf20Sopenharmony_ci u8 index_frontend; 23248c2ecf20Sopenharmony_ci u32 snr_master; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 23278c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 23288c2ecf20Sopenharmony_ci return -EINTR; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci snr_master = dib9000_get_snr(fe); 23318c2ecf20Sopenharmony_ci for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) 23328c2ecf20Sopenharmony_ci snr_master += dib9000_get_snr(state->fe[index_frontend]); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci if ((snr_master >> 16) != 0) { 23358c2ecf20Sopenharmony_ci snr_master = 10 * intlog10(snr_master >> 16); 23368c2ecf20Sopenharmony_ci *snr = snr_master / ((1 << 24) / 10); 23378c2ecf20Sopenharmony_ci } else 23388c2ecf20Sopenharmony_ci *snr = 0; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci return 0; 23438c2ecf20Sopenharmony_ci} 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_cistatic int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) 23468c2ecf20Sopenharmony_ci{ 23478c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 23488c2ecf20Sopenharmony_ci u16 *c = (u16 *)state->i2c_read_buffer; 23498c2ecf20Sopenharmony_ci int ret = 0; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->demod_lock) < 0) { 23528c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 23538c2ecf20Sopenharmony_ci return -EINTR; 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { 23568c2ecf20Sopenharmony_ci dprintk("could not get the lock\n"); 23578c2ecf20Sopenharmony_ci ret = -EINTR; 23588c2ecf20Sopenharmony_ci goto error; 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { 23618c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 23628c2ecf20Sopenharmony_ci ret = -EIO; 23638c2ecf20Sopenharmony_ci goto error; 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); 23668c2ecf20Sopenharmony_ci mutex_unlock(&state->platform.risc.mem_mbx_lock); 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci *unc = c[12]; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_cierror: 23718c2ecf20Sopenharmony_ci mutex_unlock(&state->demod_lock); 23728c2ecf20Sopenharmony_ci return ret; 23738c2ecf20Sopenharmony_ci} 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ciint dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) 23768c2ecf20Sopenharmony_ci{ 23778c2ecf20Sopenharmony_ci int k = 0, ret = 0; 23788c2ecf20Sopenharmony_ci u8 new_addr = 0; 23798c2ecf20Sopenharmony_ci struct i2c_device client = {.i2c_adap = i2c }; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci client.i2c_write_buffer = kzalloc(4, GFP_KERNEL); 23828c2ecf20Sopenharmony_ci if (!client.i2c_write_buffer) { 23838c2ecf20Sopenharmony_ci dprintk("%s: not enough memory\n", __func__); 23848c2ecf20Sopenharmony_ci return -ENOMEM; 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci client.i2c_read_buffer = kzalloc(4, GFP_KERNEL); 23878c2ecf20Sopenharmony_ci if (!client.i2c_read_buffer) { 23888c2ecf20Sopenharmony_ci dprintk("%s: not enough memory\n", __func__); 23898c2ecf20Sopenharmony_ci ret = -ENOMEM; 23908c2ecf20Sopenharmony_ci goto error_memory; 23918c2ecf20Sopenharmony_ci } 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci client.i2c_addr = default_addr + 16; 23948c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1796, 0x0); 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci for (k = no_of_demods - 1; k >= 0; k--) { 23978c2ecf20Sopenharmony_ci /* designated i2c address */ 23988c2ecf20Sopenharmony_ci new_addr = first_addr + (k << 1); 23998c2ecf20Sopenharmony_ci client.i2c_addr = default_addr; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1817, 3); 24028c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1796, 0); 24038c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1227, 1); 24048c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1227, 0); 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci client.i2c_addr = new_addr; 24078c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1817, 3); 24088c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1796, 0); 24098c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1227, 1); 24108c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1227, 0); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci if (dib9000_identify(&client) == 0) { 24138c2ecf20Sopenharmony_ci client.i2c_addr = default_addr; 24148c2ecf20Sopenharmony_ci if (dib9000_identify(&client) == 0) { 24158c2ecf20Sopenharmony_ci dprintk("DiB9000 #%d: not identified\n", k); 24168c2ecf20Sopenharmony_ci ret = -EIO; 24178c2ecf20Sopenharmony_ci goto error; 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6)); 24228c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2); 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); 24258c2ecf20Sopenharmony_ci } 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci for (k = 0; k < no_of_demods; k++) { 24288c2ecf20Sopenharmony_ci new_addr = first_addr | (k << 1); 24298c2ecf20Sopenharmony_ci client.i2c_addr = new_addr; 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1794, (new_addr << 2)); 24328c2ecf20Sopenharmony_ci dib9000_i2c_write16(&client, 1795, 0); 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_cierror: 24368c2ecf20Sopenharmony_ci kfree(client.i2c_read_buffer); 24378c2ecf20Sopenharmony_cierror_memory: 24388c2ecf20Sopenharmony_ci kfree(client.i2c_write_buffer); 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci return ret; 24418c2ecf20Sopenharmony_ci} 24428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_i2c_enumeration); 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ciint dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) 24458c2ecf20Sopenharmony_ci{ 24468c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 24478c2ecf20Sopenharmony_ci u8 index_frontend = 1; 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) 24508c2ecf20Sopenharmony_ci index_frontend++; 24518c2ecf20Sopenharmony_ci if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { 24528c2ecf20Sopenharmony_ci dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend); 24538c2ecf20Sopenharmony_ci state->fe[index_frontend] = fe_slave; 24548c2ecf20Sopenharmony_ci return 0; 24558c2ecf20Sopenharmony_ci } 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci dprintk("too many slave frontend\n"); 24588c2ecf20Sopenharmony_ci return -ENOMEM; 24598c2ecf20Sopenharmony_ci} 24608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_set_slave_frontend); 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_cistruct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) 24638c2ecf20Sopenharmony_ci{ 24648c2ecf20Sopenharmony_ci struct dib9000_state *state = fe->demodulator_priv; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci if (slave_index >= MAX_NUMBER_OF_FRONTENDS) 24678c2ecf20Sopenharmony_ci return NULL; 24688c2ecf20Sopenharmony_ci return state->fe[slave_index]; 24698c2ecf20Sopenharmony_ci} 24708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dib9000_get_slave_frontend); 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib9000_ops; 24738c2ecf20Sopenharmony_cistruct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg) 24748c2ecf20Sopenharmony_ci{ 24758c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 24768c2ecf20Sopenharmony_ci struct dib9000_state *st; 24778c2ecf20Sopenharmony_ci st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL); 24788c2ecf20Sopenharmony_ci if (st == NULL) 24798c2ecf20Sopenharmony_ci return NULL; 24808c2ecf20Sopenharmony_ci fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); 24818c2ecf20Sopenharmony_ci if (fe == NULL) { 24828c2ecf20Sopenharmony_ci kfree(st); 24838c2ecf20Sopenharmony_ci return NULL; 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config)); 24878c2ecf20Sopenharmony_ci st->i2c.i2c_adap = i2c_adap; 24888c2ecf20Sopenharmony_ci st->i2c.i2c_addr = i2c_addr; 24898c2ecf20Sopenharmony_ci st->i2c.i2c_write_buffer = st->i2c_write_buffer; 24908c2ecf20Sopenharmony_ci st->i2c.i2c_read_buffer = st->i2c_read_buffer; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS; 24938c2ecf20Sopenharmony_ci st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; 24948c2ecf20Sopenharmony_ci st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci mutex_init(&st->platform.risc.mbx_if_lock); 24978c2ecf20Sopenharmony_ci mutex_init(&st->platform.risc.mbx_lock); 24988c2ecf20Sopenharmony_ci mutex_init(&st->platform.risc.mem_lock); 24998c2ecf20Sopenharmony_ci mutex_init(&st->platform.risc.mem_mbx_lock); 25008c2ecf20Sopenharmony_ci mutex_init(&st->demod_lock); 25018c2ecf20Sopenharmony_ci st->get_frontend_internal = 0; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci st->pid_ctrl_index = -2; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci st->fe[0] = fe; 25068c2ecf20Sopenharmony_ci fe->demodulator_priv = st; 25078c2ecf20Sopenharmony_ci memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops)); 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* Ensure the output mode remains at the previous default if it's 25108c2ecf20Sopenharmony_ci * not specifically set by the caller. 25118c2ecf20Sopenharmony_ci */ 25128c2ecf20Sopenharmony_ci if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) 25138c2ecf20Sopenharmony_ci st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci if (dib9000_identify(&st->i2c) == 0) 25168c2ecf20Sopenharmony_ci goto error; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr); 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci st->tuner_adap.dev.parent = i2c_adap->dev.parent; 25218c2ecf20Sopenharmony_ci strscpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", 25228c2ecf20Sopenharmony_ci sizeof(st->tuner_adap.name)); 25238c2ecf20Sopenharmony_ci st->tuner_adap.algo = &dib9000_tuner_algo; 25248c2ecf20Sopenharmony_ci st->tuner_adap.algo_data = NULL; 25258c2ecf20Sopenharmony_ci i2c_set_adapdata(&st->tuner_adap, st); 25268c2ecf20Sopenharmony_ci if (i2c_add_adapter(&st->tuner_adap) < 0) 25278c2ecf20Sopenharmony_ci goto error; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci st->component_bus.dev.parent = i2c_adap->dev.parent; 25308c2ecf20Sopenharmony_ci strscpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", 25318c2ecf20Sopenharmony_ci sizeof(st->component_bus.name)); 25328c2ecf20Sopenharmony_ci st->component_bus.algo = &dib9000_component_bus_algo; 25338c2ecf20Sopenharmony_ci st->component_bus.algo_data = NULL; 25348c2ecf20Sopenharmony_ci st->component_bus_speed = 340; 25358c2ecf20Sopenharmony_ci i2c_set_adapdata(&st->component_bus, st); 25368c2ecf20Sopenharmony_ci if (i2c_add_adapter(&st->component_bus) < 0) 25378c2ecf20Sopenharmony_ci goto component_bus_add_error; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci dib9000_fw_reset(fe); 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci return fe; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_cicomponent_bus_add_error: 25448c2ecf20Sopenharmony_ci i2c_del_adapter(&st->tuner_adap); 25458c2ecf20Sopenharmony_cierror: 25468c2ecf20Sopenharmony_ci kfree(st); 25478c2ecf20Sopenharmony_ci return NULL; 25488c2ecf20Sopenharmony_ci} 25498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dib9000_attach); 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_cistatic const struct dvb_frontend_ops dib9000_ops = { 25528c2ecf20Sopenharmony_ci .delsys = { SYS_DVBT }, 25538c2ecf20Sopenharmony_ci .info = { 25548c2ecf20Sopenharmony_ci .name = "DiBcom 9000", 25558c2ecf20Sopenharmony_ci .frequency_min_hz = 44250 * kHz, 25568c2ecf20Sopenharmony_ci .frequency_max_hz = 867250 * kHz, 25578c2ecf20Sopenharmony_ci .frequency_stepsize_hz = 62500, 25588c2ecf20Sopenharmony_ci .caps = FE_CAN_INVERSION_AUTO | 25598c2ecf20Sopenharmony_ci FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 25608c2ecf20Sopenharmony_ci FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 25618c2ecf20Sopenharmony_ci FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | 25628c2ecf20Sopenharmony_ci FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, 25638c2ecf20Sopenharmony_ci }, 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci .release = dib9000_release, 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci .init = dib9000_wakeup, 25688c2ecf20Sopenharmony_ci .sleep = dib9000_sleep, 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci .set_frontend = dib9000_set_frontend, 25718c2ecf20Sopenharmony_ci .get_tune_settings = dib9000_fe_get_tune_settings, 25728c2ecf20Sopenharmony_ci .get_frontend = dib9000_get_frontend, 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci .read_status = dib9000_read_status, 25758c2ecf20Sopenharmony_ci .read_ber = dib9000_read_ber, 25768c2ecf20Sopenharmony_ci .read_signal_strength = dib9000_read_signal_strength, 25778c2ecf20Sopenharmony_ci .read_snr = dib9000_read_snr, 25788c2ecf20Sopenharmony_ci .read_ucblocks = dib9000_read_unc_blocks, 25798c2ecf20Sopenharmony_ci}; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 25828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>"); 25838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator"); 25848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2585