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