media: stv090x: Implement probe/remove for stv090x

Move common code into a new function.

This provides the needed functionality to use dvb_module_probe() instead
of dvb_attach()!

[mchehab+samsung@kernel.org: fix an out of order error return code]
Signed-off-by: Tobias Klausmann <tobias.johannes.klausmann@mni.thm.de>
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Tobias Klausmann 2019-05-29 14:02:06 -04:00 committed by Mauro Carvalho Chehab
parent 3c8f4cd271
commit eb5005df88
3 changed files with 152 additions and 55 deletions

View File

@ -4889,6 +4889,67 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
}
static int stv090x_setup_compound(struct stv090x_state *state)
{
struct stv090x_dev *temp_int;
temp_int = find_dev(state->i2c,
state->config->address);
if (temp_int && state->demod_mode == STV090x_DUAL) {
state->internal = temp_int->internal;
state->internal->num_used++;
dprintk(FE_INFO, 1, "Found Internal Structure!");
} else {
state->internal = kmalloc(sizeof(*state->internal), GFP_KERNEL);
if (!state->internal)
goto error;
temp_int = append_internal(state->internal);
if (!temp_int) {
kfree(state->internal);
goto error;
}
state->internal->num_used = 1;
state->internal->mclk = 0;
state->internal->dev_ver = 0;
state->internal->i2c_adap = state->i2c;
state->internal->i2c_addr = state->config->address;
dprintk(FE_INFO, 1, "Create New Internal Structure!");
mutex_init(&state->internal->demod_lock);
mutex_init(&state->internal->tuner_lock);
if (stv090x_setup(&state->frontend) < 0) {
dprintk(FE_ERROR, 1, "Error setting up device");
goto err_remove;
}
}
if (state->internal->dev_ver >= 0x30)
state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM;
/* workaround for stuck DiSEqC output */
if (state->config->diseqc_envelope_mode)
stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
state->config->set_gpio = stv090x_set_gpio;
dprintk(FE_ERROR, 1, "Probing %s demodulator(%d) Cut=0x%02x",
state->device == STV0900 ? "STV0900" : "STV0903",
state->config->demod,
state->internal->dev_ver);
return 0;
error:
kfree(state);
return -ENOMEM;
err_remove:
remove_dev(state->internal);
kfree(state->internal);
return -ENODEV;
}
static const struct dvb_frontend_ops stv090x_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.info = {
@ -4921,16 +4982,74 @@ static const struct dvb_frontend_ops stv090x_ops = {
.read_snr = stv090x_read_cnr,
};
static struct dvb_frontend *stv090x_get_dvb_frontend(struct i2c_client *client)
{
struct stv090x_state *state = i2c_get_clientdata(client);
dev_dbg(&client->dev, "\n");
return &state->frontend;
}
static int stv090x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
struct stv090x_config *config = client->dev.platform_data;
struct stv090x_state *state = NULL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state) {
ret = -ENOMEM;
goto error;
}
state->verbose = &verbose;
state->config = config;
state->i2c = client->adapter;
state->frontend.ops = stv090x_ops;
state->frontend.demodulator_priv = state;
state->demod = config->demod;
/* Single or Dual mode */
state->demod_mode = config->demod_mode;
state->device = config->device;
/* default */
state->rolloff = STV090x_RO_35;
ret = stv090x_setup_compound(state);
if (ret)
goto error;
i2c_set_clientdata(client, state);
/* setup callbacks */
config->get_dvb_frontend = stv090x_get_dvb_frontend;
return 0;
error:
kfree(state);
return ret;
}
static int stv090x_remove(struct i2c_client *client)
{
struct stv090x_state *state = i2c_get_clientdata(client);
stv090x_release(&state->frontend);
return 0;
}
struct dvb_frontend *stv090x_attach(struct stv090x_config *config,
struct i2c_adapter *i2c,
enum stv090x_demodulator demod)
{
int ret = 0;
struct stv090x_state *state = NULL;
struct stv090x_dev *temp_int;
state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
if (state == NULL)
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
goto error;
state->verbose = &verbose;
@ -4939,67 +5058,42 @@ struct dvb_frontend *stv090x_attach(struct stv090x_config *config,
state->frontend.ops = stv090x_ops;
state->frontend.demodulator_priv = state;
state->demod = demod;
state->demod_mode = config->demod_mode; /* Single or Dual mode */
/* Single or Dual mode */
state->demod_mode = config->demod_mode;
state->device = config->device;
state->rolloff = STV090x_RO_35; /* default */
/* default */
state->rolloff = STV090x_RO_35;
temp_int = find_dev(state->i2c,
state->config->address);
if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) {
state->internal = temp_int->internal;
state->internal->num_used++;
dprintk(FE_INFO, 1, "Found Internal Structure!");
} else {
state->internal = kmalloc(sizeof(struct stv090x_internal),
GFP_KERNEL);
if (!state->internal)
goto error;
temp_int = append_internal(state->internal);
if (!temp_int) {
kfree(state->internal);
goto error;
}
state->internal->num_used = 1;
state->internal->mclk = 0;
state->internal->dev_ver = 0;
state->internal->i2c_adap = state->i2c;
state->internal->i2c_addr = state->config->address;
dprintk(FE_INFO, 1, "Create New Internal Structure!");
mutex_init(&state->internal->demod_lock);
mutex_init(&state->internal->tuner_lock);
if (stv090x_setup(&state->frontend) < 0) {
dprintk(FE_ERROR, 1, "Error setting up device");
goto err_remove;
}
}
if (state->internal->dev_ver >= 0x30)
state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM;
/* workaround for stuck DiSEqC output */
if (config->diseqc_envelope_mode)
stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
config->set_gpio = stv090x_set_gpio;
dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
state->device == STV0900 ? "STV0900" : "STV0903",
demod,
state->internal->dev_ver);
ret = stv090x_setup_compound(state);
if (ret)
goto error;
return &state->frontend;
err_remove:
remove_dev(state->internal);
kfree(state->internal);
error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(stv090x_attach);
static const struct i2c_device_id stv090x_id_table[] = {
{"stv090x", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, stv090x_id_table);
static struct i2c_driver stv090x_driver = {
.driver = {
.name = "stv090x",
.suppress_bind_attrs = true,
},
.probe = stv090x_probe,
.remove = stv090x_remove,
.id_table = stv090x_id_table,
};
module_i2c_driver(stv090x_driver);
MODULE_PARM_DESC(verbose, "Set Verbosity level");
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");

View File

@ -57,6 +57,7 @@ struct stv090x_config {
enum stv090x_device device;
enum stv090x_mode demod_mode;
enum stv090x_clkmode clk_mode;
enum stv090x_demodulator demod;
u32 xtal; /* default: 8000000 */
u8 address; /* default: 0x68 */
@ -93,6 +94,8 @@ struct stv090x_config {
/* dir = 0 -> output, dir = 1 -> input/open-drain */
int (*set_gpio)(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
u8 xor_value);
struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *i2c);
};
#if IS_REACHABLE(CONFIG_DVB_STV090x)

View File

@ -237,7 +237,7 @@ struct stv090x_state {
struct stv090x_internal *internal;
struct i2c_adapter *i2c;
const struct stv090x_config *config;
struct stv090x_config *config;
struct dvb_frontend frontend;
u32 *verbose; /* Cached module verbosity */