Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7cd785ad authored by Matthias Schwarzott's avatar Matthias Schwarzott Committed by Mauro Carvalho Chehab
Browse files

[media] si2165: support i2c_client attach



Afterwards it is possible to convert attaching in card drivers.

Signed-off-by: default avatarMatthias Schwarzott <zzam@gentoo.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 2df9dda0
Loading
Loading
Loading
Loading
+149 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@
 */

struct si2165_state {
	struct i2c_client *client;

	struct i2c_adapter *i2c;

	struct dvb_frontend fe;
@@ -1163,6 +1165,153 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
}
EXPORT_SYMBOL(si2165_attach);

static int si2165_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	struct si2165_state *state = NULL;
	struct si2165_platform_data *pdata = client->dev.platform_data;
	int n;
	int ret = 0;
	u8 val;
	char rev_char;
	const char *chip_name;

	/* allocate memory for the internal state */
	state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL);
	if (state == NULL) {
		ret = -ENOMEM;
		goto error;
	}

	/* setup the state */
	state->client = client;
	state->i2c = client->adapter;
	state->config.i2c_addr = client->addr;
	state->config.chip_mode = pdata->chip_mode;
	state->config.ref_freq_Hz = pdata->ref_freq_Hz;
	state->config.inversion = pdata->inversion;

	if (state->config.ref_freq_Hz < 4000000
	    || state->config.ref_freq_Hz > 27000000) {
		dev_err(&state->i2c->dev, "%s: ref_freq of %d Hz not supported by this driver\n",
			 KBUILD_MODNAME, state->config.ref_freq_Hz);
		ret = -EINVAL;
		goto error;
	}

	/* create dvb_frontend */
	memcpy(&state->fe.ops, &si2165_ops,
		sizeof(struct dvb_frontend_ops));
	state->fe.ops.release = NULL;
	state->fe.demodulator_priv = state;
	i2c_set_clientdata(client, state);

	/* powerup */
	ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
	if (ret < 0)
		goto nodev_error;

	ret = si2165_readreg8(state, 0x0000, &val);
	if (ret < 0)
		goto nodev_error;
	if (val != state->config.chip_mode)
		goto nodev_error;

	ret = si2165_readreg8(state, 0x0023, &state->chip_revcode);
	if (ret < 0)
		goto nodev_error;

	ret = si2165_readreg8(state, 0x0118, &state->chip_type);
	if (ret < 0)
		goto nodev_error;

	/* powerdown */
	ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
	if (ret < 0)
		goto nodev_error;

	if (state->chip_revcode < 26)
		rev_char = 'A' + state->chip_revcode;
	else
		rev_char = '?';

	switch (state->chip_type) {
	case 0x06:
		chip_name = "Si2161";
		state->has_dvbt = true;
		break;
	case 0x07:
		chip_name = "Si2165";
		state->has_dvbt = true;
		state->has_dvbc = true;
		break;
	default:
		dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n",
			KBUILD_MODNAME, state->chip_type, state->chip_revcode);
		goto nodev_error;
	}

	dev_info(&state->i2c->dev,
		"%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n",
		KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
		state->chip_revcode);

	strlcat(state->fe.ops.info.name, chip_name,
			sizeof(state->fe.ops.info.name));

	n = 0;
	if (state->has_dvbt) {
		state->fe.ops.delsys[n++] = SYS_DVBT;
		strlcat(state->fe.ops.info.name, " DVB-T",
			sizeof(state->fe.ops.info.name));
	}
	if (state->has_dvbc) {
		state->fe.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
		strlcat(state->fe.ops.info.name, " DVB-C",
			sizeof(state->fe.ops.info.name));
	}

	/* return fe pointer */
	*pdata->fe = &state->fe;

	return 0;

nodev_error:
	ret = -ENODEV;
error:
	kfree(state);
	dev_dbg(&client->dev, "failed=%d\n", ret);
	return ret;
}

static int si2165_remove(struct i2c_client *client)
{
	struct si2165_state *state = i2c_get_clientdata(client);

	dev_dbg(&client->dev, "\n");

	kfree(state);
	return 0;
}

static const struct i2c_device_id si2165_id_table[] = {
	{"si2165", 0},
	{}
};
MODULE_DEVICE_TABLE(i2c, si2165_id_table);

static struct i2c_driver si2165_driver = {
	.driver = {
		.owner	= THIS_MODULE,
		.name	= "si2165",
	},
	.probe		= si2165_probe,
	.remove		= si2165_remove,
	.id_table	= si2165_id_table,
};

module_i2c_driver(si2165_driver);

module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");

+22 −0
Original line number Diff line number Diff line
@@ -28,6 +28,28 @@ enum {
	SI2165_MODE_PLL_XTAL = 0x21
};

/* I2C addresses
 * possible values: 0x64,0x65,0x66,0x67
 */
struct si2165_platform_data {
	/*
	 * frontend
	 * returned by driver
	 */
	struct dvb_frontend **fe;

	/* external clock or XTAL */
	u8 chip_mode;

	/* frequency of external clock or xtal in Hz
	 * possible values: 4000000, 16000000, 20000000, 240000000, 27000000
	 */
	u32 ref_freq_Hz;

	/* invert the spectrum */
	bool inversion;
};

struct si2165_config {
	/* i2c addr
	 * possible values: 0x64,0x65,0x66,0x67 */