162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
362306a36Sopenharmony_ci * DVB-T receiver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include "dibusb.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "mt352.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic int umt_mt352_demod_init(struct dvb_frontend *fe)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
1862306a36Sopenharmony_ci	static u8 mt352_reset[] = { 0x50, 0x80 };
1962306a36Sopenharmony_ci	static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
2062306a36Sopenharmony_ci	static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
2162306a36Sopenharmony_ci	static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
2462306a36Sopenharmony_ci	static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
2562306a36Sopenharmony_ci	static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
2662306a36Sopenharmony_ci	static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
2762306a36Sopenharmony_ci	static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
3062306a36Sopenharmony_ci	static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
3362306a36Sopenharmony_ci	udelay(2000);
3462306a36Sopenharmony_ci	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
3562306a36Sopenharmony_ci	mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
3862306a36Sopenharmony_ci	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
4162306a36Sopenharmony_ci	mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
4262306a36Sopenharmony_ci	mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
4362306a36Sopenharmony_ci	mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
4462306a36Sopenharmony_ci	mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
4762306a36Sopenharmony_ci	mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct mt352_config umt_config;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	memset(&umt_config,0,sizeof(struct mt352_config));
5762306a36Sopenharmony_ci	umt_config.demod_init = umt_mt352_demod_init;
5862306a36Sopenharmony_ci	umt_config.demod_address = 0xf;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	return 0;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic int umt_tuner_attach (struct dvb_usb_adapter *adap)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034);
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* USB Driver stuff */
7262306a36Sopenharmony_cistatic struct dvb_usb_device_properties umt_properties;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int umt_probe(struct usb_interface *intf,
7562306a36Sopenharmony_ci		const struct usb_device_id *id)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	if (0 == dvb_usb_device_init(intf, &umt_properties,
7862306a36Sopenharmony_ci				     THIS_MODULE, NULL, adapter_nr))
7962306a36Sopenharmony_ci		return 0;
8062306a36Sopenharmony_ci	return -EINVAL;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* do not change the order of the ID table */
8462306a36Sopenharmony_cienum {
8562306a36Sopenharmony_ci	HANFTEK_UMT_010_COLD,
8662306a36Sopenharmony_ci	HANFTEK_UMT_010_WARM,
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic struct usb_device_id umt_table[] = {
9062306a36Sopenharmony_ci	DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_COLD),
9162306a36Sopenharmony_ci	DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_WARM),
9262306a36Sopenharmony_ci	{ }
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ciMODULE_DEVICE_TABLE (usb, umt_table);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic struct dvb_usb_device_properties umt_properties = {
9862306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	.usb_ctrl = CYPRESS_FX2,
10162306a36Sopenharmony_ci	.firmware = "dvb-usb-umt-010-02.fw",
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	.num_adapters = 1,
10462306a36Sopenharmony_ci	.adapter = {
10562306a36Sopenharmony_ci		{
10662306a36Sopenharmony_ci		.num_frontends = 1,
10762306a36Sopenharmony_ci		.fe = {{
10862306a36Sopenharmony_ci			.streaming_ctrl   = dibusb2_0_streaming_ctrl,
10962306a36Sopenharmony_ci			.frontend_attach  = umt_mt352_frontend_attach,
11062306a36Sopenharmony_ci			.tuner_attach     = umt_tuner_attach,
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
11362306a36Sopenharmony_ci			.stream = {
11462306a36Sopenharmony_ci				.type = USB_BULK,
11562306a36Sopenharmony_ci				.count = MAX_NO_URBS_FOR_DATA_STREAM,
11662306a36Sopenharmony_ci				.endpoint = 0x06,
11762306a36Sopenharmony_ci				.u = {
11862306a36Sopenharmony_ci					.bulk = {
11962306a36Sopenharmony_ci						.buffersize = 512,
12062306a36Sopenharmony_ci					}
12162306a36Sopenharmony_ci				}
12262306a36Sopenharmony_ci			},
12362306a36Sopenharmony_ci		}},
12462306a36Sopenharmony_ci			.size_of_priv     = sizeof(struct dibusb_state),
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci	},
12762306a36Sopenharmony_ci	.power_ctrl       = dibusb_power_ctrl,
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	.i2c_algo         = &dibusb_i2c_algo,
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	.num_device_descs = 1,
13462306a36Sopenharmony_ci	.devices = {
13562306a36Sopenharmony_ci		{	"Hanftek UMT-010 DVB-T USB2.0",
13662306a36Sopenharmony_ci			{ &umt_table[HANFTEK_UMT_010_COLD], NULL },
13762306a36Sopenharmony_ci			{ &umt_table[HANFTEK_UMT_010_WARM], NULL },
13862306a36Sopenharmony_ci		},
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic struct usb_driver umt_driver = {
14362306a36Sopenharmony_ci	.name		= "dvb_usb_umt_010",
14462306a36Sopenharmony_ci	.probe		= umt_probe,
14562306a36Sopenharmony_ci	.disconnect = dvb_usb_device_exit,
14662306a36Sopenharmony_ci	.id_table	= umt_table,
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cimodule_usb_driver(umt_driver);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
15262306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
15362306a36Sopenharmony_ciMODULE_VERSION("1.0");
15462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
155