162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * driver for Earthsoft PT1/PT2
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * based on pt1dvr - http://pt1dvr.sourceforge.jp/
862306a36Sopenharmony_ci *	by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/sched.h>
1362306a36Sopenharmony_ci#include <linux/sched/signal.h>
1462306a36Sopenharmony_ci#include <linux/hrtimer.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/vmalloc.h>
1962306a36Sopenharmony_ci#include <linux/pci.h>
2062306a36Sopenharmony_ci#include <linux/kthread.h>
2162306a36Sopenharmony_ci#include <linux/freezer.h>
2262306a36Sopenharmony_ci#include <linux/ratelimit.h>
2362306a36Sopenharmony_ci#include <linux/string.h>
2462306a36Sopenharmony_ci#include <linux/i2c.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <media/dvbdev.h>
2762306a36Sopenharmony_ci#include <media/dvb_demux.h>
2862306a36Sopenharmony_ci#include <media/dmxdev.h>
2962306a36Sopenharmony_ci#include <media/dvb_net.h>
3062306a36Sopenharmony_ci#include <media/dvb_frontend.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "tc90522.h"
3362306a36Sopenharmony_ci#include "qm1d1b0004.h"
3462306a36Sopenharmony_ci#include "dvb-pll.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define DRIVER_NAME "earth-pt1"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define PT1_PAGE_SHIFT 12
3962306a36Sopenharmony_ci#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT)
4062306a36Sopenharmony_ci#define PT1_NR_UPACKETS 1024
4162306a36Sopenharmony_ci#define PT1_NR_BUFS 511
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct pt1_buffer_page {
4462306a36Sopenharmony_ci	__le32 upackets[PT1_NR_UPACKETS];
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct pt1_table_page {
4862306a36Sopenharmony_ci	__le32 next_pfn;
4962306a36Sopenharmony_ci	__le32 buf_pfns[PT1_NR_BUFS];
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct pt1_buffer {
5362306a36Sopenharmony_ci	struct pt1_buffer_page *page;
5462306a36Sopenharmony_ci	dma_addr_t addr;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct pt1_table {
5862306a36Sopenharmony_ci	struct pt1_table_page *page;
5962306a36Sopenharmony_ci	dma_addr_t addr;
6062306a36Sopenharmony_ci	struct pt1_buffer bufs[PT1_NR_BUFS];
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cienum pt1_fe_clk {
6462306a36Sopenharmony_ci	PT1_FE_CLK_20MHZ,	/* PT1 */
6562306a36Sopenharmony_ci	PT1_FE_CLK_25MHZ,	/* PT2 */
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define PT1_NR_ADAPS 4
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistruct pt1_adapter;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct pt1 {
7362306a36Sopenharmony_ci	struct pci_dev *pdev;
7462306a36Sopenharmony_ci	void __iomem *regs;
7562306a36Sopenharmony_ci	struct i2c_adapter i2c_adap;
7662306a36Sopenharmony_ci	int i2c_running;
7762306a36Sopenharmony_ci	struct pt1_adapter *adaps[PT1_NR_ADAPS];
7862306a36Sopenharmony_ci	struct pt1_table *tables;
7962306a36Sopenharmony_ci	struct task_struct *kthread;
8062306a36Sopenharmony_ci	int table_index;
8162306a36Sopenharmony_ci	int buf_index;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	struct mutex lock;
8462306a36Sopenharmony_ci	int power;
8562306a36Sopenharmony_ci	int reset;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	enum pt1_fe_clk fe_clk;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct pt1_adapter {
9162306a36Sopenharmony_ci	struct pt1 *pt1;
9262306a36Sopenharmony_ci	int index;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	u8 *buf;
9562306a36Sopenharmony_ci	int upacket_count;
9662306a36Sopenharmony_ci	int packet_count;
9762306a36Sopenharmony_ci	int st_count;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	struct dvb_adapter adap;
10062306a36Sopenharmony_ci	struct dvb_demux demux;
10162306a36Sopenharmony_ci	int users;
10262306a36Sopenharmony_ci	struct dmxdev dmxdev;
10362306a36Sopenharmony_ci	struct dvb_frontend *fe;
10462306a36Sopenharmony_ci	struct i2c_client *demod_i2c_client;
10562306a36Sopenharmony_ci	struct i2c_client *tuner_i2c_client;
10662306a36Sopenharmony_ci	int (*orig_set_voltage)(struct dvb_frontend *fe,
10762306a36Sopenharmony_ci				enum fe_sec_voltage voltage);
10862306a36Sopenharmony_ci	int (*orig_sleep)(struct dvb_frontend *fe);
10962306a36Sopenharmony_ci	int (*orig_init)(struct dvb_frontend *fe);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	enum fe_sec_voltage voltage;
11262306a36Sopenharmony_ci	int sleep;
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciunion pt1_tuner_config {
11662306a36Sopenharmony_ci	struct qm1d1b0004_config qm1d1b0004;
11762306a36Sopenharmony_ci	struct dvb_pll_config tda6651;
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct pt1_config {
12162306a36Sopenharmony_ci	struct i2c_board_info demod_info;
12262306a36Sopenharmony_ci	struct tc90522_config demod_cfg;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	struct i2c_board_info tuner_info;
12562306a36Sopenharmony_ci	union pt1_tuner_config tuner_cfg;
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic const struct pt1_config pt1_configs[PT1_NR_ADAPS] = {
12962306a36Sopenharmony_ci	{
13062306a36Sopenharmony_ci		.demod_info = {
13162306a36Sopenharmony_ci			I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x1b),
13262306a36Sopenharmony_ci		},
13362306a36Sopenharmony_ci		.tuner_info = {
13462306a36Sopenharmony_ci			I2C_BOARD_INFO("qm1d1b0004", 0x60),
13562306a36Sopenharmony_ci		},
13662306a36Sopenharmony_ci	},
13762306a36Sopenharmony_ci	{
13862306a36Sopenharmony_ci		.demod_info = {
13962306a36Sopenharmony_ci			I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x1a),
14062306a36Sopenharmony_ci		},
14162306a36Sopenharmony_ci		.tuner_info = {
14262306a36Sopenharmony_ci			I2C_BOARD_INFO("tda665x_earthpt1", 0x61),
14362306a36Sopenharmony_ci		},
14462306a36Sopenharmony_ci	},
14562306a36Sopenharmony_ci	{
14662306a36Sopenharmony_ci		.demod_info = {
14762306a36Sopenharmony_ci			I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x19),
14862306a36Sopenharmony_ci		},
14962306a36Sopenharmony_ci		.tuner_info = {
15062306a36Sopenharmony_ci			I2C_BOARD_INFO("qm1d1b0004", 0x60),
15162306a36Sopenharmony_ci		},
15262306a36Sopenharmony_ci	},
15362306a36Sopenharmony_ci	{
15462306a36Sopenharmony_ci		.demod_info = {
15562306a36Sopenharmony_ci			I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x18),
15662306a36Sopenharmony_ci		},
15762306a36Sopenharmony_ci		.tuner_info = {
15862306a36Sopenharmony_ci			I2C_BOARD_INFO("tda665x_earthpt1", 0x61),
15962306a36Sopenharmony_ci		},
16062306a36Sopenharmony_ci	},
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic const u8 va1j5jf8007s_20mhz_configs[][2] = {
16462306a36Sopenharmony_ci	{0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},
16562306a36Sopenharmony_ci	{0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},
16662306a36Sopenharmony_ci	{0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},
16762306a36Sopenharmony_ci	{0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic const u8 va1j5jf8007s_25mhz_configs[][2] = {
17162306a36Sopenharmony_ci	{0x04, 0x02}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01}, {0x1c, 0x0a},
17262306a36Sopenharmony_ci	{0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0}, {0x52, 0x89},
17362306a36Sopenharmony_ci	{0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69}, {0x87, 0x04},
17462306a36Sopenharmony_ci	{0x8e, 0x26}, {0xa3, 0xf7}, {0xa5, 0xc0},
17562306a36Sopenharmony_ci};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic const u8 va1j5jf8007t_20mhz_configs[][2] = {
17862306a36Sopenharmony_ci	{0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
17962306a36Sopenharmony_ci	{0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
18062306a36Sopenharmony_ci	{0x3b, 0x11}, {0x3c, 0x3f},
18162306a36Sopenharmony_ci	{0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
18262306a36Sopenharmony_ci	{0xef, 0x01}
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic const u8 va1j5jf8007t_25mhz_configs[][2] = {
18662306a36Sopenharmony_ci	{0x03, 0x90}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2}, {0x22, 0x83},
18762306a36Sopenharmony_ci	{0x3a, 0x04}, {0x3b, 0x11}, {0x3c, 0x3f}, {0x5c, 0x40}, {0x5f, 0x80},
18862306a36Sopenharmony_ci	{0x75, 0x0a}, {0x76, 0x4c}, {0x77, 0x03}, {0xef, 0x01}
18962306a36Sopenharmony_ci};
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	int ret;
19462306a36Sopenharmony_ci	bool is_sat;
19562306a36Sopenharmony_ci	const u8 (*cfg_data)[2];
19662306a36Sopenharmony_ci	int i, len;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	is_sat = !strncmp(cl->name, TC90522_I2C_DEV_SAT,
19962306a36Sopenharmony_ci			  strlen(TC90522_I2C_DEV_SAT));
20062306a36Sopenharmony_ci	if (is_sat) {
20162306a36Sopenharmony_ci		struct i2c_msg msg[2];
20262306a36Sopenharmony_ci		u8 wbuf, rbuf;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		wbuf = 0x07;
20562306a36Sopenharmony_ci		msg[0].addr = cl->addr;
20662306a36Sopenharmony_ci		msg[0].flags = 0;
20762306a36Sopenharmony_ci		msg[0].len = 1;
20862306a36Sopenharmony_ci		msg[0].buf = &wbuf;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		msg[1].addr = cl->addr;
21162306a36Sopenharmony_ci		msg[1].flags = I2C_M_RD;
21262306a36Sopenharmony_ci		msg[1].len = 1;
21362306a36Sopenharmony_ci		msg[1].buf = &rbuf;
21462306a36Sopenharmony_ci		ret = i2c_transfer(cl->adapter, msg, 2);
21562306a36Sopenharmony_ci		if (ret < 0)
21662306a36Sopenharmony_ci			return ret;
21762306a36Sopenharmony_ci		if (rbuf != 0x41)
21862306a36Sopenharmony_ci			return -EIO;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* frontend init */
22262306a36Sopenharmony_ci	if (clk == PT1_FE_CLK_20MHZ) {
22362306a36Sopenharmony_ci		if (is_sat) {
22462306a36Sopenharmony_ci			cfg_data = va1j5jf8007s_20mhz_configs;
22562306a36Sopenharmony_ci			len = ARRAY_SIZE(va1j5jf8007s_20mhz_configs);
22662306a36Sopenharmony_ci		} else {
22762306a36Sopenharmony_ci			cfg_data = va1j5jf8007t_20mhz_configs;
22862306a36Sopenharmony_ci			len = ARRAY_SIZE(va1j5jf8007t_20mhz_configs);
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci	} else {
23162306a36Sopenharmony_ci		if (is_sat) {
23262306a36Sopenharmony_ci			cfg_data = va1j5jf8007s_25mhz_configs;
23362306a36Sopenharmony_ci			len = ARRAY_SIZE(va1j5jf8007s_25mhz_configs);
23462306a36Sopenharmony_ci		} else {
23562306a36Sopenharmony_ci			cfg_data = va1j5jf8007t_25mhz_configs;
23662306a36Sopenharmony_ci			len = ARRAY_SIZE(va1j5jf8007t_25mhz_configs);
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
24162306a36Sopenharmony_ci		ret = i2c_master_send(cl, cfg_data[i], 2);
24262306a36Sopenharmony_ci		if (ret < 0)
24362306a36Sopenharmony_ci			return ret;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	return 0;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/*
24962306a36Sopenharmony_ci * Init registers for (each pair of) terrestrial/satellite block in demod.
25062306a36Sopenharmony_ci * Note that resetting terr. block also resets its peer sat. block as well.
25162306a36Sopenharmony_ci * This function must be called before configuring any demod block
25262306a36Sopenharmony_ci * (before pt1_wakeup(), fe->ops.init()).
25362306a36Sopenharmony_ci */
25462306a36Sopenharmony_cistatic int pt1_demod_block_init(struct pt1 *pt1)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct i2c_client *cl;
25762306a36Sopenharmony_ci	u8 buf[2] = {0x01, 0x80};
25862306a36Sopenharmony_ci	int ret;
25962306a36Sopenharmony_ci	int i;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* reset all terr. & sat. pairs first */
26262306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++) {
26362306a36Sopenharmony_ci		cl = pt1->adaps[i]->demod_i2c_client;
26462306a36Sopenharmony_ci		if (strncmp(cl->name, TC90522_I2C_DEV_TER,
26562306a36Sopenharmony_ci			    strlen(TC90522_I2C_DEV_TER)))
26662306a36Sopenharmony_ci			continue;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		ret = i2c_master_send(cl, buf, 2);
26962306a36Sopenharmony_ci		if (ret < 0)
27062306a36Sopenharmony_ci			return ret;
27162306a36Sopenharmony_ci		usleep_range(30000, 50000);
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++) {
27562306a36Sopenharmony_ci		cl = pt1->adaps[i]->demod_i2c_client;
27662306a36Sopenharmony_ci		if (strncmp(cl->name, TC90522_I2C_DEV_SAT,
27762306a36Sopenharmony_ci			    strlen(TC90522_I2C_DEV_SAT)))
27862306a36Sopenharmony_ci			continue;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci		ret = i2c_master_send(cl, buf, 2);
28162306a36Sopenharmony_ci		if (ret < 0)
28262306a36Sopenharmony_ci			return ret;
28362306a36Sopenharmony_ci		usleep_range(30000, 50000);
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	writel(data, pt1->regs + reg * 4);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic u32 pt1_read_reg(struct pt1 *pt1, int reg)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	return readl(pt1->regs + reg * 4);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic unsigned int pt1_nr_tables = 8;
29962306a36Sopenharmony_cimodule_param_named(nr_tables, pt1_nr_tables, uint, 0);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic void pt1_increment_table_count(struct pt1 *pt1)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x00000020);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void pt1_init_table_count(struct pt1 *pt1)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x00000010);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic void pt1_register_tables(struct pt1 *pt1, u32 first_pfn)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	pt1_write_reg(pt1, 5, first_pfn);
31462306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x0c000040);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic void pt1_unregister_tables(struct pt1 *pt1)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x08080000);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic int pt1_sync(struct pt1 *pt1)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	int i;
32562306a36Sopenharmony_ci	for (i = 0; i < 57; i++) {
32662306a36Sopenharmony_ci		if (pt1_read_reg(pt1, 0) & 0x20000000)
32762306a36Sopenharmony_ci			return 0;
32862306a36Sopenharmony_ci		pt1_write_reg(pt1, 0, 0x00000008);
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci	dev_err(&pt1->pdev->dev, "could not sync\n");
33162306a36Sopenharmony_ci	return -EIO;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic u64 pt1_identify(struct pt1 *pt1)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	int i;
33762306a36Sopenharmony_ci	u64 id = 0;
33862306a36Sopenharmony_ci	for (i = 0; i < 57; i++) {
33962306a36Sopenharmony_ci		id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i;
34062306a36Sopenharmony_ci		pt1_write_reg(pt1, 0, 0x00000008);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	return id;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int pt1_unlock(struct pt1 *pt1)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int i;
34862306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x00000008);
34962306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
35062306a36Sopenharmony_ci		if (pt1_read_reg(pt1, 0) & 0x80000000)
35162306a36Sopenharmony_ci			return 0;
35262306a36Sopenharmony_ci		usleep_range(1000, 2000);
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci	dev_err(&pt1->pdev->dev, "could not unlock\n");
35562306a36Sopenharmony_ci	return -EIO;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int pt1_reset_pci(struct pt1 *pt1)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	int i;
36162306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x01010000);
36262306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x01000000);
36362306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
36462306a36Sopenharmony_ci		if (pt1_read_reg(pt1, 0) & 0x00000001)
36562306a36Sopenharmony_ci			return 0;
36662306a36Sopenharmony_ci		usleep_range(1000, 2000);
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci	dev_err(&pt1->pdev->dev, "could not reset PCI\n");
36962306a36Sopenharmony_ci	return -EIO;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int pt1_reset_ram(struct pt1 *pt1)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	int i;
37562306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x02020000);
37662306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x02000000);
37762306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
37862306a36Sopenharmony_ci		if (pt1_read_reg(pt1, 0) & 0x00000002)
37962306a36Sopenharmony_ci			return 0;
38062306a36Sopenharmony_ci		usleep_range(1000, 2000);
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci	dev_err(&pt1->pdev->dev, "could not reset RAM\n");
38362306a36Sopenharmony_ci	return -EIO;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic int pt1_do_enable_ram(struct pt1 *pt1)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	int i, j;
38962306a36Sopenharmony_ci	u32 status;
39062306a36Sopenharmony_ci	status = pt1_read_reg(pt1, 0) & 0x00000004;
39162306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x00000002);
39262306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
39362306a36Sopenharmony_ci		for (j = 0; j < 1024; j++) {
39462306a36Sopenharmony_ci			if ((pt1_read_reg(pt1, 0) & 0x00000004) != status)
39562306a36Sopenharmony_ci				return 0;
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci		usleep_range(1000, 2000);
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci	dev_err(&pt1->pdev->dev, "could not enable RAM\n");
40062306a36Sopenharmony_ci	return -EIO;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int pt1_enable_ram(struct pt1 *pt1)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	int i, ret;
40662306a36Sopenharmony_ci	int phase;
40762306a36Sopenharmony_ci	usleep_range(1000, 2000);
40862306a36Sopenharmony_ci	phase = pt1->pdev->device == 0x211a ? 128 : 166;
40962306a36Sopenharmony_ci	for (i = 0; i < phase; i++) {
41062306a36Sopenharmony_ci		ret = pt1_do_enable_ram(pt1);
41162306a36Sopenharmony_ci		if (ret < 0)
41262306a36Sopenharmony_ci			return ret;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci	return 0;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic void pt1_disable_ram(struct pt1 *pt1)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x0b0b0000);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic void pt1_set_stream(struct pt1 *pt1, int index, int enabled)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic void pt1_init_streams(struct pt1 *pt1)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	int i;
43062306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++)
43162306a36Sopenharmony_ci		pt1_set_stream(pt1, i, 0);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	u32 upacket;
43762306a36Sopenharmony_ci	int i;
43862306a36Sopenharmony_ci	int index;
43962306a36Sopenharmony_ci	struct pt1_adapter *adap;
44062306a36Sopenharmony_ci	int offset;
44162306a36Sopenharmony_ci	u8 *buf;
44262306a36Sopenharmony_ci	int sc;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (!page->upackets[PT1_NR_UPACKETS - 1])
44562306a36Sopenharmony_ci		return 0;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_UPACKETS; i++) {
44862306a36Sopenharmony_ci		upacket = le32_to_cpu(page->upackets[i]);
44962306a36Sopenharmony_ci		index = (upacket >> 29) - 1;
45062306a36Sopenharmony_ci		if (index < 0 || index >=  PT1_NR_ADAPS)
45162306a36Sopenharmony_ci			continue;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		adap = pt1->adaps[index];
45462306a36Sopenharmony_ci		if (upacket >> 25 & 1)
45562306a36Sopenharmony_ci			adap->upacket_count = 0;
45662306a36Sopenharmony_ci		else if (!adap->upacket_count)
45762306a36Sopenharmony_ci			continue;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (upacket >> 24 & 1)
46062306a36Sopenharmony_ci			printk_ratelimited(KERN_INFO "earth-pt1: device buffer overflowing. table[%d] buf[%d]\n",
46162306a36Sopenharmony_ci				pt1->table_index, pt1->buf_index);
46262306a36Sopenharmony_ci		sc = upacket >> 26 & 0x7;
46362306a36Sopenharmony_ci		if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7))
46462306a36Sopenharmony_ci			printk_ratelimited(KERN_INFO "earth-pt1: data loss in streamID(adapter)[%d]\n",
46562306a36Sopenharmony_ci					   index);
46662306a36Sopenharmony_ci		adap->st_count = sc;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		buf = adap->buf;
46962306a36Sopenharmony_ci		offset = adap->packet_count * 188 + adap->upacket_count * 3;
47062306a36Sopenharmony_ci		buf[offset] = upacket >> 16;
47162306a36Sopenharmony_ci		buf[offset + 1] = upacket >> 8;
47262306a36Sopenharmony_ci		if (adap->upacket_count != 62)
47362306a36Sopenharmony_ci			buf[offset + 2] = upacket;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		if (++adap->upacket_count >= 63) {
47662306a36Sopenharmony_ci			adap->upacket_count = 0;
47762306a36Sopenharmony_ci			if (++adap->packet_count >= 21) {
47862306a36Sopenharmony_ci				dvb_dmx_swfilter_packets(&adap->demux, buf, 21);
47962306a36Sopenharmony_ci				adap->packet_count = 0;
48062306a36Sopenharmony_ci			}
48162306a36Sopenharmony_ci		}
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	page->upackets[PT1_NR_UPACKETS - 1] = 0;
48562306a36Sopenharmony_ci	return 1;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic int pt1_thread(void *data)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct pt1 *pt1;
49162306a36Sopenharmony_ci	struct pt1_buffer_page *page;
49262306a36Sopenharmony_ci	bool was_frozen;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci#define PT1_FETCH_DELAY 10
49562306a36Sopenharmony_ci#define PT1_FETCH_DELAY_DELTA 2
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	pt1 = data;
49862306a36Sopenharmony_ci	set_freezable();
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	while (!kthread_freezable_should_stop(&was_frozen)) {
50162306a36Sopenharmony_ci		if (was_frozen) {
50262306a36Sopenharmony_ci			int i;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci			for (i = 0; i < PT1_NR_ADAPS; i++)
50562306a36Sopenharmony_ci				pt1_set_stream(pt1, i, !!pt1->adaps[i]->users);
50662306a36Sopenharmony_ci		}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page;
50962306a36Sopenharmony_ci		if (!pt1_filter(pt1, page)) {
51062306a36Sopenharmony_ci			ktime_t delay;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci			delay = ktime_set(0, PT1_FETCH_DELAY * NSEC_PER_MSEC);
51362306a36Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE);
51462306a36Sopenharmony_ci			schedule_hrtimeout_range(&delay,
51562306a36Sopenharmony_ci					PT1_FETCH_DELAY_DELTA * NSEC_PER_MSEC,
51662306a36Sopenharmony_ci					HRTIMER_MODE_REL);
51762306a36Sopenharmony_ci			continue;
51862306a36Sopenharmony_ci		}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		if (++pt1->buf_index >= PT1_NR_BUFS) {
52162306a36Sopenharmony_ci			pt1_increment_table_count(pt1);
52262306a36Sopenharmony_ci			pt1->buf_index = 0;
52362306a36Sopenharmony_ci			if (++pt1->table_index >= pt1_nr_tables)
52462306a36Sopenharmony_ci				pt1->table_index = 0;
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return 0;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	void *page;
53962306a36Sopenharmony_ci	dma_addr_t addr;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr,
54262306a36Sopenharmony_ci				  GFP_KERNEL);
54362306a36Sopenharmony_ci	if (page == NULL)
54462306a36Sopenharmony_ci		return NULL;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	BUG_ON(addr & (PT1_PAGE_SIZE - 1));
54762306a36Sopenharmony_ci	BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	*addrp = addr;
55062306a36Sopenharmony_ci	*pfnp = addr >> PT1_PAGE_SHIFT;
55162306a36Sopenharmony_ci	return page;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	pt1_free_page(pt1, buf->page, buf->addr);
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic int
56062306a36Sopenharmony_cipt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf,  u32 *pfnp)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct pt1_buffer_page *page;
56362306a36Sopenharmony_ci	dma_addr_t addr;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	page = pt1_alloc_page(pt1, &addr, pfnp);
56662306a36Sopenharmony_ci	if (page == NULL)
56762306a36Sopenharmony_ci		return -ENOMEM;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	page->upackets[PT1_NR_UPACKETS - 1] = 0;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	buf->page = page;
57262306a36Sopenharmony_ci	buf->addr = addr;
57362306a36Sopenharmony_ci	return 0;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	int i;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_BUFS; i++)
58162306a36Sopenharmony_ci		pt1_cleanup_buffer(pt1, &table->bufs[i]);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	pt1_free_page(pt1, table->page, table->addr);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic int
58762306a36Sopenharmony_cipt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	struct pt1_table_page *page;
59062306a36Sopenharmony_ci	dma_addr_t addr;
59162306a36Sopenharmony_ci	int i, ret;
59262306a36Sopenharmony_ci	u32 buf_pfn;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	page = pt1_alloc_page(pt1, &addr, pfnp);
59562306a36Sopenharmony_ci	if (page == NULL)
59662306a36Sopenharmony_ci		return -ENOMEM;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_BUFS; i++) {
59962306a36Sopenharmony_ci		ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn);
60062306a36Sopenharmony_ci		if (ret < 0)
60162306a36Sopenharmony_ci			goto err;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci		page->buf_pfns[i] = cpu_to_le32(buf_pfn);
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	pt1_increment_table_count(pt1);
60762306a36Sopenharmony_ci	table->page = page;
60862306a36Sopenharmony_ci	table->addr = addr;
60962306a36Sopenharmony_ci	return 0;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cierr:
61262306a36Sopenharmony_ci	while (i--)
61362306a36Sopenharmony_ci		pt1_cleanup_buffer(pt1, &table->bufs[i]);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	pt1_free_page(pt1, page, addr);
61662306a36Sopenharmony_ci	return ret;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic void pt1_cleanup_tables(struct pt1 *pt1)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	struct pt1_table *tables;
62262306a36Sopenharmony_ci	int i;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	tables = pt1->tables;
62562306a36Sopenharmony_ci	pt1_unregister_tables(pt1);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	for (i = 0; i < pt1_nr_tables; i++)
62862306a36Sopenharmony_ci		pt1_cleanup_table(pt1, &tables[i]);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	vfree(tables);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int pt1_init_tables(struct pt1 *pt1)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct pt1_table *tables;
63662306a36Sopenharmony_ci	int i, ret;
63762306a36Sopenharmony_ci	u32 first_pfn, pfn;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (!pt1_nr_tables)
64062306a36Sopenharmony_ci		return 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	tables = vmalloc(array_size(pt1_nr_tables, sizeof(struct pt1_table)));
64362306a36Sopenharmony_ci	if (tables == NULL)
64462306a36Sopenharmony_ci		return -ENOMEM;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	pt1_init_table_count(pt1);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	i = 0;
64962306a36Sopenharmony_ci	ret = pt1_init_table(pt1, &tables[0], &first_pfn);
65062306a36Sopenharmony_ci	if (ret)
65162306a36Sopenharmony_ci		goto err;
65262306a36Sopenharmony_ci	i++;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	while (i < pt1_nr_tables) {
65562306a36Sopenharmony_ci		ret = pt1_init_table(pt1, &tables[i], &pfn);
65662306a36Sopenharmony_ci		if (ret)
65762306a36Sopenharmony_ci			goto err;
65862306a36Sopenharmony_ci		tables[i - 1].page->next_pfn = cpu_to_le32(pfn);
65962306a36Sopenharmony_ci		i++;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	pt1_register_tables(pt1, first_pfn);
66562306a36Sopenharmony_ci	pt1->tables = tables;
66662306a36Sopenharmony_ci	return 0;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cierr:
66962306a36Sopenharmony_ci	while (i--)
67062306a36Sopenharmony_ci		pt1_cleanup_table(pt1, &tables[i]);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	vfree(tables);
67362306a36Sopenharmony_ci	return ret;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic int pt1_start_polling(struct pt1 *pt1)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	int ret = 0;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	mutex_lock(&pt1->lock);
68162306a36Sopenharmony_ci	if (!pt1->kthread) {
68262306a36Sopenharmony_ci		pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1");
68362306a36Sopenharmony_ci		if (IS_ERR(pt1->kthread)) {
68462306a36Sopenharmony_ci			ret = PTR_ERR(pt1->kthread);
68562306a36Sopenharmony_ci			pt1->kthread = NULL;
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci	mutex_unlock(&pt1->lock);
68962306a36Sopenharmony_ci	return ret;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic int pt1_start_feed(struct dvb_demux_feed *feed)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct pt1_adapter *adap;
69562306a36Sopenharmony_ci	adap = container_of(feed->demux, struct pt1_adapter, demux);
69662306a36Sopenharmony_ci	if (!adap->users++) {
69762306a36Sopenharmony_ci		int ret;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		ret = pt1_start_polling(adap->pt1);
70062306a36Sopenharmony_ci		if (ret)
70162306a36Sopenharmony_ci			return ret;
70262306a36Sopenharmony_ci		pt1_set_stream(adap->pt1, adap->index, 1);
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci	return 0;
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic void pt1_stop_polling(struct pt1 *pt1)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	int i, count;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	mutex_lock(&pt1->lock);
71262306a36Sopenharmony_ci	for (i = 0, count = 0; i < PT1_NR_ADAPS; i++)
71362306a36Sopenharmony_ci		count += pt1->adaps[i]->users;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (count == 0 && pt1->kthread) {
71662306a36Sopenharmony_ci		kthread_stop(pt1->kthread);
71762306a36Sopenharmony_ci		pt1->kthread = NULL;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci	mutex_unlock(&pt1->lock);
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic int pt1_stop_feed(struct dvb_demux_feed *feed)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	struct pt1_adapter *adap;
72562306a36Sopenharmony_ci	adap = container_of(feed->demux, struct pt1_adapter, demux);
72662306a36Sopenharmony_ci	if (!--adap->users) {
72762306a36Sopenharmony_ci		pt1_set_stream(adap->pt1, adap->index, 0);
72862306a36Sopenharmony_ci		pt1_stop_polling(adap->pt1);
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci	return 0;
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic void
73462306a36Sopenharmony_cipt1_update_power(struct pt1 *pt1)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	int bits;
73762306a36Sopenharmony_ci	int i;
73862306a36Sopenharmony_ci	struct pt1_adapter *adap;
73962306a36Sopenharmony_ci	static const int sleep_bits[] = {
74062306a36Sopenharmony_ci		1 << 4,
74162306a36Sopenharmony_ci		1 << 6 | 1 << 7,
74262306a36Sopenharmony_ci		1 << 5,
74362306a36Sopenharmony_ci		1 << 6 | 1 << 8,
74462306a36Sopenharmony_ci	};
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	bits = pt1->power | !pt1->reset << 3;
74762306a36Sopenharmony_ci	mutex_lock(&pt1->lock);
74862306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++) {
74962306a36Sopenharmony_ci		adap = pt1->adaps[i];
75062306a36Sopenharmony_ci		switch (adap->voltage) {
75162306a36Sopenharmony_ci		case SEC_VOLTAGE_13: /* actually 11V */
75262306a36Sopenharmony_ci			bits |= 1 << 2;
75362306a36Sopenharmony_ci			break;
75462306a36Sopenharmony_ci		case SEC_VOLTAGE_18: /* actually 15V */
75562306a36Sopenharmony_ci			bits |= 1 << 1 | 1 << 2;
75662306a36Sopenharmony_ci			break;
75762306a36Sopenharmony_ci		default:
75862306a36Sopenharmony_ci			break;
75962306a36Sopenharmony_ci		}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		/* XXX: The bits should be changed depending on adap->sleep. */
76262306a36Sopenharmony_ci		bits |= sleep_bits[i];
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci	pt1_write_reg(pt1, 1, bits);
76562306a36Sopenharmony_ci	mutex_unlock(&pt1->lock);
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic int pt1_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct pt1_adapter *adap;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	adap = container_of(fe->dvb, struct pt1_adapter, adap);
77362306a36Sopenharmony_ci	adap->voltage = voltage;
77462306a36Sopenharmony_ci	pt1_update_power(adap->pt1);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (adap->orig_set_voltage)
77762306a36Sopenharmony_ci		return adap->orig_set_voltage(fe, voltage);
77862306a36Sopenharmony_ci	else
77962306a36Sopenharmony_ci		return 0;
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic int pt1_sleep(struct dvb_frontend *fe)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	struct pt1_adapter *adap;
78562306a36Sopenharmony_ci	int ret;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	adap = container_of(fe->dvb, struct pt1_adapter, adap);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	ret = 0;
79062306a36Sopenharmony_ci	if (adap->orig_sleep)
79162306a36Sopenharmony_ci		ret = adap->orig_sleep(fe);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	adap->sleep = 1;
79462306a36Sopenharmony_ci	pt1_update_power(adap->pt1);
79562306a36Sopenharmony_ci	return ret;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic int pt1_wakeup(struct dvb_frontend *fe)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	struct pt1_adapter *adap;
80162306a36Sopenharmony_ci	int ret;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	adap = container_of(fe->dvb, struct pt1_adapter, adap);
80462306a36Sopenharmony_ci	adap->sleep = 0;
80562306a36Sopenharmony_ci	pt1_update_power(adap->pt1);
80662306a36Sopenharmony_ci	usleep_range(1000, 2000);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	ret = config_demod(adap->demod_i2c_client, adap->pt1->fe_clk);
80962306a36Sopenharmony_ci	if (ret == 0 && adap->orig_init)
81062306a36Sopenharmony_ci		ret = adap->orig_init(fe);
81162306a36Sopenharmony_ci	return ret;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void pt1_free_adapter(struct pt1_adapter *adap)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	adap->demux.dmx.close(&adap->demux.dmx);
81762306a36Sopenharmony_ci	dvb_dmxdev_release(&adap->dmxdev);
81862306a36Sopenharmony_ci	dvb_dmx_release(&adap->demux);
81962306a36Sopenharmony_ci	dvb_unregister_adapter(&adap->adap);
82062306a36Sopenharmony_ci	free_page((unsigned long)adap->buf);
82162306a36Sopenharmony_ci	kfree(adap);
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic struct pt1_adapter *
82762306a36Sopenharmony_cipt1_alloc_adapter(struct pt1 *pt1)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct pt1_adapter *adap;
83062306a36Sopenharmony_ci	void *buf;
83162306a36Sopenharmony_ci	struct dvb_adapter *dvb_adap;
83262306a36Sopenharmony_ci	struct dvb_demux *demux;
83362306a36Sopenharmony_ci	struct dmxdev *dmxdev;
83462306a36Sopenharmony_ci	int ret;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL);
83762306a36Sopenharmony_ci	if (!adap) {
83862306a36Sopenharmony_ci		ret = -ENOMEM;
83962306a36Sopenharmony_ci		goto err;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	adap->pt1 = pt1;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	adap->voltage = SEC_VOLTAGE_OFF;
84562306a36Sopenharmony_ci	adap->sleep = 1;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	buf = (u8 *)__get_free_page(GFP_KERNEL);
84862306a36Sopenharmony_ci	if (!buf) {
84962306a36Sopenharmony_ci		ret = -ENOMEM;
85062306a36Sopenharmony_ci		goto err_kfree;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	adap->buf = buf;
85462306a36Sopenharmony_ci	adap->upacket_count = 0;
85562306a36Sopenharmony_ci	adap->packet_count = 0;
85662306a36Sopenharmony_ci	adap->st_count = -1;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	dvb_adap = &adap->adap;
85962306a36Sopenharmony_ci	dvb_adap->priv = adap;
86062306a36Sopenharmony_ci	ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE,
86162306a36Sopenharmony_ci				   &pt1->pdev->dev, adapter_nr);
86262306a36Sopenharmony_ci	if (ret < 0)
86362306a36Sopenharmony_ci		goto err_free_page;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	demux = &adap->demux;
86662306a36Sopenharmony_ci	demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
86762306a36Sopenharmony_ci	demux->priv = adap;
86862306a36Sopenharmony_ci	demux->feednum = 256;
86962306a36Sopenharmony_ci	demux->filternum = 256;
87062306a36Sopenharmony_ci	demux->start_feed = pt1_start_feed;
87162306a36Sopenharmony_ci	demux->stop_feed = pt1_stop_feed;
87262306a36Sopenharmony_ci	demux->write_to_decoder = NULL;
87362306a36Sopenharmony_ci	ret = dvb_dmx_init(demux);
87462306a36Sopenharmony_ci	if (ret < 0)
87562306a36Sopenharmony_ci		goto err_unregister_adapter;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	dmxdev = &adap->dmxdev;
87862306a36Sopenharmony_ci	dmxdev->filternum = 256;
87962306a36Sopenharmony_ci	dmxdev->demux = &demux->dmx;
88062306a36Sopenharmony_ci	dmxdev->capabilities = 0;
88162306a36Sopenharmony_ci	ret = dvb_dmxdev_init(dmxdev, dvb_adap);
88262306a36Sopenharmony_ci	if (ret < 0)
88362306a36Sopenharmony_ci		goto err_dmx_release;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return adap;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_cierr_dmx_release:
88862306a36Sopenharmony_ci	dvb_dmx_release(demux);
88962306a36Sopenharmony_cierr_unregister_adapter:
89062306a36Sopenharmony_ci	dvb_unregister_adapter(dvb_adap);
89162306a36Sopenharmony_cierr_free_page:
89262306a36Sopenharmony_ci	free_page((unsigned long)buf);
89362306a36Sopenharmony_cierr_kfree:
89462306a36Sopenharmony_ci	kfree(adap);
89562306a36Sopenharmony_cierr:
89662306a36Sopenharmony_ci	return ERR_PTR(ret);
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic void pt1_cleanup_adapters(struct pt1 *pt1)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	int i;
90262306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++)
90362306a36Sopenharmony_ci		pt1_free_adapter(pt1->adaps[i]);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic int pt1_init_adapters(struct pt1 *pt1)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	int i;
90962306a36Sopenharmony_ci	struct pt1_adapter *adap;
91062306a36Sopenharmony_ci	int ret;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++) {
91362306a36Sopenharmony_ci		adap = pt1_alloc_adapter(pt1);
91462306a36Sopenharmony_ci		if (IS_ERR(adap)) {
91562306a36Sopenharmony_ci			ret = PTR_ERR(adap);
91662306a36Sopenharmony_ci			goto err;
91762306a36Sopenharmony_ci		}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		adap->index = i;
92062306a36Sopenharmony_ci		pt1->adaps[i] = adap;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci	return 0;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cierr:
92562306a36Sopenharmony_ci	while (i--)
92662306a36Sopenharmony_ci		pt1_free_adapter(pt1->adaps[i]);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	return ret;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic void pt1_cleanup_frontend(struct pt1_adapter *adap)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	dvb_unregister_frontend(adap->fe);
93462306a36Sopenharmony_ci	dvb_module_release(adap->tuner_i2c_client);
93562306a36Sopenharmony_ci	dvb_module_release(adap->demod_i2c_client);
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int pt1_init_frontend(struct pt1_adapter *adap, struct dvb_frontend *fe)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	int ret;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	adap->orig_set_voltage = fe->ops.set_voltage;
94362306a36Sopenharmony_ci	adap->orig_sleep = fe->ops.sleep;
94462306a36Sopenharmony_ci	adap->orig_init = fe->ops.init;
94562306a36Sopenharmony_ci	fe->ops.set_voltage = pt1_set_voltage;
94662306a36Sopenharmony_ci	fe->ops.sleep = pt1_sleep;
94762306a36Sopenharmony_ci	fe->ops.init = pt1_wakeup;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	ret = dvb_register_frontend(&adap->adap, fe);
95062306a36Sopenharmony_ci	if (ret < 0)
95162306a36Sopenharmony_ci		return ret;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	adap->fe = fe;
95462306a36Sopenharmony_ci	return 0;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic void pt1_cleanup_frontends(struct pt1 *pt1)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	int i;
96062306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++)
96162306a36Sopenharmony_ci		pt1_cleanup_frontend(pt1->adaps[i]);
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic int pt1_init_frontends(struct pt1 *pt1)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	int i;
96762306a36Sopenharmony_ci	int ret;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pt1_configs); i++) {
97062306a36Sopenharmony_ci		const struct i2c_board_info *info;
97162306a36Sopenharmony_ci		struct tc90522_config dcfg;
97262306a36Sopenharmony_ci		struct i2c_client *cl;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci		info = &pt1_configs[i].demod_info;
97562306a36Sopenharmony_ci		dcfg = pt1_configs[i].demod_cfg;
97662306a36Sopenharmony_ci		dcfg.tuner_i2c = NULL;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		ret = -ENODEV;
97962306a36Sopenharmony_ci		cl = dvb_module_probe("tc90522", info->type, &pt1->i2c_adap,
98062306a36Sopenharmony_ci				      info->addr, &dcfg);
98162306a36Sopenharmony_ci		if (!cl)
98262306a36Sopenharmony_ci			goto fe_unregister;
98362306a36Sopenharmony_ci		pt1->adaps[i]->demod_i2c_client = cl;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		if (!strncmp(cl->name, TC90522_I2C_DEV_SAT,
98662306a36Sopenharmony_ci			     strlen(TC90522_I2C_DEV_SAT))) {
98762306a36Sopenharmony_ci			struct qm1d1b0004_config tcfg;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci			info = &pt1_configs[i].tuner_info;
99062306a36Sopenharmony_ci			tcfg = pt1_configs[i].tuner_cfg.qm1d1b0004;
99162306a36Sopenharmony_ci			tcfg.fe = dcfg.fe;
99262306a36Sopenharmony_ci			cl = dvb_module_probe("qm1d1b0004",
99362306a36Sopenharmony_ci					      info->type, dcfg.tuner_i2c,
99462306a36Sopenharmony_ci					      info->addr, &tcfg);
99562306a36Sopenharmony_ci		} else {
99662306a36Sopenharmony_ci			struct dvb_pll_config tcfg;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci			info = &pt1_configs[i].tuner_info;
99962306a36Sopenharmony_ci			tcfg = pt1_configs[i].tuner_cfg.tda6651;
100062306a36Sopenharmony_ci			tcfg.fe = dcfg.fe;
100162306a36Sopenharmony_ci			cl = dvb_module_probe("dvb_pll",
100262306a36Sopenharmony_ci					      info->type, dcfg.tuner_i2c,
100362306a36Sopenharmony_ci					      info->addr, &tcfg);
100462306a36Sopenharmony_ci		}
100562306a36Sopenharmony_ci		if (!cl)
100662306a36Sopenharmony_ci			goto demod_release;
100762306a36Sopenharmony_ci		pt1->adaps[i]->tuner_i2c_client = cl;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci		ret = pt1_init_frontend(pt1->adaps[i], dcfg.fe);
101062306a36Sopenharmony_ci		if (ret < 0)
101162306a36Sopenharmony_ci			goto tuner_release;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	ret = pt1_demod_block_init(pt1);
101562306a36Sopenharmony_ci	if (ret < 0)
101662306a36Sopenharmony_ci		goto fe_unregister;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	return 0;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cituner_release:
102162306a36Sopenharmony_ci	dvb_module_release(pt1->adaps[i]->tuner_i2c_client);
102262306a36Sopenharmony_cidemod_release:
102362306a36Sopenharmony_ci	dvb_module_release(pt1->adaps[i]->demod_i2c_client);
102462306a36Sopenharmony_cife_unregister:
102562306a36Sopenharmony_ci	dev_warn(&pt1->pdev->dev, "failed to init FE(%d).\n", i);
102662306a36Sopenharmony_ci	i--;
102762306a36Sopenharmony_ci	for (; i >= 0; i--) {
102862306a36Sopenharmony_ci		dvb_unregister_frontend(pt1->adaps[i]->fe);
102962306a36Sopenharmony_ci		dvb_module_release(pt1->adaps[i]->tuner_i2c_client);
103062306a36Sopenharmony_ci		dvb_module_release(pt1->adaps[i]->demod_i2c_client);
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci	return ret;
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable,
103662306a36Sopenharmony_ci			 int clock, int data, int next_addr)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 |
103962306a36Sopenharmony_ci		      !clock << 11 | !data << 10 | next_addr);
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr,     1, 0, 0, data, addr + 1);
104562306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2);
104662306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3);
104762306a36Sopenharmony_ci	*addrp = addr + 3;
104862306a36Sopenharmony_ci}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_cistatic void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr,     1, 0, 0, 1, addr + 1);
105362306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2);
105462306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3);
105562306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4);
105662306a36Sopenharmony_ci	*addrp = addr + 4;
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_cistatic void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data)
106062306a36Sopenharmony_ci{
106162306a36Sopenharmony_ci	int i;
106262306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
106362306a36Sopenharmony_ci		pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1);
106462306a36Sopenharmony_ci	pt1_i2c_write_bit(pt1, addr, &addr, 1);
106562306a36Sopenharmony_ci	*addrp = addr;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	int i;
107162306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
107262306a36Sopenharmony_ci		pt1_i2c_read_bit(pt1, addr, &addr);
107362306a36Sopenharmony_ci	pt1_i2c_write_bit(pt1, addr, &addr, last);
107462306a36Sopenharmony_ci	*addrp = addr;
107562306a36Sopenharmony_ci}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_cistatic void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr,     1, 0, 1, 1, addr + 1);
108062306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
108162306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3);
108262306a36Sopenharmony_ci	*addrp = addr + 3;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic void
108662306a36Sopenharmony_cipt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	int i;
108962306a36Sopenharmony_ci	pt1_i2c_prepare(pt1, addr, &addr);
109062306a36Sopenharmony_ci	pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1);
109162306a36Sopenharmony_ci	for (i = 0; i < msg->len; i++)
109262306a36Sopenharmony_ci		pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]);
109362306a36Sopenharmony_ci	*addrp = addr;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic void
109762306a36Sopenharmony_cipt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	int i;
110062306a36Sopenharmony_ci	pt1_i2c_prepare(pt1, addr, &addr);
110162306a36Sopenharmony_ci	pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1);
110262306a36Sopenharmony_ci	for (i = 0; i < msg->len; i++)
110362306a36Sopenharmony_ci		pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1);
110462306a36Sopenharmony_ci	*addrp = addr;
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic int pt1_i2c_end(struct pt1 *pt1, int addr)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr,     1, 0, 0, 0, addr + 1);
111062306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
111162306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	pt1_write_reg(pt1, 0, 0x00000004);
111462306a36Sopenharmony_ci	do {
111562306a36Sopenharmony_ci		if (signal_pending(current))
111662306a36Sopenharmony_ci			return -EINTR;
111762306a36Sopenharmony_ci		usleep_range(1000, 2000);
111862306a36Sopenharmony_ci	} while (pt1_read_reg(pt1, 0) & 0x00000080);
111962306a36Sopenharmony_ci	return 0;
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistatic void pt1_i2c_begin(struct pt1 *pt1, int *addrp)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	int addr = 0;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	pt1_i2c_emit(pt1, addr,     0, 0, 1, 1, addr /* itself */);
112762306a36Sopenharmony_ci	addr = addr + 1;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (!pt1->i2c_running) {
113062306a36Sopenharmony_ci		pt1_i2c_emit(pt1, addr,     1, 0, 1, 1, addr + 1);
113162306a36Sopenharmony_ci		pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
113262306a36Sopenharmony_ci		addr = addr + 2;
113362306a36Sopenharmony_ci		pt1->i2c_running = 1;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci	*addrp = addr;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	struct pt1 *pt1;
114162306a36Sopenharmony_ci	int i;
114262306a36Sopenharmony_ci	struct i2c_msg *msg, *next_msg;
114362306a36Sopenharmony_ci	int addr, ret;
114462306a36Sopenharmony_ci	u16 len;
114562306a36Sopenharmony_ci	u32 word;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	pt1 = i2c_get_adapdata(adap);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
115062306a36Sopenharmony_ci		msg = &msgs[i];
115162306a36Sopenharmony_ci		if (msg->flags & I2C_M_RD)
115262306a36Sopenharmony_ci			return -ENOTSUPP;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci		if (i + 1 < num)
115562306a36Sopenharmony_ci			next_msg = &msgs[i + 1];
115662306a36Sopenharmony_ci		else
115762306a36Sopenharmony_ci			next_msg = NULL;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci		if (next_msg && next_msg->flags & I2C_M_RD) {
116062306a36Sopenharmony_ci			i++;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci			len = next_msg->len;
116362306a36Sopenharmony_ci			if (len > 4)
116462306a36Sopenharmony_ci				return -ENOTSUPP;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci			pt1_i2c_begin(pt1, &addr);
116762306a36Sopenharmony_ci			pt1_i2c_write_msg(pt1, addr, &addr, msg);
116862306a36Sopenharmony_ci			pt1_i2c_read_msg(pt1, addr, &addr, next_msg);
116962306a36Sopenharmony_ci			ret = pt1_i2c_end(pt1, addr);
117062306a36Sopenharmony_ci			if (ret < 0)
117162306a36Sopenharmony_ci				return ret;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci			word = pt1_read_reg(pt1, 2);
117462306a36Sopenharmony_ci			while (len--) {
117562306a36Sopenharmony_ci				next_msg->buf[len] = word;
117662306a36Sopenharmony_ci				word >>= 8;
117762306a36Sopenharmony_ci			}
117862306a36Sopenharmony_ci		} else {
117962306a36Sopenharmony_ci			pt1_i2c_begin(pt1, &addr);
118062306a36Sopenharmony_ci			pt1_i2c_write_msg(pt1, addr, &addr, msg);
118162306a36Sopenharmony_ci			ret = pt1_i2c_end(pt1, addr);
118262306a36Sopenharmony_ci			if (ret < 0)
118362306a36Sopenharmony_ci				return ret;
118462306a36Sopenharmony_ci		}
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	return num;
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic u32 pt1_i2c_func(struct i2c_adapter *adap)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	return I2C_FUNC_I2C;
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic const struct i2c_algorithm pt1_i2c_algo = {
119662306a36Sopenharmony_ci	.master_xfer = pt1_i2c_xfer,
119762306a36Sopenharmony_ci	.functionality = pt1_i2c_func,
119862306a36Sopenharmony_ci};
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic void pt1_i2c_wait(struct pt1 *pt1)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	int i;
120362306a36Sopenharmony_ci	for (i = 0; i < 128; i++)
120462306a36Sopenharmony_ci		pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0);
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_cistatic void pt1_i2c_init(struct pt1 *pt1)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	int i;
121062306a36Sopenharmony_ci	for (i = 0; i < 1024; i++)
121162306a36Sopenharmony_ci		pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0);
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic int pt1_suspend(struct device *dev)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	struct pt1 *pt1 = dev_get_drvdata(dev);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	pt1_init_streams(pt1);
122162306a36Sopenharmony_ci	pt1_disable_ram(pt1);
122262306a36Sopenharmony_ci	pt1->power = 0;
122362306a36Sopenharmony_ci	pt1->reset = 1;
122462306a36Sopenharmony_ci	pt1_update_power(pt1);
122562306a36Sopenharmony_ci	return 0;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int pt1_resume(struct device *dev)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct pt1 *pt1 = dev_get_drvdata(dev);
123162306a36Sopenharmony_ci	int ret;
123262306a36Sopenharmony_ci	int i;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	pt1->power = 0;
123562306a36Sopenharmony_ci	pt1->reset = 1;
123662306a36Sopenharmony_ci	pt1_update_power(pt1);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	pt1_i2c_init(pt1);
123962306a36Sopenharmony_ci	pt1_i2c_wait(pt1);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	ret = pt1_sync(pt1);
124262306a36Sopenharmony_ci	if (ret < 0)
124362306a36Sopenharmony_ci		goto resume_err;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	pt1_identify(pt1);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	ret = pt1_unlock(pt1);
124862306a36Sopenharmony_ci	if (ret < 0)
124962306a36Sopenharmony_ci		goto resume_err;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	ret = pt1_reset_pci(pt1);
125262306a36Sopenharmony_ci	if (ret < 0)
125362306a36Sopenharmony_ci		goto resume_err;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	ret = pt1_reset_ram(pt1);
125662306a36Sopenharmony_ci	if (ret < 0)
125762306a36Sopenharmony_ci		goto resume_err;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	ret = pt1_enable_ram(pt1);
126062306a36Sopenharmony_ci	if (ret < 0)
126162306a36Sopenharmony_ci		goto resume_err;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	pt1_init_streams(pt1);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	pt1->power = 1;
126662306a36Sopenharmony_ci	pt1_update_power(pt1);
126762306a36Sopenharmony_ci	msleep(20);
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	pt1->reset = 0;
127062306a36Sopenharmony_ci	pt1_update_power(pt1);
127162306a36Sopenharmony_ci	usleep_range(1000, 2000);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	ret = pt1_demod_block_init(pt1);
127462306a36Sopenharmony_ci	if (ret < 0)
127562306a36Sopenharmony_ci		goto resume_err;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++)
127862306a36Sopenharmony_ci		dvb_frontend_reinitialise(pt1->adaps[i]->fe);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	pt1_init_table_count(pt1);
128162306a36Sopenharmony_ci	for (i = 0; i < pt1_nr_tables; i++) {
128262306a36Sopenharmony_ci		int j;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci		for (j = 0; j < PT1_NR_BUFS; j++)
128562306a36Sopenharmony_ci			pt1->tables[i].bufs[j].page->upackets[PT1_NR_UPACKETS-1]
128662306a36Sopenharmony_ci				= 0;
128762306a36Sopenharmony_ci		pt1_increment_table_count(pt1);
128862306a36Sopenharmony_ci	}
128962306a36Sopenharmony_ci	pt1_register_tables(pt1, pt1->tables[0].addr >> PT1_PAGE_SHIFT);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	pt1->table_index = 0;
129262306a36Sopenharmony_ci	pt1->buf_index = 0;
129362306a36Sopenharmony_ci	for (i = 0; i < PT1_NR_ADAPS; i++) {
129462306a36Sopenharmony_ci		pt1->adaps[i]->upacket_count = 0;
129562306a36Sopenharmony_ci		pt1->adaps[i]->packet_count = 0;
129662306a36Sopenharmony_ci		pt1->adaps[i]->st_count = -1;
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	return 0;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ciresume_err:
130262306a36Sopenharmony_ci	dev_info(&pt1->pdev->dev, "failed to resume PT1/PT2.");
130362306a36Sopenharmony_ci	return 0;	/* resume anyway */
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic void pt1_remove(struct pci_dev *pdev)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	struct pt1 *pt1;
131162306a36Sopenharmony_ci	void __iomem *regs;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	pt1 = pci_get_drvdata(pdev);
131462306a36Sopenharmony_ci	regs = pt1->regs;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (pt1->kthread)
131762306a36Sopenharmony_ci		kthread_stop(pt1->kthread);
131862306a36Sopenharmony_ci	pt1_cleanup_tables(pt1);
131962306a36Sopenharmony_ci	pt1_cleanup_frontends(pt1);
132062306a36Sopenharmony_ci	pt1_disable_ram(pt1);
132162306a36Sopenharmony_ci	pt1->power = 0;
132262306a36Sopenharmony_ci	pt1->reset = 1;
132362306a36Sopenharmony_ci	pt1_update_power(pt1);
132462306a36Sopenharmony_ci	pt1_cleanup_adapters(pt1);
132562306a36Sopenharmony_ci	i2c_del_adapter(&pt1->i2c_adap);
132662306a36Sopenharmony_ci	kfree(pt1);
132762306a36Sopenharmony_ci	pci_iounmap(pdev, regs);
132862306a36Sopenharmony_ci	pci_release_regions(pdev);
132962306a36Sopenharmony_ci	pci_disable_device(pdev);
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_cistatic int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	int ret;
133562306a36Sopenharmony_ci	void __iomem *regs;
133662306a36Sopenharmony_ci	struct pt1 *pt1;
133762306a36Sopenharmony_ci	struct i2c_adapter *i2c_adap;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
134062306a36Sopenharmony_ci	if (ret < 0)
134162306a36Sopenharmony_ci		goto err;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
134462306a36Sopenharmony_ci	if (ret < 0)
134562306a36Sopenharmony_ci		goto err_pci_disable_device;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	pci_set_master(pdev);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	ret = pci_request_regions(pdev, DRIVER_NAME);
135062306a36Sopenharmony_ci	if (ret < 0)
135162306a36Sopenharmony_ci		goto err_pci_disable_device;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	regs = pci_iomap(pdev, 0, 0);
135462306a36Sopenharmony_ci	if (!regs) {
135562306a36Sopenharmony_ci		ret = -EIO;
135662306a36Sopenharmony_ci		goto err_pci_release_regions;
135762306a36Sopenharmony_ci	}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL);
136062306a36Sopenharmony_ci	if (!pt1) {
136162306a36Sopenharmony_ci		ret = -ENOMEM;
136262306a36Sopenharmony_ci		goto err_pci_iounmap;
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	mutex_init(&pt1->lock);
136662306a36Sopenharmony_ci	pt1->pdev = pdev;
136762306a36Sopenharmony_ci	pt1->regs = regs;
136862306a36Sopenharmony_ci	pt1->fe_clk = (pdev->device == 0x211a) ?
136962306a36Sopenharmony_ci				PT1_FE_CLK_20MHZ : PT1_FE_CLK_25MHZ;
137062306a36Sopenharmony_ci	pci_set_drvdata(pdev, pt1);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	ret = pt1_init_adapters(pt1);
137362306a36Sopenharmony_ci	if (ret < 0)
137462306a36Sopenharmony_ci		goto err_kfree;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	mutex_init(&pt1->lock);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	pt1->power = 0;
137962306a36Sopenharmony_ci	pt1->reset = 1;
138062306a36Sopenharmony_ci	pt1_update_power(pt1);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	i2c_adap = &pt1->i2c_adap;
138362306a36Sopenharmony_ci	i2c_adap->algo = &pt1_i2c_algo;
138462306a36Sopenharmony_ci	i2c_adap->algo_data = NULL;
138562306a36Sopenharmony_ci	i2c_adap->dev.parent = &pdev->dev;
138662306a36Sopenharmony_ci	strscpy(i2c_adap->name, DRIVER_NAME, sizeof(i2c_adap->name));
138762306a36Sopenharmony_ci	i2c_set_adapdata(i2c_adap, pt1);
138862306a36Sopenharmony_ci	ret = i2c_add_adapter(i2c_adap);
138962306a36Sopenharmony_ci	if (ret < 0)
139062306a36Sopenharmony_ci		goto err_pt1_cleanup_adapters;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	pt1_i2c_init(pt1);
139362306a36Sopenharmony_ci	pt1_i2c_wait(pt1);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	ret = pt1_sync(pt1);
139662306a36Sopenharmony_ci	if (ret < 0)
139762306a36Sopenharmony_ci		goto err_i2c_del_adapter;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	pt1_identify(pt1);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	ret = pt1_unlock(pt1);
140262306a36Sopenharmony_ci	if (ret < 0)
140362306a36Sopenharmony_ci		goto err_i2c_del_adapter;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	ret = pt1_reset_pci(pt1);
140662306a36Sopenharmony_ci	if (ret < 0)
140762306a36Sopenharmony_ci		goto err_i2c_del_adapter;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	ret = pt1_reset_ram(pt1);
141062306a36Sopenharmony_ci	if (ret < 0)
141162306a36Sopenharmony_ci		goto err_i2c_del_adapter;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	ret = pt1_enable_ram(pt1);
141462306a36Sopenharmony_ci	if (ret < 0)
141562306a36Sopenharmony_ci		goto err_i2c_del_adapter;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	pt1_init_streams(pt1);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	pt1->power = 1;
142062306a36Sopenharmony_ci	pt1_update_power(pt1);
142162306a36Sopenharmony_ci	msleep(20);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	pt1->reset = 0;
142462306a36Sopenharmony_ci	pt1_update_power(pt1);
142562306a36Sopenharmony_ci	usleep_range(1000, 2000);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	ret = pt1_init_frontends(pt1);
142862306a36Sopenharmony_ci	if (ret < 0)
142962306a36Sopenharmony_ci		goto err_pt1_disable_ram;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	ret = pt1_init_tables(pt1);
143262306a36Sopenharmony_ci	if (ret < 0)
143362306a36Sopenharmony_ci		goto err_pt1_cleanup_frontends;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	return 0;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cierr_pt1_cleanup_frontends:
143862306a36Sopenharmony_ci	pt1_cleanup_frontends(pt1);
143962306a36Sopenharmony_cierr_pt1_disable_ram:
144062306a36Sopenharmony_ci	pt1_disable_ram(pt1);
144162306a36Sopenharmony_ci	pt1->power = 0;
144262306a36Sopenharmony_ci	pt1->reset = 1;
144362306a36Sopenharmony_ci	pt1_update_power(pt1);
144462306a36Sopenharmony_cierr_i2c_del_adapter:
144562306a36Sopenharmony_ci	i2c_del_adapter(i2c_adap);
144662306a36Sopenharmony_cierr_pt1_cleanup_adapters:
144762306a36Sopenharmony_ci	pt1_cleanup_adapters(pt1);
144862306a36Sopenharmony_cierr_kfree:
144962306a36Sopenharmony_ci	kfree(pt1);
145062306a36Sopenharmony_cierr_pci_iounmap:
145162306a36Sopenharmony_ci	pci_iounmap(pdev, regs);
145262306a36Sopenharmony_cierr_pci_release_regions:
145362306a36Sopenharmony_ci	pci_release_regions(pdev);
145462306a36Sopenharmony_cierr_pci_disable_device:
145562306a36Sopenharmony_ci	pci_disable_device(pdev);
145662306a36Sopenharmony_cierr:
145762306a36Sopenharmony_ci	return ret;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_cistatic const struct pci_device_id pt1_id_table[] = {
146262306a36Sopenharmony_ci	{ PCI_DEVICE(0x10ee, 0x211a) },
146362306a36Sopenharmony_ci	{ PCI_DEVICE(0x10ee, 0x222a) },
146462306a36Sopenharmony_ci	{ },
146562306a36Sopenharmony_ci};
146662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pt1_id_table);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pt1_pm_ops, pt1_suspend, pt1_resume);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_cistatic struct pci_driver pt1_driver = {
147162306a36Sopenharmony_ci	.name		= DRIVER_NAME,
147262306a36Sopenharmony_ci	.probe		= pt1_probe,
147362306a36Sopenharmony_ci	.remove		= pt1_remove,
147462306a36Sopenharmony_ci	.id_table	= pt1_id_table,
147562306a36Sopenharmony_ci	.driver.pm	= &pt1_pm_ops,
147662306a36Sopenharmony_ci};
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cimodule_pci_driver(pt1_driver);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ciMODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
148162306a36Sopenharmony_ciMODULE_DESCRIPTION("Earthsoft PT1/PT2 Driver");
148262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1483