[media] si2165: support i2c_client attach
Afterwards it is possible to convert attaching in card drivers. Signed-off-by: Matthias Schwarzott <zzam@gentoo.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
Родитель
2df9dda07f
Коммит
7cd785adc4
|
@ -40,6 +40,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct si2165_state {
|
struct si2165_state {
|
||||||
|
struct i2c_client *client;
|
||||||
|
|
||||||
struct i2c_adapter *i2c;
|
struct i2c_adapter *i2c;
|
||||||
|
|
||||||
struct dvb_frontend fe;
|
struct dvb_frontend fe;
|
||||||
|
@ -1163,6 +1165,153 @@ error:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(si2165_attach);
|
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_param(debug, int, 0644);
|
||||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,28 @@ enum {
|
||||||
SI2165_MODE_PLL_XTAL = 0x21
|
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 {
|
struct si2165_config {
|
||||||
/* i2c addr
|
/* i2c addr
|
||||||
* possible values: 0x64,0x65,0x66,0x67 */
|
* possible values: 0x64,0x65,0x66,0x67 */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче