18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * driver for Earthsoft PT1/PT2 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * based on pt1dvr - http://pt1dvr.sourceforge.jp/ 88c2ecf20Sopenharmony_ci * by Tomoaki Ishikawa <tomy@users.sourceforge.jp> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/sched.h> 138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 148c2ecf20Sopenharmony_ci#include <linux/hrtimer.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/kthread.h> 218c2ecf20Sopenharmony_ci#include <linux/freezer.h> 228c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 238c2ecf20Sopenharmony_ci#include <linux/string.h> 248c2ecf20Sopenharmony_ci#include <linux/i2c.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <media/dvbdev.h> 278c2ecf20Sopenharmony_ci#include <media/dvb_demux.h> 288c2ecf20Sopenharmony_ci#include <media/dmxdev.h> 298c2ecf20Sopenharmony_ci#include <media/dvb_net.h> 308c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "tc90522.h" 338c2ecf20Sopenharmony_ci#include "qm1d1b0004.h" 348c2ecf20Sopenharmony_ci#include "dvb-pll.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DRIVER_NAME "earth-pt1" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define PT1_PAGE_SHIFT 12 398c2ecf20Sopenharmony_ci#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT) 408c2ecf20Sopenharmony_ci#define PT1_NR_UPACKETS 1024 418c2ecf20Sopenharmony_ci#define PT1_NR_BUFS 511 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct pt1_buffer_page { 448c2ecf20Sopenharmony_ci __le32 upackets[PT1_NR_UPACKETS]; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct pt1_table_page { 488c2ecf20Sopenharmony_ci __le32 next_pfn; 498c2ecf20Sopenharmony_ci __le32 buf_pfns[PT1_NR_BUFS]; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct pt1_buffer { 538c2ecf20Sopenharmony_ci struct pt1_buffer_page *page; 548c2ecf20Sopenharmony_ci dma_addr_t addr; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct pt1_table { 588c2ecf20Sopenharmony_ci struct pt1_table_page *page; 598c2ecf20Sopenharmony_ci dma_addr_t addr; 608c2ecf20Sopenharmony_ci struct pt1_buffer bufs[PT1_NR_BUFS]; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cienum pt1_fe_clk { 648c2ecf20Sopenharmony_ci PT1_FE_CLK_20MHZ, /* PT1 */ 658c2ecf20Sopenharmony_ci PT1_FE_CLK_25MHZ, /* PT2 */ 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define PT1_NR_ADAPS 4 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistruct pt1_adapter; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct pt1 { 738c2ecf20Sopenharmony_ci struct pci_dev *pdev; 748c2ecf20Sopenharmony_ci void __iomem *regs; 758c2ecf20Sopenharmony_ci struct i2c_adapter i2c_adap; 768c2ecf20Sopenharmony_ci int i2c_running; 778c2ecf20Sopenharmony_ci struct pt1_adapter *adaps[PT1_NR_ADAPS]; 788c2ecf20Sopenharmony_ci struct pt1_table *tables; 798c2ecf20Sopenharmony_ci struct task_struct *kthread; 808c2ecf20Sopenharmony_ci int table_index; 818c2ecf20Sopenharmony_ci int buf_index; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci struct mutex lock; 848c2ecf20Sopenharmony_ci int power; 858c2ecf20Sopenharmony_ci int reset; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci enum pt1_fe_clk fe_clk; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct pt1_adapter { 918c2ecf20Sopenharmony_ci struct pt1 *pt1; 928c2ecf20Sopenharmony_ci int index; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci u8 *buf; 958c2ecf20Sopenharmony_ci int upacket_count; 968c2ecf20Sopenharmony_ci int packet_count; 978c2ecf20Sopenharmony_ci int st_count; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci struct dvb_adapter adap; 1008c2ecf20Sopenharmony_ci struct dvb_demux demux; 1018c2ecf20Sopenharmony_ci int users; 1028c2ecf20Sopenharmony_ci struct dmxdev dmxdev; 1038c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 1048c2ecf20Sopenharmony_ci struct i2c_client *demod_i2c_client; 1058c2ecf20Sopenharmony_ci struct i2c_client *tuner_i2c_client; 1068c2ecf20Sopenharmony_ci int (*orig_set_voltage)(struct dvb_frontend *fe, 1078c2ecf20Sopenharmony_ci enum fe_sec_voltage voltage); 1088c2ecf20Sopenharmony_ci int (*orig_sleep)(struct dvb_frontend *fe); 1098c2ecf20Sopenharmony_ci int (*orig_init)(struct dvb_frontend *fe); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci enum fe_sec_voltage voltage; 1128c2ecf20Sopenharmony_ci int sleep; 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciunion pt1_tuner_config { 1168c2ecf20Sopenharmony_ci struct qm1d1b0004_config qm1d1b0004; 1178c2ecf20Sopenharmony_ci struct dvb_pll_config tda6651; 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistruct pt1_config { 1218c2ecf20Sopenharmony_ci struct i2c_board_info demod_info; 1228c2ecf20Sopenharmony_ci struct tc90522_config demod_cfg; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci struct i2c_board_info tuner_info; 1258c2ecf20Sopenharmony_ci union pt1_tuner_config tuner_cfg; 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic const struct pt1_config pt1_configs[PT1_NR_ADAPS] = { 1298c2ecf20Sopenharmony_ci { 1308c2ecf20Sopenharmony_ci .demod_info = { 1318c2ecf20Sopenharmony_ci I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x1b), 1328c2ecf20Sopenharmony_ci }, 1338c2ecf20Sopenharmony_ci .tuner_info = { 1348c2ecf20Sopenharmony_ci I2C_BOARD_INFO("qm1d1b0004", 0x60), 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci }, 1378c2ecf20Sopenharmony_ci { 1388c2ecf20Sopenharmony_ci .demod_info = { 1398c2ecf20Sopenharmony_ci I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x1a), 1408c2ecf20Sopenharmony_ci }, 1418c2ecf20Sopenharmony_ci .tuner_info = { 1428c2ecf20Sopenharmony_ci I2C_BOARD_INFO("tda665x_earthpt1", 0x61), 1438c2ecf20Sopenharmony_ci }, 1448c2ecf20Sopenharmony_ci }, 1458c2ecf20Sopenharmony_ci { 1468c2ecf20Sopenharmony_ci .demod_info = { 1478c2ecf20Sopenharmony_ci I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x19), 1488c2ecf20Sopenharmony_ci }, 1498c2ecf20Sopenharmony_ci .tuner_info = { 1508c2ecf20Sopenharmony_ci I2C_BOARD_INFO("qm1d1b0004", 0x60), 1518c2ecf20Sopenharmony_ci }, 1528c2ecf20Sopenharmony_ci }, 1538c2ecf20Sopenharmony_ci { 1548c2ecf20Sopenharmony_ci .demod_info = { 1558c2ecf20Sopenharmony_ci I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x18), 1568c2ecf20Sopenharmony_ci }, 1578c2ecf20Sopenharmony_ci .tuner_info = { 1588c2ecf20Sopenharmony_ci I2C_BOARD_INFO("tda665x_earthpt1", 0x61), 1598c2ecf20Sopenharmony_ci }, 1608c2ecf20Sopenharmony_ci }, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic const u8 va1j5jf8007s_20mhz_configs[][2] = { 1648c2ecf20Sopenharmony_ci {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, 1658c2ecf20Sopenharmony_ci {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, 1668c2ecf20Sopenharmony_ci {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, 1678c2ecf20Sopenharmony_ci {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0}, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic const u8 va1j5jf8007s_25mhz_configs[][2] = { 1718c2ecf20Sopenharmony_ci {0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a}, 1728c2ecf20Sopenharmony_ci {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89}, 1738c2ecf20Sopenharmony_ci {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04}, 1748c2ecf20Sopenharmony_ci {0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0}, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const u8 va1j5jf8007t_20mhz_configs[][2] = { 1788c2ecf20Sopenharmony_ci {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, 1798c2ecf20Sopenharmony_ci {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00}, 1808c2ecf20Sopenharmony_ci {0x3b, 0x11}, {0x3c, 0x3f}, 1818c2ecf20Sopenharmony_ci {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03}, 1828c2ecf20Sopenharmony_ci {0xef, 0x01} 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic const u8 va1j5jf8007t_25mhz_configs[][2] = { 1868c2ecf20Sopenharmony_ci {0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83}, 1878c2ecf20Sopenharmony_ci {0x3a, 0x04}, {0x3b, 0x11}, {0x3c, 0x3f}, {0x5c, 0x40}, {0x5f, 0x80}, 1888c2ecf20Sopenharmony_ci {0x75, 0x0a}, {0x76, 0x4c}, {0x77, 0x03}, {0xef, 0x01} 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci bool is_sat; 1958c2ecf20Sopenharmony_ci const u8 (*cfg_data)[2]; 1968c2ecf20Sopenharmony_ci int i, len; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci is_sat = !strncmp(cl->name, TC90522_I2C_DEV_SAT, 1998c2ecf20Sopenharmony_ci strlen(TC90522_I2C_DEV_SAT)); 2008c2ecf20Sopenharmony_ci if (is_sat) { 2018c2ecf20Sopenharmony_ci struct i2c_msg msg[2]; 2028c2ecf20Sopenharmony_ci u8 wbuf, rbuf; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci wbuf = 0x07; 2058c2ecf20Sopenharmony_ci msg[0].addr = cl->addr; 2068c2ecf20Sopenharmony_ci msg[0].flags = 0; 2078c2ecf20Sopenharmony_ci msg[0].len = 1; 2088c2ecf20Sopenharmony_ci msg[0].buf = &wbuf; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci msg[1].addr = cl->addr; 2118c2ecf20Sopenharmony_ci msg[1].flags = I2C_M_RD; 2128c2ecf20Sopenharmony_ci msg[1].len = 1; 2138c2ecf20Sopenharmony_ci msg[1].buf = &rbuf; 2148c2ecf20Sopenharmony_ci ret = i2c_transfer(cl->adapter, msg, 2); 2158c2ecf20Sopenharmony_ci if (ret < 0) 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci if (rbuf != 0x41) 2188c2ecf20Sopenharmony_ci return -EIO; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* frontend init */ 2228c2ecf20Sopenharmony_ci if (clk == PT1_FE_CLK_20MHZ) { 2238c2ecf20Sopenharmony_ci if (is_sat) { 2248c2ecf20Sopenharmony_ci cfg_data = va1j5jf8007s_20mhz_configs; 2258c2ecf20Sopenharmony_ci len = ARRAY_SIZE(va1j5jf8007s_20mhz_configs); 2268c2ecf20Sopenharmony_ci } else { 2278c2ecf20Sopenharmony_ci cfg_data = va1j5jf8007t_20mhz_configs; 2288c2ecf20Sopenharmony_ci len = ARRAY_SIZE(va1j5jf8007t_20mhz_configs); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci } else { 2318c2ecf20Sopenharmony_ci if (is_sat) { 2328c2ecf20Sopenharmony_ci cfg_data = va1j5jf8007s_25mhz_configs; 2338c2ecf20Sopenharmony_ci len = ARRAY_SIZE(va1j5jf8007s_25mhz_configs); 2348c2ecf20Sopenharmony_ci } else { 2358c2ecf20Sopenharmony_ci cfg_data = va1j5jf8007t_25mhz_configs; 2368c2ecf20Sopenharmony_ci len = ARRAY_SIZE(va1j5jf8007t_25mhz_configs); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 2418c2ecf20Sopenharmony_ci ret = i2c_master_send(cl, cfg_data[i], 2); 2428c2ecf20Sopenharmony_ci if (ret < 0) 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* 2498c2ecf20Sopenharmony_ci * Init registers for (each pair of) terrestrial/satellite block in demod. 2508c2ecf20Sopenharmony_ci * Note that resetting terr. block also resets its peer sat. block as well. 2518c2ecf20Sopenharmony_ci * This function must be called before configuring any demod block 2528c2ecf20Sopenharmony_ci * (before pt1_wakeup(), fe->ops.init()). 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic int pt1_demod_block_init(struct pt1 *pt1) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct i2c_client *cl; 2578c2ecf20Sopenharmony_ci u8 buf[2] = {0x01, 0x80}; 2588c2ecf20Sopenharmony_ci int ret; 2598c2ecf20Sopenharmony_ci int i; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* reset all terr. & sat. pairs first */ 2628c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) { 2638c2ecf20Sopenharmony_ci cl = pt1->adaps[i]->demod_i2c_client; 2648c2ecf20Sopenharmony_ci if (strncmp(cl->name, TC90522_I2C_DEV_TER, 2658c2ecf20Sopenharmony_ci strlen(TC90522_I2C_DEV_TER))) 2668c2ecf20Sopenharmony_ci continue; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = i2c_master_send(cl, buf, 2); 2698c2ecf20Sopenharmony_ci if (ret < 0) 2708c2ecf20Sopenharmony_ci return ret; 2718c2ecf20Sopenharmony_ci usleep_range(30000, 50000); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) { 2758c2ecf20Sopenharmony_ci cl = pt1->adaps[i]->demod_i2c_client; 2768c2ecf20Sopenharmony_ci if (strncmp(cl->name, TC90522_I2C_DEV_SAT, 2778c2ecf20Sopenharmony_ci strlen(TC90522_I2C_DEV_SAT))) 2788c2ecf20Sopenharmony_ci continue; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = i2c_master_send(cl, buf, 2); 2818c2ecf20Sopenharmony_ci if (ret < 0) 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci usleep_range(30000, 50000); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void pt1_write_reg(struct pt1 *pt1, int reg, u32 data) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci writel(data, pt1->regs + reg * 4); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic u32 pt1_read_reg(struct pt1 *pt1, int reg) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci return readl(pt1->regs + reg * 4); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic unsigned int pt1_nr_tables = 8; 2998c2ecf20Sopenharmony_cimodule_param_named(nr_tables, pt1_nr_tables, uint, 0); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void pt1_increment_table_count(struct pt1 *pt1) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x00000020); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void pt1_init_table_count(struct pt1 *pt1) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x00000010); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void pt1_register_tables(struct pt1 *pt1, u32 first_pfn) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 5, first_pfn); 3148c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x0c000040); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void pt1_unregister_tables(struct pt1 *pt1) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x08080000); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int pt1_sync(struct pt1 *pt1) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci int i; 3258c2ecf20Sopenharmony_ci for (i = 0; i < 57; i++) { 3268c2ecf20Sopenharmony_ci if (pt1_read_reg(pt1, 0) & 0x20000000) 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x00000008); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci dev_err(&pt1->pdev->dev, "could not sync\n"); 3318c2ecf20Sopenharmony_ci return -EIO; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic u64 pt1_identify(struct pt1 *pt1) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci int i; 3378c2ecf20Sopenharmony_ci u64 id; 3388c2ecf20Sopenharmony_ci id = 0; 3398c2ecf20Sopenharmony_ci for (i = 0; i < 57; i++) { 3408c2ecf20Sopenharmony_ci id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i; 3418c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x00000008); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci return id; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int pt1_unlock(struct pt1 *pt1) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci int i; 3498c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x00000008); 3508c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 3518c2ecf20Sopenharmony_ci if (pt1_read_reg(pt1, 0) & 0x80000000) 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci dev_err(&pt1->pdev->dev, "could not unlock\n"); 3568c2ecf20Sopenharmony_ci return -EIO; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int pt1_reset_pci(struct pt1 *pt1) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci int i; 3628c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x01010000); 3638c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x01000000); 3648c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 3658c2ecf20Sopenharmony_ci if (pt1_read_reg(pt1, 0) & 0x00000001) 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci dev_err(&pt1->pdev->dev, "could not reset PCI\n"); 3708c2ecf20Sopenharmony_ci return -EIO; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int pt1_reset_ram(struct pt1 *pt1) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci int i; 3768c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x02020000); 3778c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x02000000); 3788c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 3798c2ecf20Sopenharmony_ci if (pt1_read_reg(pt1, 0) & 0x00000002) 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci dev_err(&pt1->pdev->dev, "could not reset RAM\n"); 3848c2ecf20Sopenharmony_ci return -EIO; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int pt1_do_enable_ram(struct pt1 *pt1) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci int i, j; 3908c2ecf20Sopenharmony_ci u32 status; 3918c2ecf20Sopenharmony_ci status = pt1_read_reg(pt1, 0) & 0x00000004; 3928c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x00000002); 3938c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 3948c2ecf20Sopenharmony_ci for (j = 0; j < 1024; j++) { 3958c2ecf20Sopenharmony_ci if ((pt1_read_reg(pt1, 0) & 0x00000004) != status) 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci dev_err(&pt1->pdev->dev, "could not enable RAM\n"); 4018c2ecf20Sopenharmony_ci return -EIO; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic int pt1_enable_ram(struct pt1 *pt1) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci int i, ret; 4078c2ecf20Sopenharmony_ci int phase; 4088c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 4098c2ecf20Sopenharmony_ci phase = pt1->pdev->device == 0x211a ? 128 : 166; 4108c2ecf20Sopenharmony_ci for (i = 0; i < phase; i++) { 4118c2ecf20Sopenharmony_ci ret = pt1_do_enable_ram(pt1); 4128c2ecf20Sopenharmony_ci if (ret < 0) 4138c2ecf20Sopenharmony_ci return ret; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic void pt1_disable_ram(struct pt1 *pt1) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x0b0b0000); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic void pt1_set_stream(struct pt1 *pt1, int index, int enabled) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void pt1_init_streams(struct pt1 *pt1) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci int i; 4318c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) 4328c2ecf20Sopenharmony_ci pt1_set_stream(pt1, i, 0); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci u32 upacket; 4388c2ecf20Sopenharmony_ci int i; 4398c2ecf20Sopenharmony_ci int index; 4408c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 4418c2ecf20Sopenharmony_ci int offset; 4428c2ecf20Sopenharmony_ci u8 *buf; 4438c2ecf20Sopenharmony_ci int sc; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!page->upackets[PT1_NR_UPACKETS - 1]) 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_UPACKETS; i++) { 4498c2ecf20Sopenharmony_ci upacket = le32_to_cpu(page->upackets[i]); 4508c2ecf20Sopenharmony_ci index = (upacket >> 29) - 1; 4518c2ecf20Sopenharmony_ci if (index < 0 || index >= PT1_NR_ADAPS) 4528c2ecf20Sopenharmony_ci continue; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci adap = pt1->adaps[index]; 4558c2ecf20Sopenharmony_ci if (upacket >> 25 & 1) 4568c2ecf20Sopenharmony_ci adap->upacket_count = 0; 4578c2ecf20Sopenharmony_ci else if (!adap->upacket_count) 4588c2ecf20Sopenharmony_ci continue; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (upacket >> 24 & 1) 4618c2ecf20Sopenharmony_ci printk_ratelimited(KERN_INFO "earth-pt1: device buffer overflowing. table[%d] buf[%d]\n", 4628c2ecf20Sopenharmony_ci pt1->table_index, pt1->buf_index); 4638c2ecf20Sopenharmony_ci sc = upacket >> 26 & 0x7; 4648c2ecf20Sopenharmony_ci if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) 4658c2ecf20Sopenharmony_ci printk_ratelimited(KERN_INFO "earth-pt1: data loss in streamID(adapter)[%d]\n", 4668c2ecf20Sopenharmony_ci index); 4678c2ecf20Sopenharmony_ci adap->st_count = sc; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci buf = adap->buf; 4708c2ecf20Sopenharmony_ci offset = adap->packet_count * 188 + adap->upacket_count * 3; 4718c2ecf20Sopenharmony_ci buf[offset] = upacket >> 16; 4728c2ecf20Sopenharmony_ci buf[offset + 1] = upacket >> 8; 4738c2ecf20Sopenharmony_ci if (adap->upacket_count != 62) 4748c2ecf20Sopenharmony_ci buf[offset + 2] = upacket; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (++adap->upacket_count >= 63) { 4778c2ecf20Sopenharmony_ci adap->upacket_count = 0; 4788c2ecf20Sopenharmony_ci if (++adap->packet_count >= 21) { 4798c2ecf20Sopenharmony_ci dvb_dmx_swfilter_packets(&adap->demux, buf, 21); 4808c2ecf20Sopenharmony_ci adap->packet_count = 0; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci page->upackets[PT1_NR_UPACKETS - 1] = 0; 4868c2ecf20Sopenharmony_ci return 1; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int pt1_thread(void *data) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct pt1 *pt1; 4928c2ecf20Sopenharmony_ci struct pt1_buffer_page *page; 4938c2ecf20Sopenharmony_ci bool was_frozen; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci#define PT1_FETCH_DELAY 10 4968c2ecf20Sopenharmony_ci#define PT1_FETCH_DELAY_DELTA 2 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci pt1 = data; 4998c2ecf20Sopenharmony_ci set_freezable(); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci while (!kthread_freezable_should_stop(&was_frozen)) { 5028c2ecf20Sopenharmony_ci if (was_frozen) { 5038c2ecf20Sopenharmony_ci int i; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) 5068c2ecf20Sopenharmony_ci pt1_set_stream(pt1, i, !!pt1->adaps[i]->users); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; 5108c2ecf20Sopenharmony_ci if (!pt1_filter(pt1, page)) { 5118c2ecf20Sopenharmony_ci ktime_t delay; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci delay = ktime_set(0, PT1_FETCH_DELAY * NSEC_PER_MSEC); 5148c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 5158c2ecf20Sopenharmony_ci schedule_hrtimeout_range(&delay, 5168c2ecf20Sopenharmony_ci PT1_FETCH_DELAY_DELTA * NSEC_PER_MSEC, 5178c2ecf20Sopenharmony_ci HRTIMER_MODE_REL); 5188c2ecf20Sopenharmony_ci continue; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (++pt1->buf_index >= PT1_NR_BUFS) { 5228c2ecf20Sopenharmony_ci pt1_increment_table_count(pt1); 5238c2ecf20Sopenharmony_ci pt1->buf_index = 0; 5248c2ecf20Sopenharmony_ci if (++pt1->table_index >= pt1_nr_tables) 5258c2ecf20Sopenharmony_ci pt1->table_index = 0; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci void *page; 5408c2ecf20Sopenharmony_ci dma_addr_t addr; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr, 5438c2ecf20Sopenharmony_ci GFP_KERNEL); 5448c2ecf20Sopenharmony_ci if (page == NULL) 5458c2ecf20Sopenharmony_ci return NULL; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci BUG_ON(addr & (PT1_PAGE_SIZE - 1)); 5488c2ecf20Sopenharmony_ci BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci *addrp = addr; 5518c2ecf20Sopenharmony_ci *pfnp = addr >> PT1_PAGE_SHIFT; 5528c2ecf20Sopenharmony_ci return page; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci pt1_free_page(pt1, buf->page, buf->addr); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int 5618c2ecf20Sopenharmony_cipt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf, u32 *pfnp) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct pt1_buffer_page *page; 5648c2ecf20Sopenharmony_ci dma_addr_t addr; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci page = pt1_alloc_page(pt1, &addr, pfnp); 5678c2ecf20Sopenharmony_ci if (page == NULL) 5688c2ecf20Sopenharmony_ci return -ENOMEM; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci page->upackets[PT1_NR_UPACKETS - 1] = 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci buf->page = page; 5738c2ecf20Sopenharmony_ci buf->addr = addr; 5748c2ecf20Sopenharmony_ci return 0; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci int i; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_BUFS; i++) 5828c2ecf20Sopenharmony_ci pt1_cleanup_buffer(pt1, &table->bufs[i]); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci pt1_free_page(pt1, table->page, table->addr); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic int 5888c2ecf20Sopenharmony_cipt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct pt1_table_page *page; 5918c2ecf20Sopenharmony_ci dma_addr_t addr; 5928c2ecf20Sopenharmony_ci int i, ret; 5938c2ecf20Sopenharmony_ci u32 buf_pfn; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci page = pt1_alloc_page(pt1, &addr, pfnp); 5968c2ecf20Sopenharmony_ci if (page == NULL) 5978c2ecf20Sopenharmony_ci return -ENOMEM; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_BUFS; i++) { 6008c2ecf20Sopenharmony_ci ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn); 6018c2ecf20Sopenharmony_ci if (ret < 0) 6028c2ecf20Sopenharmony_ci goto err; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci page->buf_pfns[i] = cpu_to_le32(buf_pfn); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci pt1_increment_table_count(pt1); 6088c2ecf20Sopenharmony_ci table->page = page; 6098c2ecf20Sopenharmony_ci table->addr = addr; 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cierr: 6138c2ecf20Sopenharmony_ci while (i--) 6148c2ecf20Sopenharmony_ci pt1_cleanup_buffer(pt1, &table->bufs[i]); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci pt1_free_page(pt1, page, addr); 6178c2ecf20Sopenharmony_ci return ret; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic void pt1_cleanup_tables(struct pt1 *pt1) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct pt1_table *tables; 6238c2ecf20Sopenharmony_ci int i; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci tables = pt1->tables; 6268c2ecf20Sopenharmony_ci pt1_unregister_tables(pt1); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci for (i = 0; i < pt1_nr_tables; i++) 6298c2ecf20Sopenharmony_ci pt1_cleanup_table(pt1, &tables[i]); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci vfree(tables); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int pt1_init_tables(struct pt1 *pt1) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct pt1_table *tables; 6378c2ecf20Sopenharmony_ci int i, ret; 6388c2ecf20Sopenharmony_ci u32 first_pfn, pfn; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (!pt1_nr_tables) 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci tables = vmalloc(array_size(pt1_nr_tables, sizeof(struct pt1_table))); 6448c2ecf20Sopenharmony_ci if (tables == NULL) 6458c2ecf20Sopenharmony_ci return -ENOMEM; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci pt1_init_table_count(pt1); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci i = 0; 6508c2ecf20Sopenharmony_ci ret = pt1_init_table(pt1, &tables[0], &first_pfn); 6518c2ecf20Sopenharmony_ci if (ret) 6528c2ecf20Sopenharmony_ci goto err; 6538c2ecf20Sopenharmony_ci i++; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci while (i < pt1_nr_tables) { 6568c2ecf20Sopenharmony_ci ret = pt1_init_table(pt1, &tables[i], &pfn); 6578c2ecf20Sopenharmony_ci if (ret) 6588c2ecf20Sopenharmony_ci goto err; 6598c2ecf20Sopenharmony_ci tables[i - 1].page->next_pfn = cpu_to_le32(pfn); 6608c2ecf20Sopenharmony_ci i++; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci pt1_register_tables(pt1, first_pfn); 6668c2ecf20Sopenharmony_ci pt1->tables = tables; 6678c2ecf20Sopenharmony_ci return 0; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cierr: 6708c2ecf20Sopenharmony_ci while (i--) 6718c2ecf20Sopenharmony_ci pt1_cleanup_table(pt1, &tables[i]); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci vfree(tables); 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int pt1_start_polling(struct pt1 *pt1) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci int ret = 0; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci mutex_lock(&pt1->lock); 6828c2ecf20Sopenharmony_ci if (!pt1->kthread) { 6838c2ecf20Sopenharmony_ci pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1"); 6848c2ecf20Sopenharmony_ci if (IS_ERR(pt1->kthread)) { 6858c2ecf20Sopenharmony_ci ret = PTR_ERR(pt1->kthread); 6868c2ecf20Sopenharmony_ci pt1->kthread = NULL; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci mutex_unlock(&pt1->lock); 6908c2ecf20Sopenharmony_ci return ret; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int pt1_start_feed(struct dvb_demux_feed *feed) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 6968c2ecf20Sopenharmony_ci adap = container_of(feed->demux, struct pt1_adapter, demux); 6978c2ecf20Sopenharmony_ci if (!adap->users++) { 6988c2ecf20Sopenharmony_ci int ret; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci ret = pt1_start_polling(adap->pt1); 7018c2ecf20Sopenharmony_ci if (ret) 7028c2ecf20Sopenharmony_ci return ret; 7038c2ecf20Sopenharmony_ci pt1_set_stream(adap->pt1, adap->index, 1); 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci return 0; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void pt1_stop_polling(struct pt1 *pt1) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci int i, count; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci mutex_lock(&pt1->lock); 7138c2ecf20Sopenharmony_ci for (i = 0, count = 0; i < PT1_NR_ADAPS; i++) 7148c2ecf20Sopenharmony_ci count += pt1->adaps[i]->users; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (count == 0 && pt1->kthread) { 7178c2ecf20Sopenharmony_ci kthread_stop(pt1->kthread); 7188c2ecf20Sopenharmony_ci pt1->kthread = NULL; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci mutex_unlock(&pt1->lock); 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int pt1_stop_feed(struct dvb_demux_feed *feed) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 7268c2ecf20Sopenharmony_ci adap = container_of(feed->demux, struct pt1_adapter, demux); 7278c2ecf20Sopenharmony_ci if (!--adap->users) { 7288c2ecf20Sopenharmony_ci pt1_set_stream(adap->pt1, adap->index, 0); 7298c2ecf20Sopenharmony_ci pt1_stop_polling(adap->pt1); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic void 7358c2ecf20Sopenharmony_cipt1_update_power(struct pt1 *pt1) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci int bits; 7388c2ecf20Sopenharmony_ci int i; 7398c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 7408c2ecf20Sopenharmony_ci static const int sleep_bits[] = { 7418c2ecf20Sopenharmony_ci 1 << 4, 7428c2ecf20Sopenharmony_ci 1 << 6 | 1 << 7, 7438c2ecf20Sopenharmony_ci 1 << 5, 7448c2ecf20Sopenharmony_ci 1 << 6 | 1 << 8, 7458c2ecf20Sopenharmony_ci }; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci bits = pt1->power | !pt1->reset << 3; 7488c2ecf20Sopenharmony_ci mutex_lock(&pt1->lock); 7498c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) { 7508c2ecf20Sopenharmony_ci adap = pt1->adaps[i]; 7518c2ecf20Sopenharmony_ci switch (adap->voltage) { 7528c2ecf20Sopenharmony_ci case SEC_VOLTAGE_13: /* actually 11V */ 7538c2ecf20Sopenharmony_ci bits |= 1 << 2; 7548c2ecf20Sopenharmony_ci break; 7558c2ecf20Sopenharmony_ci case SEC_VOLTAGE_18: /* actually 15V */ 7568c2ecf20Sopenharmony_ci bits |= 1 << 1 | 1 << 2; 7578c2ecf20Sopenharmony_ci break; 7588c2ecf20Sopenharmony_ci default: 7598c2ecf20Sopenharmony_ci break; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* XXX: The bits should be changed depending on adap->sleep. */ 7638c2ecf20Sopenharmony_ci bits |= sleep_bits[i]; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 1, bits); 7668c2ecf20Sopenharmony_ci mutex_unlock(&pt1->lock); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic int pt1_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci adap = container_of(fe->dvb, struct pt1_adapter, adap); 7748c2ecf20Sopenharmony_ci adap->voltage = voltage; 7758c2ecf20Sopenharmony_ci pt1_update_power(adap->pt1); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (adap->orig_set_voltage) 7788c2ecf20Sopenharmony_ci return adap->orig_set_voltage(fe, voltage); 7798c2ecf20Sopenharmony_ci else 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int pt1_sleep(struct dvb_frontend *fe) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 7868c2ecf20Sopenharmony_ci int ret; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci adap = container_of(fe->dvb, struct pt1_adapter, adap); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci ret = 0; 7918c2ecf20Sopenharmony_ci if (adap->orig_sleep) 7928c2ecf20Sopenharmony_ci ret = adap->orig_sleep(fe); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci adap->sleep = 1; 7958c2ecf20Sopenharmony_ci pt1_update_power(adap->pt1); 7968c2ecf20Sopenharmony_ci return ret; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int pt1_wakeup(struct dvb_frontend *fe) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 8028c2ecf20Sopenharmony_ci int ret; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci adap = container_of(fe->dvb, struct pt1_adapter, adap); 8058c2ecf20Sopenharmony_ci adap->sleep = 0; 8068c2ecf20Sopenharmony_ci pt1_update_power(adap->pt1); 8078c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci ret = config_demod(adap->demod_i2c_client, adap->pt1->fe_clk); 8108c2ecf20Sopenharmony_ci if (ret == 0 && adap->orig_init) 8118c2ecf20Sopenharmony_ci ret = adap->orig_init(fe); 8128c2ecf20Sopenharmony_ci return ret; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic void pt1_free_adapter(struct pt1_adapter *adap) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci adap->demux.dmx.close(&adap->demux.dmx); 8188c2ecf20Sopenharmony_ci dvb_dmxdev_release(&adap->dmxdev); 8198c2ecf20Sopenharmony_ci dvb_dmx_release(&adap->demux); 8208c2ecf20Sopenharmony_ci dvb_unregister_adapter(&adap->adap); 8218c2ecf20Sopenharmony_ci free_page((unsigned long)adap->buf); 8228c2ecf20Sopenharmony_ci kfree(adap); 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic struct pt1_adapter * 8288c2ecf20Sopenharmony_cipt1_alloc_adapter(struct pt1 *pt1) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 8318c2ecf20Sopenharmony_ci void *buf; 8328c2ecf20Sopenharmony_ci struct dvb_adapter *dvb_adap; 8338c2ecf20Sopenharmony_ci struct dvb_demux *demux; 8348c2ecf20Sopenharmony_ci struct dmxdev *dmxdev; 8358c2ecf20Sopenharmony_ci int ret; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL); 8388c2ecf20Sopenharmony_ci if (!adap) { 8398c2ecf20Sopenharmony_ci ret = -ENOMEM; 8408c2ecf20Sopenharmony_ci goto err; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci adap->pt1 = pt1; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci adap->voltage = SEC_VOLTAGE_OFF; 8468c2ecf20Sopenharmony_ci adap->sleep = 1; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci buf = (u8 *)__get_free_page(GFP_KERNEL); 8498c2ecf20Sopenharmony_ci if (!buf) { 8508c2ecf20Sopenharmony_ci ret = -ENOMEM; 8518c2ecf20Sopenharmony_ci goto err_kfree; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci adap->buf = buf; 8558c2ecf20Sopenharmony_ci adap->upacket_count = 0; 8568c2ecf20Sopenharmony_ci adap->packet_count = 0; 8578c2ecf20Sopenharmony_ci adap->st_count = -1; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci dvb_adap = &adap->adap; 8608c2ecf20Sopenharmony_ci dvb_adap->priv = adap; 8618c2ecf20Sopenharmony_ci ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE, 8628c2ecf20Sopenharmony_ci &pt1->pdev->dev, adapter_nr); 8638c2ecf20Sopenharmony_ci if (ret < 0) 8648c2ecf20Sopenharmony_ci goto err_free_page; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci demux = &adap->demux; 8678c2ecf20Sopenharmony_ci demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; 8688c2ecf20Sopenharmony_ci demux->priv = adap; 8698c2ecf20Sopenharmony_ci demux->feednum = 256; 8708c2ecf20Sopenharmony_ci demux->filternum = 256; 8718c2ecf20Sopenharmony_ci demux->start_feed = pt1_start_feed; 8728c2ecf20Sopenharmony_ci demux->stop_feed = pt1_stop_feed; 8738c2ecf20Sopenharmony_ci demux->write_to_decoder = NULL; 8748c2ecf20Sopenharmony_ci ret = dvb_dmx_init(demux); 8758c2ecf20Sopenharmony_ci if (ret < 0) 8768c2ecf20Sopenharmony_ci goto err_unregister_adapter; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci dmxdev = &adap->dmxdev; 8798c2ecf20Sopenharmony_ci dmxdev->filternum = 256; 8808c2ecf20Sopenharmony_ci dmxdev->demux = &demux->dmx; 8818c2ecf20Sopenharmony_ci dmxdev->capabilities = 0; 8828c2ecf20Sopenharmony_ci ret = dvb_dmxdev_init(dmxdev, dvb_adap); 8838c2ecf20Sopenharmony_ci if (ret < 0) 8848c2ecf20Sopenharmony_ci goto err_dmx_release; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci return adap; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cierr_dmx_release: 8898c2ecf20Sopenharmony_ci dvb_dmx_release(demux); 8908c2ecf20Sopenharmony_cierr_unregister_adapter: 8918c2ecf20Sopenharmony_ci dvb_unregister_adapter(dvb_adap); 8928c2ecf20Sopenharmony_cierr_free_page: 8938c2ecf20Sopenharmony_ci free_page((unsigned long)buf); 8948c2ecf20Sopenharmony_cierr_kfree: 8958c2ecf20Sopenharmony_ci kfree(adap); 8968c2ecf20Sopenharmony_cierr: 8978c2ecf20Sopenharmony_ci return ERR_PTR(ret); 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic void pt1_cleanup_adapters(struct pt1 *pt1) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci int i; 9038c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) 9048c2ecf20Sopenharmony_ci pt1_free_adapter(pt1->adaps[i]); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic int pt1_init_adapters(struct pt1 *pt1) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci int i; 9108c2ecf20Sopenharmony_ci struct pt1_adapter *adap; 9118c2ecf20Sopenharmony_ci int ret; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) { 9148c2ecf20Sopenharmony_ci adap = pt1_alloc_adapter(pt1); 9158c2ecf20Sopenharmony_ci if (IS_ERR(adap)) { 9168c2ecf20Sopenharmony_ci ret = PTR_ERR(adap); 9178c2ecf20Sopenharmony_ci goto err; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci adap->index = i; 9218c2ecf20Sopenharmony_ci pt1->adaps[i] = adap; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cierr: 9268c2ecf20Sopenharmony_ci while (i--) 9278c2ecf20Sopenharmony_ci pt1_free_adapter(pt1->adaps[i]); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci return ret; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void pt1_cleanup_frontend(struct pt1_adapter *adap) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci dvb_unregister_frontend(adap->fe); 9358c2ecf20Sopenharmony_ci dvb_module_release(adap->tuner_i2c_client); 9368c2ecf20Sopenharmony_ci dvb_module_release(adap->demod_i2c_client); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci int ret; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci adap->orig_set_voltage = fe->ops.set_voltage; 9448c2ecf20Sopenharmony_ci adap->orig_sleep = fe->ops.sleep; 9458c2ecf20Sopenharmony_ci adap->orig_init = fe->ops.init; 9468c2ecf20Sopenharmony_ci fe->ops.set_voltage = pt1_set_voltage; 9478c2ecf20Sopenharmony_ci fe->ops.sleep = pt1_sleep; 9488c2ecf20Sopenharmony_ci fe->ops.init = pt1_wakeup; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci ret = dvb_register_frontend(&adap->adap, fe); 9518c2ecf20Sopenharmony_ci if (ret < 0) 9528c2ecf20Sopenharmony_ci return ret; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci adap->fe = fe; 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic void pt1_cleanup_frontends(struct pt1 *pt1) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci int i; 9618c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) 9628c2ecf20Sopenharmony_ci pt1_cleanup_frontend(pt1->adaps[i]); 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic int pt1_init_frontends(struct pt1 *pt1) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci int i; 9688c2ecf20Sopenharmony_ci int ret; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pt1_configs); i++) { 9718c2ecf20Sopenharmony_ci const struct i2c_board_info *info; 9728c2ecf20Sopenharmony_ci struct tc90522_config dcfg; 9738c2ecf20Sopenharmony_ci struct i2c_client *cl; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci info = &pt1_configs[i].demod_info; 9768c2ecf20Sopenharmony_ci dcfg = pt1_configs[i].demod_cfg; 9778c2ecf20Sopenharmony_ci dcfg.tuner_i2c = NULL; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci ret = -ENODEV; 9808c2ecf20Sopenharmony_ci cl = dvb_module_probe("tc90522", info->type, &pt1->i2c_adap, 9818c2ecf20Sopenharmony_ci info->addr, &dcfg); 9828c2ecf20Sopenharmony_ci if (!cl) 9838c2ecf20Sopenharmony_ci goto fe_unregister; 9848c2ecf20Sopenharmony_ci pt1->adaps[i]->demod_i2c_client = cl; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, 9878c2ecf20Sopenharmony_ci strlen(TC90522_I2C_DEV_SAT))) { 9888c2ecf20Sopenharmony_ci struct qm1d1b0004_config tcfg; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci info = &pt1_configs[i].tuner_info; 9918c2ecf20Sopenharmony_ci tcfg = pt1_configs[i].tuner_cfg.qm1d1b0004; 9928c2ecf20Sopenharmony_ci tcfg.fe = dcfg.fe; 9938c2ecf20Sopenharmony_ci cl = dvb_module_probe("qm1d1b0004", 9948c2ecf20Sopenharmony_ci info->type, dcfg.tuner_i2c, 9958c2ecf20Sopenharmony_ci info->addr, &tcfg); 9968c2ecf20Sopenharmony_ci } else { 9978c2ecf20Sopenharmony_ci struct dvb_pll_config tcfg; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci info = &pt1_configs[i].tuner_info; 10008c2ecf20Sopenharmony_ci tcfg = pt1_configs[i].tuner_cfg.tda6651; 10018c2ecf20Sopenharmony_ci tcfg.fe = dcfg.fe; 10028c2ecf20Sopenharmony_ci cl = dvb_module_probe("dvb_pll", 10038c2ecf20Sopenharmony_ci info->type, dcfg.tuner_i2c, 10048c2ecf20Sopenharmony_ci info->addr, &tcfg); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci if (!cl) 10078c2ecf20Sopenharmony_ci goto demod_release; 10088c2ecf20Sopenharmony_ci pt1->adaps[i]->tuner_i2c_client = cl; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci ret = pt1_init_frontend(pt1->adaps[i], dcfg.fe); 10118c2ecf20Sopenharmony_ci if (ret < 0) 10128c2ecf20Sopenharmony_ci goto tuner_release; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci ret = pt1_demod_block_init(pt1); 10168c2ecf20Sopenharmony_ci if (ret < 0) 10178c2ecf20Sopenharmony_ci goto fe_unregister; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return 0; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cituner_release: 10228c2ecf20Sopenharmony_ci dvb_module_release(pt1->adaps[i]->tuner_i2c_client); 10238c2ecf20Sopenharmony_cidemod_release: 10248c2ecf20Sopenharmony_ci dvb_module_release(pt1->adaps[i]->demod_i2c_client); 10258c2ecf20Sopenharmony_cife_unregister: 10268c2ecf20Sopenharmony_ci dev_warn(&pt1->pdev->dev, "failed to init FE(%d).\n", i); 10278c2ecf20Sopenharmony_ci i--; 10288c2ecf20Sopenharmony_ci for (; i >= 0; i--) { 10298c2ecf20Sopenharmony_ci dvb_unregister_frontend(pt1->adaps[i]->fe); 10308c2ecf20Sopenharmony_ci dvb_module_release(pt1->adaps[i]->tuner_i2c_client); 10318c2ecf20Sopenharmony_ci dvb_module_release(pt1->adaps[i]->demod_i2c_client); 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci return ret; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cistatic void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable, 10378c2ecf20Sopenharmony_ci int clock, int data, int next_addr) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 | 10408c2ecf20Sopenharmony_ci !clock << 11 | !data << 10 | next_addr); 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr, 1, 0, 0, data, addr + 1); 10468c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2); 10478c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3); 10488c2ecf20Sopenharmony_ci *addrp = addr + 3; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr, 1, 0, 0, 1, addr + 1); 10548c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2); 10558c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3); 10568c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4); 10578c2ecf20Sopenharmony_ci *addrp = addr + 4; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci int i; 10638c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 10648c2ecf20Sopenharmony_ci pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1); 10658c2ecf20Sopenharmony_ci pt1_i2c_write_bit(pt1, addr, &addr, 1); 10668c2ecf20Sopenharmony_ci *addrp = addr; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci int i; 10728c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 10738c2ecf20Sopenharmony_ci pt1_i2c_read_bit(pt1, addr, &addr); 10748c2ecf20Sopenharmony_ci pt1_i2c_write_bit(pt1, addr, &addr, last); 10758c2ecf20Sopenharmony_ci *addrp = addr; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); 10818c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); 10828c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3); 10838c2ecf20Sopenharmony_ci *addrp = addr + 3; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic void 10878c2ecf20Sopenharmony_cipt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci int i; 10908c2ecf20Sopenharmony_ci pt1_i2c_prepare(pt1, addr, &addr); 10918c2ecf20Sopenharmony_ci pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1); 10928c2ecf20Sopenharmony_ci for (i = 0; i < msg->len; i++) 10938c2ecf20Sopenharmony_ci pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]); 10948c2ecf20Sopenharmony_ci *addrp = addr; 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic void 10988c2ecf20Sopenharmony_cipt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci int i; 11018c2ecf20Sopenharmony_ci pt1_i2c_prepare(pt1, addr, &addr); 11028c2ecf20Sopenharmony_ci pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1); 11038c2ecf20Sopenharmony_ci for (i = 0; i < msg->len; i++) 11048c2ecf20Sopenharmony_ci pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1); 11058c2ecf20Sopenharmony_ci *addrp = addr; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic int pt1_i2c_end(struct pt1 *pt1, int addr) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr, 1, 0, 0, 0, addr + 1); 11118c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); 11128c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci pt1_write_reg(pt1, 0, 0x00000004); 11158c2ecf20Sopenharmony_ci do { 11168c2ecf20Sopenharmony_ci if (signal_pending(current)) 11178c2ecf20Sopenharmony_ci return -EINTR; 11188c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 11198c2ecf20Sopenharmony_ci } while (pt1_read_reg(pt1, 0) & 0x00000080); 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic void pt1_i2c_begin(struct pt1 *pt1, int *addrp) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci int addr; 11268c2ecf20Sopenharmony_ci addr = 0; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */); 11298c2ecf20Sopenharmony_ci addr = addr + 1; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (!pt1->i2c_running) { 11328c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1); 11338c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2); 11348c2ecf20Sopenharmony_ci addr = addr + 2; 11358c2ecf20Sopenharmony_ci pt1->i2c_running = 1; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci *addrp = addr; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci struct pt1 *pt1; 11438c2ecf20Sopenharmony_ci int i; 11448c2ecf20Sopenharmony_ci struct i2c_msg *msg, *next_msg; 11458c2ecf20Sopenharmony_ci int addr, ret; 11468c2ecf20Sopenharmony_ci u16 len; 11478c2ecf20Sopenharmony_ci u32 word; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci pt1 = i2c_get_adapdata(adap); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 11528c2ecf20Sopenharmony_ci msg = &msgs[i]; 11538c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_RD) 11548c2ecf20Sopenharmony_ci return -ENOTSUPP; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (i + 1 < num) 11578c2ecf20Sopenharmony_ci next_msg = &msgs[i + 1]; 11588c2ecf20Sopenharmony_ci else 11598c2ecf20Sopenharmony_ci next_msg = NULL; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (next_msg && next_msg->flags & I2C_M_RD) { 11628c2ecf20Sopenharmony_ci i++; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci len = next_msg->len; 11658c2ecf20Sopenharmony_ci if (len > 4) 11668c2ecf20Sopenharmony_ci return -ENOTSUPP; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci pt1_i2c_begin(pt1, &addr); 11698c2ecf20Sopenharmony_ci pt1_i2c_write_msg(pt1, addr, &addr, msg); 11708c2ecf20Sopenharmony_ci pt1_i2c_read_msg(pt1, addr, &addr, next_msg); 11718c2ecf20Sopenharmony_ci ret = pt1_i2c_end(pt1, addr); 11728c2ecf20Sopenharmony_ci if (ret < 0) 11738c2ecf20Sopenharmony_ci return ret; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci word = pt1_read_reg(pt1, 2); 11768c2ecf20Sopenharmony_ci while (len--) { 11778c2ecf20Sopenharmony_ci next_msg->buf[len] = word; 11788c2ecf20Sopenharmony_ci word >>= 8; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci } else { 11818c2ecf20Sopenharmony_ci pt1_i2c_begin(pt1, &addr); 11828c2ecf20Sopenharmony_ci pt1_i2c_write_msg(pt1, addr, &addr, msg); 11838c2ecf20Sopenharmony_ci ret = pt1_i2c_end(pt1, addr); 11848c2ecf20Sopenharmony_ci if (ret < 0) 11858c2ecf20Sopenharmony_ci return ret; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci return num; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic u32 pt1_i2c_func(struct i2c_adapter *adap) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci return I2C_FUNC_I2C; 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_cistatic const struct i2c_algorithm pt1_i2c_algo = { 11988c2ecf20Sopenharmony_ci .master_xfer = pt1_i2c_xfer, 11998c2ecf20Sopenharmony_ci .functionality = pt1_i2c_func, 12008c2ecf20Sopenharmony_ci}; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic void pt1_i2c_wait(struct pt1 *pt1) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci int i; 12058c2ecf20Sopenharmony_ci for (i = 0; i < 128; i++) 12068c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0); 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic void pt1_i2c_init(struct pt1 *pt1) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci int i; 12128c2ecf20Sopenharmony_ci for (i = 0; i < 1024; i++) 12138c2ecf20Sopenharmony_ci pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0); 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_cistatic int pt1_suspend(struct device *dev) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci struct pt1 *pt1 = dev_get_drvdata(dev); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci pt1_init_streams(pt1); 12238c2ecf20Sopenharmony_ci pt1_disable_ram(pt1); 12248c2ecf20Sopenharmony_ci pt1->power = 0; 12258c2ecf20Sopenharmony_ci pt1->reset = 1; 12268c2ecf20Sopenharmony_ci pt1_update_power(pt1); 12278c2ecf20Sopenharmony_ci return 0; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic int pt1_resume(struct device *dev) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct pt1 *pt1 = dev_get_drvdata(dev); 12338c2ecf20Sopenharmony_ci int ret; 12348c2ecf20Sopenharmony_ci int i; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci pt1->power = 0; 12378c2ecf20Sopenharmony_ci pt1->reset = 1; 12388c2ecf20Sopenharmony_ci pt1_update_power(pt1); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci pt1_i2c_init(pt1); 12418c2ecf20Sopenharmony_ci pt1_i2c_wait(pt1); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci ret = pt1_sync(pt1); 12448c2ecf20Sopenharmony_ci if (ret < 0) 12458c2ecf20Sopenharmony_ci goto resume_err; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci pt1_identify(pt1); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci ret = pt1_unlock(pt1); 12508c2ecf20Sopenharmony_ci if (ret < 0) 12518c2ecf20Sopenharmony_ci goto resume_err; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci ret = pt1_reset_pci(pt1); 12548c2ecf20Sopenharmony_ci if (ret < 0) 12558c2ecf20Sopenharmony_ci goto resume_err; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci ret = pt1_reset_ram(pt1); 12588c2ecf20Sopenharmony_ci if (ret < 0) 12598c2ecf20Sopenharmony_ci goto resume_err; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci ret = pt1_enable_ram(pt1); 12628c2ecf20Sopenharmony_ci if (ret < 0) 12638c2ecf20Sopenharmony_ci goto resume_err; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci pt1_init_streams(pt1); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci pt1->power = 1; 12688c2ecf20Sopenharmony_ci pt1_update_power(pt1); 12698c2ecf20Sopenharmony_ci msleep(20); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci pt1->reset = 0; 12728c2ecf20Sopenharmony_ci pt1_update_power(pt1); 12738c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci ret = pt1_demod_block_init(pt1); 12768c2ecf20Sopenharmony_ci if (ret < 0) 12778c2ecf20Sopenharmony_ci goto resume_err; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) 12808c2ecf20Sopenharmony_ci dvb_frontend_reinitialise(pt1->adaps[i]->fe); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci pt1_init_table_count(pt1); 12838c2ecf20Sopenharmony_ci for (i = 0; i < pt1_nr_tables; i++) { 12848c2ecf20Sopenharmony_ci int j; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci for (j = 0; j < PT1_NR_BUFS; j++) 12878c2ecf20Sopenharmony_ci pt1->tables[i].bufs[j].page->upackets[PT1_NR_UPACKETS-1] 12888c2ecf20Sopenharmony_ci = 0; 12898c2ecf20Sopenharmony_ci pt1_increment_table_count(pt1); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci pt1_register_tables(pt1, pt1->tables[0].addr >> PT1_PAGE_SHIFT); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci pt1->table_index = 0; 12948c2ecf20Sopenharmony_ci pt1->buf_index = 0; 12958c2ecf20Sopenharmony_ci for (i = 0; i < PT1_NR_ADAPS; i++) { 12968c2ecf20Sopenharmony_ci pt1->adaps[i]->upacket_count = 0; 12978c2ecf20Sopenharmony_ci pt1->adaps[i]->packet_count = 0; 12988c2ecf20Sopenharmony_ci pt1->adaps[i]->st_count = -1; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci return 0; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ciresume_err: 13048c2ecf20Sopenharmony_ci dev_info(&pt1->pdev->dev, "failed to resume PT1/PT2."); 13058c2ecf20Sopenharmony_ci return 0; /* resume anyway */ 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic void pt1_remove(struct pci_dev *pdev) 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci struct pt1 *pt1; 13138c2ecf20Sopenharmony_ci void __iomem *regs; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci pt1 = pci_get_drvdata(pdev); 13168c2ecf20Sopenharmony_ci regs = pt1->regs; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci if (pt1->kthread) 13198c2ecf20Sopenharmony_ci kthread_stop(pt1->kthread); 13208c2ecf20Sopenharmony_ci pt1_cleanup_tables(pt1); 13218c2ecf20Sopenharmony_ci pt1_cleanup_frontends(pt1); 13228c2ecf20Sopenharmony_ci pt1_disable_ram(pt1); 13238c2ecf20Sopenharmony_ci pt1->power = 0; 13248c2ecf20Sopenharmony_ci pt1->reset = 1; 13258c2ecf20Sopenharmony_ci pt1_update_power(pt1); 13268c2ecf20Sopenharmony_ci pt1_cleanup_adapters(pt1); 13278c2ecf20Sopenharmony_ci i2c_del_adapter(&pt1->i2c_adap); 13288c2ecf20Sopenharmony_ci kfree(pt1); 13298c2ecf20Sopenharmony_ci pci_iounmap(pdev, regs); 13308c2ecf20Sopenharmony_ci pci_release_regions(pdev); 13318c2ecf20Sopenharmony_ci pci_disable_device(pdev); 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_cistatic int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci int ret; 13378c2ecf20Sopenharmony_ci void __iomem *regs; 13388c2ecf20Sopenharmony_ci struct pt1 *pt1; 13398c2ecf20Sopenharmony_ci struct i2c_adapter *i2c_adap; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 13428c2ecf20Sopenharmony_ci if (ret < 0) 13438c2ecf20Sopenharmony_ci goto err; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 13468c2ecf20Sopenharmony_ci if (ret < 0) 13478c2ecf20Sopenharmony_ci goto err_pci_disable_device; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci pci_set_master(pdev); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci ret = pci_request_regions(pdev, DRIVER_NAME); 13528c2ecf20Sopenharmony_ci if (ret < 0) 13538c2ecf20Sopenharmony_ci goto err_pci_disable_device; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci regs = pci_iomap(pdev, 0, 0); 13568c2ecf20Sopenharmony_ci if (!regs) { 13578c2ecf20Sopenharmony_ci ret = -EIO; 13588c2ecf20Sopenharmony_ci goto err_pci_release_regions; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL); 13628c2ecf20Sopenharmony_ci if (!pt1) { 13638c2ecf20Sopenharmony_ci ret = -ENOMEM; 13648c2ecf20Sopenharmony_ci goto err_pci_iounmap; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci mutex_init(&pt1->lock); 13688c2ecf20Sopenharmony_ci pt1->pdev = pdev; 13698c2ecf20Sopenharmony_ci pt1->regs = regs; 13708c2ecf20Sopenharmony_ci pt1->fe_clk = (pdev->device == 0x211a) ? 13718c2ecf20Sopenharmony_ci PT1_FE_CLK_20MHZ : PT1_FE_CLK_25MHZ; 13728c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, pt1); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci ret = pt1_init_adapters(pt1); 13758c2ecf20Sopenharmony_ci if (ret < 0) 13768c2ecf20Sopenharmony_ci goto err_kfree; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci mutex_init(&pt1->lock); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci pt1->power = 0; 13818c2ecf20Sopenharmony_ci pt1->reset = 1; 13828c2ecf20Sopenharmony_ci pt1_update_power(pt1); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci i2c_adap = &pt1->i2c_adap; 13858c2ecf20Sopenharmony_ci i2c_adap->algo = &pt1_i2c_algo; 13868c2ecf20Sopenharmony_ci i2c_adap->algo_data = NULL; 13878c2ecf20Sopenharmony_ci i2c_adap->dev.parent = &pdev->dev; 13888c2ecf20Sopenharmony_ci strscpy(i2c_adap->name, DRIVER_NAME, sizeof(i2c_adap->name)); 13898c2ecf20Sopenharmony_ci i2c_set_adapdata(i2c_adap, pt1); 13908c2ecf20Sopenharmony_ci ret = i2c_add_adapter(i2c_adap); 13918c2ecf20Sopenharmony_ci if (ret < 0) 13928c2ecf20Sopenharmony_ci goto err_pt1_cleanup_adapters; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci pt1_i2c_init(pt1); 13958c2ecf20Sopenharmony_ci pt1_i2c_wait(pt1); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci ret = pt1_sync(pt1); 13988c2ecf20Sopenharmony_ci if (ret < 0) 13998c2ecf20Sopenharmony_ci goto err_i2c_del_adapter; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci pt1_identify(pt1); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci ret = pt1_unlock(pt1); 14048c2ecf20Sopenharmony_ci if (ret < 0) 14058c2ecf20Sopenharmony_ci goto err_i2c_del_adapter; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci ret = pt1_reset_pci(pt1); 14088c2ecf20Sopenharmony_ci if (ret < 0) 14098c2ecf20Sopenharmony_ci goto err_i2c_del_adapter; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci ret = pt1_reset_ram(pt1); 14128c2ecf20Sopenharmony_ci if (ret < 0) 14138c2ecf20Sopenharmony_ci goto err_i2c_del_adapter; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci ret = pt1_enable_ram(pt1); 14168c2ecf20Sopenharmony_ci if (ret < 0) 14178c2ecf20Sopenharmony_ci goto err_i2c_del_adapter; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci pt1_init_streams(pt1); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci pt1->power = 1; 14228c2ecf20Sopenharmony_ci pt1_update_power(pt1); 14238c2ecf20Sopenharmony_ci msleep(20); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci pt1->reset = 0; 14268c2ecf20Sopenharmony_ci pt1_update_power(pt1); 14278c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci ret = pt1_init_frontends(pt1); 14308c2ecf20Sopenharmony_ci if (ret < 0) 14318c2ecf20Sopenharmony_ci goto err_pt1_disable_ram; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci ret = pt1_init_tables(pt1); 14348c2ecf20Sopenharmony_ci if (ret < 0) 14358c2ecf20Sopenharmony_ci goto err_pt1_cleanup_frontends; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci return 0; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cierr_pt1_cleanup_frontends: 14408c2ecf20Sopenharmony_ci pt1_cleanup_frontends(pt1); 14418c2ecf20Sopenharmony_cierr_pt1_disable_ram: 14428c2ecf20Sopenharmony_ci pt1_disable_ram(pt1); 14438c2ecf20Sopenharmony_ci pt1->power = 0; 14448c2ecf20Sopenharmony_ci pt1->reset = 1; 14458c2ecf20Sopenharmony_ci pt1_update_power(pt1); 14468c2ecf20Sopenharmony_cierr_i2c_del_adapter: 14478c2ecf20Sopenharmony_ci i2c_del_adapter(i2c_adap); 14488c2ecf20Sopenharmony_cierr_pt1_cleanup_adapters: 14498c2ecf20Sopenharmony_ci pt1_cleanup_adapters(pt1); 14508c2ecf20Sopenharmony_cierr_kfree: 14518c2ecf20Sopenharmony_ci kfree(pt1); 14528c2ecf20Sopenharmony_cierr_pci_iounmap: 14538c2ecf20Sopenharmony_ci pci_iounmap(pdev, regs); 14548c2ecf20Sopenharmony_cierr_pci_release_regions: 14558c2ecf20Sopenharmony_ci pci_release_regions(pdev); 14568c2ecf20Sopenharmony_cierr_pci_disable_device: 14578c2ecf20Sopenharmony_ci pci_disable_device(pdev); 14588c2ecf20Sopenharmony_cierr: 14598c2ecf20Sopenharmony_ci return ret; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic const struct pci_device_id pt1_id_table[] = { 14648c2ecf20Sopenharmony_ci { PCI_DEVICE(0x10ee, 0x211a) }, 14658c2ecf20Sopenharmony_ci { PCI_DEVICE(0x10ee, 0x222a) }, 14668c2ecf20Sopenharmony_ci { }, 14678c2ecf20Sopenharmony_ci}; 14688c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pt1_id_table); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pt1_pm_ops, pt1_suspend, pt1_resume); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic struct pci_driver pt1_driver = { 14738c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 14748c2ecf20Sopenharmony_ci .probe = pt1_probe, 14758c2ecf20Sopenharmony_ci .remove = pt1_remove, 14768c2ecf20Sopenharmony_ci .id_table = pt1_id_table, 14778c2ecf20Sopenharmony_ci .driver.pm = &pt1_pm_ops, 14788c2ecf20Sopenharmony_ci}; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_cimodule_pci_driver(pt1_driver); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>"); 14838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver"); 14848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1485