diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 18:29:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 18:29:14 -0700 |
commit | 71f3a82fab1b631ae9cb1feb677f498d4ca5007d (patch) | |
tree | f3b7fd0a62658d60b491c65cf8ab93378e322024 /drivers/media/pci/ddbridge/ddbridge-mci.c | |
parent | 54dbe75bbf1e189982516de179147208e90b5e45 (diff) | |
parent | da2048b7348a0be92f706ac019e022139e29495e (diff) |
Merge tag 'media/v4.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- new Socionext MN88443x ISDB-S/T demodulator driver: mn88443x
- new sensor drivers: ak7375, ov2680 and rj54n1cb0c
- an old soc-camera sensor driver converted to the V4L2 framework:
mt9v111
- a new Voice-Coil Motor (VCM) driver: dw9807-vcm
- some cleanups at cx25821, removing legacy unused code
- some improvements at ddbridge driver
- new platform driver: vicodec
- some DVB API cleanups, removing ioctls and compat code for old
out-of-tree drivers that were never merged upstream
- improvements at DVB core to support frontents that support both
Satellite and non-satellite delivery systems
- got rid of the unused VIDIOC_RESERVED V4L2 ioctl
- some cleanups/improvements at gl861 ISDB driver
- several improvements on ov772x, ov7670 and ov5640, imx274, ov5645,
and smiapp sensor drivers
- fixes at em28xx to support dual TS devices
- some cleanups at V4L2/VB2 locking logic
- some API improvements at media controller
- some cec core and drivers improvements
- some uvcvideo improvements
- some improvements at platform drivers: stm32-dcmi, rcar-vin, coda,
reneseas-ceu, imx, vsp1, venus, camss
- lots of other cleanups and fixes
* tag 'media/v4.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (406 commits)
Revert "media: vivid: shut up warnings due to a non-trivial logic"
siano: get rid of an unused return code for debugfs register
media: isp: fix a warning about a wrong struct initializer
media: radio-wl1273: fix return code for the polling routine
media: s3c-camif: fix return code for the polling routine
media: saa7164: fix return codes for the polling routine
media: exynos-gsc: fix return code if mutex was interrupted
media: mt9v111: Fix build error with no VIDEO_V4L2_SUBDEV_API
media: xc4000: get rid of uneeded casts
media: drxj: get rid of uneeded casts
media: tuner-xc2028: don't use casts for printing sizes
media: cleanup fall-through comments
media: vivid: shut up warnings due to a non-trivial logic
media: rtl28xxu: be sure that it won't go past the array size
media: mt9v111: avoid going past the buffer
media: vsp1_dl: add a description for cmdpool field
media: sta2x11: add a missing parameter description
media: v4l2-mem2mem: add descriptions to MC fields
media: i2c: fix warning in Aptina MT9V111
media: imx: shut up a false positive warning
...
Diffstat (limited to 'drivers/media/pci/ddbridge/ddbridge-mci.c')
-rw-r--r-- | drivers/media/pci/ddbridge/ddbridge-mci.c | 409 |
1 files changed, 18 insertions, 391 deletions
diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.c b/drivers/media/pci/ddbridge/ddbridge-mci.c index 4ac634fc96e4..97384ae9ad27 100644 --- a/drivers/media/pci/ddbridge/ddbridge-mci.c +++ b/drivers/media/pci/ddbridge/ddbridge-mci.c @@ -2,9 +2,9 @@ /* * ddbridge-mci.c: Digital Devices microcode interface * - * Copyright (C) 2017 Digital Devices GmbH - * Ralph Metzler <rjkm@metzlerbros.de> - * Marcus Metzler <mocm@metzlerbros.de> + * Copyright (C) 2017-2018 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,42 +22,6 @@ static LIST_HEAD(mci_list); -static const u32 MCLK = (1550000000 / 12); -static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6); -static const u32 MAX_LDPC_BITRATE = (720000000); - -struct mci_base { - struct list_head mci_list; - void *key; - struct ddb_link *link; - struct completion completion; - - struct device *dev; - struct mutex tuner_lock; /* concurrent tuner access lock */ - u8 adr; - struct mutex mci_lock; /* concurrent MCI access lock */ - int count; - - u8 tuner_use_count[MCI_TUNER_MAX]; - u8 assigned_demod[MCI_DEMOD_MAX]; - u32 used_ldpc_bitrate[MCI_DEMOD_MAX]; - u8 demod_in_use[MCI_DEMOD_MAX]; - u32 iq_mode; -}; - -struct mci { - struct mci_base *base; - struct dvb_frontend fe; - int nr; - int demod; - int tuner; - int first_time_lock; - int started; - struct mci_result signal_info; - - u32 bb_mode; -}; - static int mci_reset(struct mci *state) { struct ddb_link *link = state->base->link; @@ -84,7 +48,7 @@ static int mci_reset(struct mci *state) return 0; } -static int mci_config(struct mci *state, u32 config) +int ddb_mci_config(struct mci *state, u32 config) { struct ddb_link *link = state->base->link; @@ -122,16 +86,16 @@ static int _mci_cmd_unlocked(struct mci *state, return 0; } -static int mci_cmd(struct mci *state, - struct mci_command *command, - struct mci_result *result) +int ddb_mci_cmd(struct mci *state, + struct mci_command *command, + struct mci_result *result) { int stat; mutex_lock(&state->base->mci_lock); stat = _mci_cmd_unlocked(state, (u32 *)command, sizeof(*command) / sizeof(u32), - (u32 *)result, sizeof(*result) / sizeof(u32)); + (u32 *)result, sizeof(*result) / sizeof(u32)); mutex_unlock(&state->base->mci_lock); return stat; } @@ -143,344 +107,6 @@ static void mci_handler(void *priv) complete(&base->completion); } -static void release(struct dvb_frontend *fe) -{ - struct mci *state = fe->demodulator_priv; - - state->base->count--; - if (state->base->count == 0) { - list_del(&state->base->mci_list); - kfree(state->base); - } - kfree(state); -} - -static int read_status(struct dvb_frontend *fe, enum fe_status *status) -{ - int stat; - struct mci *state = fe->demodulator_priv; - struct mci_command cmd; - struct mci_result res; - - cmd.command = MCI_CMD_GETSTATUS; - cmd.demod = state->demod; - stat = mci_cmd(state, &cmd, &res); - if (stat) - return stat; - *status = 0x00; - if (res.status == SX8_DEMOD_WAIT_MATYPE) - *status = 0x0f; - if (res.status == SX8_DEMOD_LOCKED) - *status = 0x1f; - return stat; -} - -static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on) -{ - struct mci *state = fe->demodulator_priv; - struct mci_command cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.tuner = state->tuner; - cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE; - return mci_cmd(state, &cmd, NULL); -} - -static int stop(struct dvb_frontend *fe) -{ - struct mci *state = fe->demodulator_priv; - struct mci_command cmd; - u32 input = state->tuner; - - memset(&cmd, 0, sizeof(cmd)); - if (state->demod != DEMOD_UNUSED) { - cmd.command = MCI_CMD_STOP; - cmd.demod = state->demod; - mci_cmd(state, &cmd, NULL); - if (state->base->iq_mode) { - cmd.command = MCI_CMD_STOP; - cmd.demod = state->demod; - cmd.output = 0; - mci_cmd(state, &cmd, NULL); - mci_config(state, SX8_TSCONFIG_MODE_NORMAL); - } - } - mutex_lock(&state->base->tuner_lock); - state->base->tuner_use_count[input]--; - if (!state->base->tuner_use_count[input]) - mci_set_tuner(fe, input, 0); - if (state->demod < MCI_DEMOD_MAX) - state->base->demod_in_use[state->demod] = 0; - state->base->used_ldpc_bitrate[state->nr] = 0; - state->demod = DEMOD_UNUSED; - state->base->assigned_demod[state->nr] = DEMOD_UNUSED; - state->base->iq_mode = 0; - mutex_unlock(&state->base->tuner_lock); - state->started = 0; - return 0; -} - -static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) -{ - struct mci *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 used_ldpc_bitrate = 0, free_ldpc_bitrate; - u32 used_demods = 0; - struct mci_command cmd; - u32 input = state->tuner; - u32 bits_per_symbol = 0; - int i, stat = 0; - - if (p->symbol_rate >= (MCLK / 2)) - flags &= ~1; - if ((flags & 3) == 0) - return -EINVAL; - - if (flags & 2) { - u32 tmp = modmask; - - bits_per_symbol = 1; - while (tmp & 1) { - tmp >>= 1; - bits_per_symbol++; - } - } - - mutex_lock(&state->base->tuner_lock); - if (state->base->iq_mode) { - stat = -EBUSY; - goto unlock; - } - for (i = 0; i < MCI_DEMOD_MAX; i++) { - used_ldpc_bitrate += state->base->used_ldpc_bitrate[i]; - if (state->base->demod_in_use[i]) - used_demods++; - } - if (used_ldpc_bitrate >= MAX_LDPC_BITRATE || - ((ts_config & SX8_TSCONFIG_MODE_MASK) > - SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) { - stat = -EBUSY; - goto unlock; - } - free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate; - if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE) - free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE; - - while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate) - bits_per_symbol--; - - if (bits_per_symbol < 2) { - stat = -EBUSY; - goto unlock; - } - i = (p->symbol_rate > (MCLK / 2)) ? 3 : 7; - while (i >= 0 && state->base->demod_in_use[i]) - i--; - if (i < 0) { - stat = -EBUSY; - goto unlock; - } - state->base->demod_in_use[i] = 1; - state->base->used_ldpc_bitrate[state->nr] = p->symbol_rate - * bits_per_symbol; - state->demod = i; - state->base->assigned_demod[state->nr] = i; - - if (!state->base->tuner_use_count[input]) - mci_set_tuner(fe, input, 1); - state->base->tuner_use_count[input]++; - state->base->iq_mode = (ts_config > 1); -unlock: - mutex_unlock(&state->base->tuner_lock); - if (stat) - return stat; - memset(&cmd, 0, sizeof(cmd)); - - if (state->base->iq_mode) { - cmd.command = SX8_CMD_SELECT_IQOUT; - cmd.demod = state->demod; - cmd.output = 0; - mci_cmd(state, &cmd, NULL); - mci_config(state, ts_config); - } - if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000) - flags |= 0x80; - dev_dbg(state->base->dev, "MCI-%d: tuner=%d demod=%d\n", - state->nr, state->tuner, state->demod); - cmd.command = MCI_CMD_SEARCH_DVBS; - cmd.dvbs2_search.flags = flags; - cmd.dvbs2_search.s2_modulation_mask = - modmask & ((1 << (bits_per_symbol - 1)) - 1); - cmd.dvbs2_search.retry = 2; - cmd.dvbs2_search.frequency = p->frequency * 1000; - cmd.dvbs2_search.symbol_rate = p->symbol_rate; - cmd.dvbs2_search.scrambling_sequence_index = - p->scrambling_sequence_index; - cmd.dvbs2_search.input_stream_id = - (p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0; - cmd.tuner = state->tuner; - cmd.demod = state->demod; - cmd.output = state->nr; - if (p->stream_id == 0x80000000) - cmd.output |= 0x80; - stat = mci_cmd(state, &cmd, NULL); - if (stat) - stop(fe); - return stat; -} - -static int start_iq(struct dvb_frontend *fe, u32 ts_config) -{ - struct mci *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 used_demods = 0; - struct mci_command cmd; - u32 input = state->tuner; - int i, stat = 0; - - mutex_lock(&state->base->tuner_lock); - if (state->base->iq_mode) { - stat = -EBUSY; - goto unlock; - } - for (i = 0; i < MCI_DEMOD_MAX; i++) - if (state->base->demod_in_use[i]) - used_demods++; - if (used_demods > 0) { - stat = -EBUSY; - goto unlock; - } - state->demod = 0; - state->base->assigned_demod[state->nr] = 0; - if (!state->base->tuner_use_count[input]) - mci_set_tuner(fe, input, 1); - state->base->tuner_use_count[input]++; - state->base->iq_mode = (ts_config > 1); -unlock: - mutex_unlock(&state->base->tuner_lock); - if (stat) - return stat; - - memset(&cmd, 0, sizeof(cmd)); - cmd.command = SX8_CMD_START_IQ; - cmd.dvbs2_search.frequency = p->frequency * 1000; - cmd.dvbs2_search.symbol_rate = p->symbol_rate; - cmd.tuner = state->tuner; - cmd.demod = state->demod; - cmd.output = 7; - mci_config(state, ts_config); - stat = mci_cmd(state, &cmd, NULL); - if (stat) - stop(fe); - return stat; -} - -static int set_parameters(struct dvb_frontend *fe) -{ - int stat = 0; - struct mci *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 ts_config, iq_mode = 0, isi; - - if (state->started) - stop(fe); - - isi = p->stream_id; - if (isi != NO_STREAM_ID_FILTER) - iq_mode = (isi & 0x30000000) >> 28; - - switch (iq_mode) { - case 1: - ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); - break; - case 2: - ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); - break; - default: - ts_config = SX8_TSCONFIG_MODE_NORMAL; - break; - } - - if (iq_mode != 2) { - u32 flags = 3; - u32 mask = 3; - - if (p->modulation == APSK_16 || - p->modulation == APSK_32) { - flags = 2; - mask = 15; - } - stat = start(fe, flags, mask, ts_config); - } else { - stat = start_iq(fe, ts_config); - } - - if (!stat) { - state->started = 1; - state->first_time_lock = 1; - state->signal_info.status = SX8_DEMOD_WAIT_SIGNAL; - } - - return stat; -} - -static int tune(struct dvb_frontend *fe, bool re_tune, - unsigned int mode_flags, - unsigned int *delay, enum fe_status *status) -{ - int r; - - if (re_tune) { - r = set_parameters(fe); - if (r) - return r; - } - r = read_status(fe, status); - if (r) - return r; - - if (*status & FE_HAS_LOCK) - return 0; - *delay = HZ / 10; - return 0; -} - -static enum dvbfe_algo get_algo(struct dvb_frontend *fe) -{ - return DVBFE_ALGO_HW; -} - -static int set_input(struct dvb_frontend *fe, int input) -{ - struct mci *state = fe->demodulator_priv; - - state->tuner = input; - dev_dbg(state->base->dev, "MCI-%d: input=%d\n", state->nr, input); - return 0; -} - -static struct dvb_frontend_ops mci_ops = { - .delsys = { SYS_DVBS, SYS_DVBS2 }, - .info = { - .name = "Digital Devices MaxSX8 MCI DVB-S/S2/S2X", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, - .symbol_rate_min = 100000, - .symbol_rate_max = 100000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | - FE_CAN_2G_MODULATION | - FE_CAN_MULTISTREAM, - }, - .get_frontend_algo = get_algo, - .tune = tune, - .release = release, - .read_status = read_status, -}; - static struct mci_base *match_base(void *key) { struct mci_base *p; @@ -498,8 +124,7 @@ static int probe(struct mci *state) } struct dvb_frontend -*ddb_mci_attach(struct ddb_input *input, - int mci_type, int nr, +*ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, int (**fn_set_input)(struct dvb_frontend *fe, int input)) { struct ddb_port *port = input->port; @@ -507,9 +132,9 @@ struct dvb_frontend struct ddb_link *link = &dev->link[port->lnr]; struct mci_base *base; struct mci *state; - void *key = mci_type ? (void *)port : (void *)link; + void *key = cfg->type ? (void *)port : (void *)link; - state = kzalloc(sizeof(*state), GFP_KERNEL); + state = kzalloc(cfg->state_size, GFP_KERNEL); if (!state) return NULL; @@ -518,7 +143,7 @@ struct dvb_frontend base->count++; state->base = base; } else { - base = kzalloc(sizeof(*base), GFP_KERNEL); + base = kzalloc(cfg->base_size, GFP_KERNEL); if (!base) goto fail; base->key = key; @@ -535,15 +160,17 @@ struct dvb_frontend goto fail; } list_add(&base->mci_list, &mci_list); + if (cfg->base_init) + cfg->base_init(base); } - state->fe.ops = mci_ops; + memcpy(&state->fe.ops, cfg->fe_ops, sizeof(struct dvb_frontend_ops)); state->fe.demodulator_priv = state; state->nr = nr; - *fn_set_input = set_input; - + *fn_set_input = cfg->set_input; state->tuner = nr; state->demod = nr; - + if (cfg->init) + cfg->init(state); return &state->fe; fail: kfree(state); |