brintos

brintos / linux-shallow public Read only

0
0
Text · 15.1 KiB · 0463898 Raw
623 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * FCI FC2580 silicon tuner driver4 *5 * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>6 */7 8#include "fc2580_priv.h"9 10/*11 * TODO:12 * I2C write and read works only for one single register. Multiple registers13 * could not be accessed using normal register address auto-increment.14 * There could be (very likely) register to change that behavior....15 */16 17/* write single register conditionally only when value differs from 0xff18 * XXX: This is special routine meant only for writing fc2580_freq_regs_lut[]19 * values. Do not use for the other purposes. */20static int fc2580_wr_reg_ff(struct fc2580_dev *dev, u8 reg, u8 val)21{22	if (val == 0xff)23		return 0;24	else25		return regmap_write(dev->regmap, reg, val);26}27 28static int fc2580_set_params(struct fc2580_dev *dev)29{30	struct i2c_client *client = dev->client;31	int ret, i;32	unsigned int uitmp, div_ref, div_ref_val, div_n, k, k_cw, div_out;33	u64 f_vco;34	u8 synth_config;35	unsigned long timeout;36 37	if (!dev->active) {38		dev_dbg(&client->dev, "tuner is sleeping\n");39		return 0;40	}41 42	/*43	 * Fractional-N synthesizer44	 *45	 *                      +---------------------------------------+46	 *                      v                                       |47	 *  Fref   +----+     +----+     +-------+         +----+     +------+     +---+48	 * ------> | /R | --> | PD | --> |  VCO  | ------> | /2 | --> | /N.F | <-- | K |49	 *         +----+     +----+     +-------+         +----+     +------+     +---+50	 *                                 |51	 *                                 |52	 *                                 v53	 *                               +-------+  Fout54	 *                               | /Rout | ------>55	 *                               +-------+56	 */57	for (i = 0; i < ARRAY_SIZE(fc2580_pll_lut); i++) {58		if (dev->f_frequency <= fc2580_pll_lut[i].freq)59			break;60	}61	if (i == ARRAY_SIZE(fc2580_pll_lut)) {62		ret = -EINVAL;63		goto err;64	}65 66	#define DIV_PRE_N 267	#define F_REF dev->clk68	div_out = fc2580_pll_lut[i].div_out;69	f_vco = (u64) dev->f_frequency * div_out;70	synth_config = fc2580_pll_lut[i].band;71	if (f_vco < 2600000000ULL)72		synth_config |= 0x06;73	else74		synth_config |= 0x0e;75 76	/* select reference divider R (keep PLL div N in valid range) */77	#define DIV_N_MIN 7678	if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 1)) {79		div_ref = 1;80		div_ref_val = 0x00;81	} else if (f_vco >= div_u64((u64) DIV_PRE_N * DIV_N_MIN * F_REF, 2)) {82		div_ref = 2;83		div_ref_val = 0x10;84	} else {85		div_ref = 4;86		div_ref_val = 0x20;87	}88 89	/* calculate PLL integer and fractional control word */90	uitmp = DIV_PRE_N * F_REF / div_ref;91	div_n = div_u64_rem(f_vco, uitmp, &k);92	k_cw = div_u64((u64) k * 0x100000, uitmp);93 94	dev_dbg(&client->dev,95		"frequency=%u bandwidth=%u f_vco=%llu F_REF=%u div_ref=%u div_n=%u k=%u div_out=%u k_cw=%0x\n",96		dev->f_frequency, dev->f_bandwidth, f_vco, F_REF, div_ref,97		div_n, k, div_out, k_cw);98 99	ret = regmap_write(dev->regmap, 0x02, synth_config);100	if (ret)101		goto err;102 103	ret = regmap_write(dev->regmap, 0x18, div_ref_val << 0 | k_cw >> 16);104	if (ret)105		goto err;106 107	ret = regmap_write(dev->regmap, 0x1a, (k_cw >> 8) & 0xff);108	if (ret)109		goto err;110 111	ret = regmap_write(dev->regmap, 0x1b, (k_cw >> 0) & 0xff);112	if (ret)113		goto err;114 115	ret = regmap_write(dev->regmap, 0x1c, div_n);116	if (ret)117		goto err;118 119	/* registers */120	for (i = 0; i < ARRAY_SIZE(fc2580_freq_regs_lut); i++) {121		if (dev->f_frequency <= fc2580_freq_regs_lut[i].freq)122			break;123	}124	if (i == ARRAY_SIZE(fc2580_freq_regs_lut)) {125		ret = -EINVAL;126		goto err;127	}128 129	ret = fc2580_wr_reg_ff(dev, 0x25, fc2580_freq_regs_lut[i].r25_val);130	if (ret)131		goto err;132 133	ret = fc2580_wr_reg_ff(dev, 0x27, fc2580_freq_regs_lut[i].r27_val);134	if (ret)135		goto err;136 137	ret = fc2580_wr_reg_ff(dev, 0x28, fc2580_freq_regs_lut[i].r28_val);138	if (ret)139		goto err;140 141	ret = fc2580_wr_reg_ff(dev, 0x29, fc2580_freq_regs_lut[i].r29_val);142	if (ret)143		goto err;144 145	ret = fc2580_wr_reg_ff(dev, 0x2b, fc2580_freq_regs_lut[i].r2b_val);146	if (ret)147		goto err;148 149	ret = fc2580_wr_reg_ff(dev, 0x2c, fc2580_freq_regs_lut[i].r2c_val);150	if (ret)151		goto err;152 153	ret = fc2580_wr_reg_ff(dev, 0x2d, fc2580_freq_regs_lut[i].r2d_val);154	if (ret)155		goto err;156 157	ret = fc2580_wr_reg_ff(dev, 0x30, fc2580_freq_regs_lut[i].r30_val);158	if (ret)159		goto err;160 161	ret = fc2580_wr_reg_ff(dev, 0x44, fc2580_freq_regs_lut[i].r44_val);162	if (ret)163		goto err;164 165	ret = fc2580_wr_reg_ff(dev, 0x50, fc2580_freq_regs_lut[i].r50_val);166	if (ret)167		goto err;168 169	ret = fc2580_wr_reg_ff(dev, 0x53, fc2580_freq_regs_lut[i].r53_val);170	if (ret)171		goto err;172 173	ret = fc2580_wr_reg_ff(dev, 0x5f, fc2580_freq_regs_lut[i].r5f_val);174	if (ret)175		goto err;176 177	ret = fc2580_wr_reg_ff(dev, 0x61, fc2580_freq_regs_lut[i].r61_val);178	if (ret)179		goto err;180 181	ret = fc2580_wr_reg_ff(dev, 0x62, fc2580_freq_regs_lut[i].r62_val);182	if (ret)183		goto err;184 185	ret = fc2580_wr_reg_ff(dev, 0x63, fc2580_freq_regs_lut[i].r63_val);186	if (ret)187		goto err;188 189	ret = fc2580_wr_reg_ff(dev, 0x67, fc2580_freq_regs_lut[i].r67_val);190	if (ret)191		goto err;192 193	ret = fc2580_wr_reg_ff(dev, 0x68, fc2580_freq_regs_lut[i].r68_val);194	if (ret)195		goto err;196 197	ret = fc2580_wr_reg_ff(dev, 0x69, fc2580_freq_regs_lut[i].r69_val);198	if (ret)199		goto err;200 201	ret = fc2580_wr_reg_ff(dev, 0x6a, fc2580_freq_regs_lut[i].r6a_val);202	if (ret)203		goto err;204 205	ret = fc2580_wr_reg_ff(dev, 0x6b, fc2580_freq_regs_lut[i].r6b_val);206	if (ret)207		goto err;208 209	ret = fc2580_wr_reg_ff(dev, 0x6c, fc2580_freq_regs_lut[i].r6c_val);210	if (ret)211		goto err;212 213	ret = fc2580_wr_reg_ff(dev, 0x6d, fc2580_freq_regs_lut[i].r6d_val);214	if (ret)215		goto err;216 217	ret = fc2580_wr_reg_ff(dev, 0x6e, fc2580_freq_regs_lut[i].r6e_val);218	if (ret)219		goto err;220 221	ret = fc2580_wr_reg_ff(dev, 0x6f, fc2580_freq_regs_lut[i].r6f_val);222	if (ret)223		goto err;224 225	/* IF filters */226	for (i = 0; i < ARRAY_SIZE(fc2580_if_filter_lut); i++) {227		if (dev->f_bandwidth <= fc2580_if_filter_lut[i].freq)228			break;229	}230	if (i == ARRAY_SIZE(fc2580_if_filter_lut)) {231		ret = -EINVAL;232		goto err;233	}234 235	ret = regmap_write(dev->regmap, 0x36, fc2580_if_filter_lut[i].r36_val);236	if (ret)237		goto err;238 239	uitmp = (unsigned int) 8058000 - (dev->f_bandwidth * 122 / 100 / 2);240	uitmp = div64_u64((u64) dev->clk * uitmp, 1000000000000ULL);241	ret = regmap_write(dev->regmap, 0x37, uitmp);242	if (ret)243		goto err;244 245	ret = regmap_write(dev->regmap, 0x39, fc2580_if_filter_lut[i].r39_val);246	if (ret)247		goto err;248 249	timeout = jiffies + msecs_to_jiffies(30);250	for (uitmp = ~0xc0; !time_after(jiffies, timeout) && uitmp != 0xc0;) {251		/* trigger filter */252		ret = regmap_write(dev->regmap, 0x2e, 0x09);253		if (ret)254			goto err;255 256		/* locked when [7:6] are set (val: d7 6MHz, d5 7MHz, cd 8MHz) */257		ret = regmap_read(dev->regmap, 0x2f, &uitmp);258		if (ret)259			goto err;260		uitmp &= 0xc0;261 262		ret = regmap_write(dev->regmap, 0x2e, 0x01);263		if (ret)264			goto err;265	}266	if (uitmp != 0xc0)267		dev_dbg(&client->dev, "filter did not lock %02x\n", uitmp);268 269	return 0;270err:271	dev_dbg(&client->dev, "failed=%d\n", ret);272	return ret;273}274 275static int fc2580_init(struct fc2580_dev *dev)276{277	struct i2c_client *client = dev->client;278	int ret, i;279 280	dev_dbg(&client->dev, "\n");281 282	for (i = 0; i < ARRAY_SIZE(fc2580_init_reg_vals); i++) {283		ret = regmap_write(dev->regmap, fc2580_init_reg_vals[i].reg,284				fc2580_init_reg_vals[i].val);285		if (ret)286			goto err;287	}288 289	dev->active = true;290	return 0;291err:292	dev_dbg(&client->dev, "failed=%d\n", ret);293	return ret;294}295 296static int fc2580_sleep(struct fc2580_dev *dev)297{298	struct i2c_client *client = dev->client;299	int ret;300 301	dev_dbg(&client->dev, "\n");302 303	dev->active = false;304 305	ret = regmap_write(dev->regmap, 0x02, 0x0a);306	if (ret)307		goto err;308	return 0;309err:310	dev_dbg(&client->dev, "failed=%d\n", ret);311	return ret;312}313 314/*315 * DVB API316 */317static int fc2580_dvb_set_params(struct dvb_frontend *fe)318{319	struct fc2580_dev *dev = fe->tuner_priv;320	struct dtv_frontend_properties *c = &fe->dtv_property_cache;321 322	dev->f_frequency = c->frequency;323	dev->f_bandwidth = c->bandwidth_hz;324	return fc2580_set_params(dev);325}326 327static int fc2580_dvb_init(struct dvb_frontend *fe)328{329	return fc2580_init(fe->tuner_priv);330}331 332static int fc2580_dvb_sleep(struct dvb_frontend *fe)333{334	return fc2580_sleep(fe->tuner_priv);335}336 337static int fc2580_dvb_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)338{339	*frequency = 0; /* Zero-IF */340	return 0;341}342 343static const struct dvb_tuner_ops fc2580_dvb_tuner_ops = {344	.info = {345		.name             = "FCI FC2580",346		.frequency_min_hz = 174 * MHz,347		.frequency_max_hz = 862 * MHz,348	},349 350	.init = fc2580_dvb_init,351	.sleep = fc2580_dvb_sleep,352	.set_params = fc2580_dvb_set_params,353 354	.get_if_frequency = fc2580_dvb_get_if_frequency,355};356 357/*358 * V4L2 API359 */360#if IS_ENABLED(CONFIG_VIDEO_DEV)361static const struct v4l2_frequency_band bands[] = {362	{363		.type = V4L2_TUNER_RF,364		.index = 0,365		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,366		.rangelow   =   130000000,367		.rangehigh  =  2000000000,368	},369};370 371static inline struct fc2580_dev *fc2580_subdev_to_dev(struct v4l2_subdev *sd)372{373	return container_of(sd, struct fc2580_dev, subdev);374}375 376static int fc2580_standby(struct v4l2_subdev *sd)377{378	struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);379	int ret;380 381	ret = fc2580_sleep(dev);382	if (ret)383		return ret;384 385	return fc2580_set_params(dev);386}387 388static int fc2580_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)389{390	struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);391	struct i2c_client *client = dev->client;392 393	dev_dbg(&client->dev, "index=%d\n", v->index);394 395	strscpy(v->name, "FCI FC2580", sizeof(v->name));396	v->type = V4L2_TUNER_RF;397	v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;398	v->rangelow  = bands[0].rangelow;399	v->rangehigh = bands[0].rangehigh;400	return 0;401}402 403static int fc2580_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v)404{405	struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);406	struct i2c_client *client = dev->client;407 408	dev_dbg(&client->dev, "index=%d\n", v->index);409	return 0;410}411 412static int fc2580_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)413{414	struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);415	struct i2c_client *client = dev->client;416 417	dev_dbg(&client->dev, "tuner=%d\n", f->tuner);418	f->frequency = dev->f_frequency;419	return 0;420}421 422static int fc2580_s_frequency(struct v4l2_subdev *sd,423			      const struct v4l2_frequency *f)424{425	struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);426	struct i2c_client *client = dev->client;427 428	dev_dbg(&client->dev, "tuner=%d type=%d frequency=%u\n",429		f->tuner, f->type, f->frequency);430 431	dev->f_frequency = clamp_t(unsigned int, f->frequency,432				   bands[0].rangelow, bands[0].rangehigh);433	return fc2580_set_params(dev);434}435 436static int fc2580_enum_freq_bands(struct v4l2_subdev *sd,437				  struct v4l2_frequency_band *band)438{439	struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);440	struct i2c_client *client = dev->client;441 442	dev_dbg(&client->dev, "tuner=%d type=%d index=%d\n",443		band->tuner, band->type, band->index);444 445	if (band->index >= ARRAY_SIZE(bands))446		return -EINVAL;447 448	band->capability = bands[band->index].capability;449	band->rangelow = bands[band->index].rangelow;450	band->rangehigh = bands[band->index].rangehigh;451	return 0;452}453 454static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = {455	.standby                  = fc2580_standby,456	.g_tuner                  = fc2580_g_tuner,457	.s_tuner                  = fc2580_s_tuner,458	.g_frequency              = fc2580_g_frequency,459	.s_frequency              = fc2580_s_frequency,460	.enum_freq_bands          = fc2580_enum_freq_bands,461};462 463static const struct v4l2_subdev_ops fc2580_subdev_ops = {464	.tuner                    = &fc2580_subdev_tuner_ops,465};466 467static int fc2580_s_ctrl(struct v4l2_ctrl *ctrl)468{469	struct fc2580_dev *dev = container_of(ctrl->handler, struct fc2580_dev, hdl);470	struct i2c_client *client = dev->client;471	int ret;472 473	dev_dbg(&client->dev, "ctrl: id=%d name=%s cur.val=%d val=%d\n",474		ctrl->id, ctrl->name, ctrl->cur.val, ctrl->val);475 476	switch (ctrl->id) {477	case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:478	case V4L2_CID_RF_TUNER_BANDWIDTH:479		/*480		 * TODO: Auto logic does not work 100% correctly as tuner driver481		 * do not have information to calculate maximum suitable482		 * bandwidth. Calculating it is responsible of master driver.483		 */484		dev->f_bandwidth = dev->bandwidth->val;485		ret = fc2580_set_params(dev);486		break;487	default:488		dev_dbg(&client->dev, "unknown ctrl");489		ret = -EINVAL;490	}491	return ret;492}493 494static const struct v4l2_ctrl_ops fc2580_ctrl_ops = {495	.s_ctrl = fc2580_s_ctrl,496};497#endif498 499static struct v4l2_subdev *fc2580_get_v4l2_subdev(struct i2c_client *client)500{501	struct fc2580_dev *dev = i2c_get_clientdata(client);502 503	if (dev->subdev.ops)504		return &dev->subdev;505	else506		return NULL;507}508 509static int fc2580_probe(struct i2c_client *client)510{511	struct fc2580_dev *dev;512	struct fc2580_platform_data *pdata = client->dev.platform_data;513	struct dvb_frontend *fe = pdata->dvb_frontend;514	int ret;515	unsigned int uitmp;516	static const struct regmap_config regmap_config = {517		.reg_bits = 8,518		.val_bits = 8,519	};520 521	dev = kzalloc(sizeof(*dev), GFP_KERNEL);522	if (!dev) {523		ret = -ENOMEM;524		goto err;525	}526 527	if (pdata->clk)528		dev->clk = pdata->clk;529	else530		dev->clk = 16384000; /* internal clock */531	dev->client = client;532	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);533	if (IS_ERR(dev->regmap)) {534		ret = PTR_ERR(dev->regmap);535		goto err_kfree;536	}537 538	/* check if the tuner is there */539	ret = regmap_read(dev->regmap, 0x01, &uitmp);540	if (ret)541		goto err_kfree;542 543	dev_dbg(&client->dev, "chip_id=%02x\n", uitmp);544 545	switch (uitmp) {546	case 0x56:547	case 0x5a:548		break;549	default:550		ret = -ENODEV;551		goto err_kfree;552	}553 554#if IS_ENABLED(CONFIG_VIDEO_DEV)555	/* Register controls */556	v4l2_ctrl_handler_init(&dev->hdl, 2);557	dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &fc2580_ctrl_ops,558						V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,559						0, 1, 1, 1);560	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &fc2580_ctrl_ops,561					   V4L2_CID_RF_TUNER_BANDWIDTH,562					   3000, 10000000, 1, 3000);563	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);564	if (dev->hdl.error) {565		ret = dev->hdl.error;566		dev_err(&client->dev, "Could not initialize controls\n");567		v4l2_ctrl_handler_free(&dev->hdl);568		goto err_kfree;569	}570	dev->subdev.ctrl_handler = &dev->hdl;571	dev->f_frequency = bands[0].rangelow;572	dev->f_bandwidth = dev->bandwidth->val;573	v4l2_i2c_subdev_init(&dev->subdev, client, &fc2580_subdev_ops);574#endif575	fe->tuner_priv = dev;576	memcpy(&fe->ops.tuner_ops, &fc2580_dvb_tuner_ops,577	       sizeof(fe->ops.tuner_ops));578	pdata->get_v4l2_subdev = fc2580_get_v4l2_subdev;579	i2c_set_clientdata(client, dev);580 581	dev_info(&client->dev, "FCI FC2580 successfully identified\n");582	return 0;583err_kfree:584	kfree(dev);585err:586	dev_dbg(&client->dev, "failed=%d\n", ret);587	return ret;588}589 590static void fc2580_remove(struct i2c_client *client)591{592	struct fc2580_dev *dev = i2c_get_clientdata(client);593 594	dev_dbg(&client->dev, "\n");595 596#if IS_ENABLED(CONFIG_VIDEO_DEV)597	v4l2_ctrl_handler_free(&dev->hdl);598#endif599	kfree(dev);600}601 602static const struct i2c_device_id fc2580_id_table[] = {603	{ "fc2580" },604	{}605};606MODULE_DEVICE_TABLE(i2c, fc2580_id_table);607 608static struct i2c_driver fc2580_driver = {609	.driver = {610		.name	= "fc2580",611		.suppress_bind_attrs = true,612	},613	.probe		= fc2580_probe,614	.remove		= fc2580_remove,615	.id_table	= fc2580_id_table,616};617 618module_i2c_driver(fc2580_driver);619 620MODULE_DESCRIPTION("FCI FC2580 silicon tuner driver");621MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");622MODULE_LICENSE("GPL");623