brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 39f2dc9 Raw
276 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * NXP TDA18212HN silicon tuner driver4 *5 * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>6 */7 8#include "tda18212.h"9#include <linux/regmap.h>10 11struct tda18212_dev {12	struct tda18212_config cfg;13	struct i2c_client *client;14	struct regmap *regmap;15 16	u32 if_frequency;17};18 19static int tda18212_set_params(struct dvb_frontend *fe)20{21	struct tda18212_dev *dev = fe->tuner_priv;22	struct dtv_frontend_properties *c = &fe->dtv_property_cache;23	int ret, i;24	u32 if_khz;25	u8 buf[9];26	#define DVBT_6   027	#define DVBT_7   128	#define DVBT_8   229	#define DVBT2_6  330	#define DVBT2_7  431	#define DVBT2_8  532	#define DVBC_6   633	#define DVBC_8   734	#define ATSC_VSB 835	#define ATSC_QAM 936	static const u8 bw_params[][3] = {37		     /* reg:   0f    13    23 */38		[DVBT_6]  = { 0xb3, 0x20, 0x03 },39		[DVBT_7]  = { 0xb3, 0x31, 0x01 },40		[DVBT_8]  = { 0xb3, 0x22, 0x01 },41		[DVBT2_6] = { 0xbc, 0x20, 0x03 },42		[DVBT2_7] = { 0xbc, 0x72, 0x03 },43		[DVBT2_8] = { 0xbc, 0x22, 0x01 },44		[DVBC_6]  = { 0x92, 0x50, 0x03 },45		[DVBC_8]  = { 0x92, 0x53, 0x03 },46		[ATSC_VSB] = { 0x7d, 0x20, 0x63 },47		[ATSC_QAM] = { 0x7d, 0x20, 0x63 },48	};49 50	dev_dbg(&dev->client->dev,51			"delivery_system=%d frequency=%d bandwidth_hz=%d\n",52			c->delivery_system, c->frequency,53			c->bandwidth_hz);54 55	if (fe->ops.i2c_gate_ctrl)56		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */57 58	switch (c->delivery_system) {59	case SYS_ATSC:60		if_khz = dev->cfg.if_atsc_vsb;61		i = ATSC_VSB;62		break;63	case SYS_DVBC_ANNEX_B:64		if_khz = dev->cfg.if_atsc_qam;65		i = ATSC_QAM;66		break;67	case SYS_DVBT:68		switch (c->bandwidth_hz) {69		case 6000000:70			if_khz = dev->cfg.if_dvbt_6;71			i = DVBT_6;72			break;73		case 7000000:74			if_khz = dev->cfg.if_dvbt_7;75			i = DVBT_7;76			break;77		case 8000000:78			if_khz = dev->cfg.if_dvbt_8;79			i = DVBT_8;80			break;81		default:82			ret = -EINVAL;83			goto error;84		}85		break;86	case SYS_DVBT2:87		switch (c->bandwidth_hz) {88		case 6000000:89			if_khz = dev->cfg.if_dvbt2_6;90			i = DVBT2_6;91			break;92		case 7000000:93			if_khz = dev->cfg.if_dvbt2_7;94			i = DVBT2_7;95			break;96		case 8000000:97			if_khz = dev->cfg.if_dvbt2_8;98			i = DVBT2_8;99			break;100		default:101			ret = -EINVAL;102			goto error;103		}104		break;105	case SYS_DVBC_ANNEX_A:106	case SYS_DVBC_ANNEX_C:107		if_khz = dev->cfg.if_dvbc;108		i = DVBC_8;109		break;110	default:111		ret = -EINVAL;112		goto error;113	}114 115	ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]);116	if (ret)117		goto error;118 119	ret = regmap_write(dev->regmap, 0x06, 0x00);120	if (ret)121		goto error;122 123	ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]);124	if (ret)125		goto error;126 127	buf[0] = 0x02;128	buf[1] = bw_params[i][1];129	buf[2] = 0x03; /* default value */130	buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);131	buf[4] = ((c->frequency / 1000) >> 16) & 0xff;132	buf[5] = ((c->frequency / 1000) >>  8) & 0xff;133	buf[6] = ((c->frequency / 1000) >>  0) & 0xff;134	buf[7] = 0xc1;135	buf[8] = 0x01;136	ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf));137	if (ret)138		goto error;139 140	/* actual IF rounded as it is on register */141	dev->if_frequency = buf[3] * 50 * 1000;142 143exit:144	if (fe->ops.i2c_gate_ctrl)145		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */146 147	return ret;148 149error:150	dev_dbg(&dev->client->dev, "failed=%d\n", ret);151	goto exit;152}153 154static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)155{156	struct tda18212_dev *dev = fe->tuner_priv;157 158	*frequency = dev->if_frequency;159 160	return 0;161}162 163static const struct dvb_tuner_ops tda18212_tuner_ops = {164	.info = {165		.name              = "NXP TDA18212",166 167		.frequency_min_hz  =  48 * MHz,168		.frequency_max_hz  = 864 * MHz,169		.frequency_step_hz =   1 * kHz,170	},171 172	.set_params    = tda18212_set_params,173	.get_if_frequency = tda18212_get_if_frequency,174};175 176static int tda18212_probe(struct i2c_client *client)177{178	struct tda18212_config *cfg = client->dev.platform_data;179	struct dvb_frontend *fe = cfg->fe;180	struct tda18212_dev *dev;181	int ret;182	unsigned int chip_id;183	char *version;184	static const struct regmap_config regmap_config = {185		.reg_bits = 8,186		.val_bits = 8,187	};188 189	dev = kzalloc(sizeof(*dev), GFP_KERNEL);190	if (dev == NULL) {191		ret = -ENOMEM;192		dev_err(&client->dev, "kzalloc() failed\n");193		goto err;194	}195 196	memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config));197	dev->client = client;198	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);199	if (IS_ERR(dev->regmap)) {200		ret = PTR_ERR(dev->regmap);201		goto err;202	}203 204	/* check if the tuner is there */205	if (fe->ops.i2c_gate_ctrl)206		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */207 208	ret = regmap_read(dev->regmap, 0x00, &chip_id);209	dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id);210 211	if (fe->ops.i2c_gate_ctrl)212		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */213 214	if (ret)215		goto err;216 217	switch (chip_id) {218	case 0xc7:219		version = "M"; /* master */220		break;221	case 0x47:222		version = "S"; /* slave */223		break;224	default:225		ret = -ENODEV;226		goto err;227	}228 229	dev_info(&dev->client->dev,230			"NXP TDA18212HN/%s successfully identified\n", version);231 232	fe->tuner_priv = dev;233	memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,234			sizeof(struct dvb_tuner_ops));235	i2c_set_clientdata(client, dev);236 237	return 0;238err:239	dev_dbg(&client->dev, "failed=%d\n", ret);240	kfree(dev);241	return ret;242}243 244static void tda18212_remove(struct i2c_client *client)245{246	struct tda18212_dev *dev = i2c_get_clientdata(client);247	struct dvb_frontend *fe = dev->cfg.fe;248 249	dev_dbg(&client->dev, "\n");250 251	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));252	fe->tuner_priv = NULL;253	kfree(dev);254}255 256static const struct i2c_device_id tda18212_id[] = {257	{ "tda18212" },258	{}259};260MODULE_DEVICE_TABLE(i2c, tda18212_id);261 262static struct i2c_driver tda18212_driver = {263	.driver = {264		.name	= "tda18212",265	},266	.probe		= tda18212_probe,267	.remove		= tda18212_remove,268	.id_table	= tda18212_id,269};270 271module_i2c_driver(tda18212_driver);272 273MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");274MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");275MODULE_LICENSE("GPL");276