Merge tag 'media/v4.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: - new CEC pin injection code for testing purposes - DVB frontend cxd2099 promoted from staging - new platform driver for Sony cxd2880 DVB devices - new sensor drivers: mt9t112, ov2685, ov5695, ov772x, tda1997x, tw9910.c - removal of unused cx18 and ivtv alsa mixers - the reneseas-ceu driver doesn't depend on soc_camera anymore and moved from staging - removed the mantis_vp3028 driver, unused since 2009 - s5p-mfc: add support for version 10 of the MSP - added a decoder for imon protocol - atomisp: lots of cleanups - imx074 and mt9t031: don't depend on soc_camera anymore, being promoted from staging - added helper functions to better support DVB I2C binding - lots of driver improvements and cleanups * tag 'media/v4.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (438 commits) media: v4l2-ioctl: rename a temp var that stores _IOC_SIZE(cmd) media: fimc-capture: get rid of two warnings media: dvb-usb-v2: fix a missing dependency of I2C_MUX media: uvc: to the right check at uvc_ioctl_enum_framesizes() media: cec-core: fix a bug at cec_error_inj_write() media: tda9840: cleanup a warning media: tm6000: avoid casting just to print pointer address media: em28xx-input: improve error handling code media: zr364xx: avoid casting just to print pointer address media: vivid-radio-rx: add a cast to avoid a warning media: saa7134-alsa: don't use casts to print a buffer address media: solo6x10: get rid of an address space warning media: zoran: don't cast pointers to print them media: ir-kbd-i2c: change the if logic to avoid a warning media: ir-kbd-i2c: improve error handling code media: saa7134-input: improve error handling media: s2255drv: fix a casting warning media: ivtvfb: Cleanup some warnings media: videobuf-dma-sg: Fix a weird cast soc_camera: fix a weird cast on printk ...
This commit is contained in:
@@ -141,6 +141,7 @@ config DVB_CORE
|
||||
tristate
|
||||
depends on MEDIA_SUPPORT
|
||||
depends on MEDIA_DIGITAL_TV_SUPPORT
|
||||
depends on (I2C || I2C=n)
|
||||
default y
|
||||
select CRC32
|
||||
|
||||
|
||||
@@ -4,3 +4,9 @@ config MEDIA_CEC_RC
|
||||
depends on CEC_CORE=m || RC_CORE=y
|
||||
---help---
|
||||
Pass on CEC remote control messages to the RC framework.
|
||||
|
||||
config CEC_PIN_ERROR_INJ
|
||||
bool "Enable CEC error injection support"
|
||||
depends on CEC_PIN && DEBUG_FS
|
||||
---help---
|
||||
This option enables CEC error injection using debugfs.
|
||||
|
||||
@@ -9,4 +9,8 @@ ifeq ($(CONFIG_CEC_PIN),y)
|
||||
cec-objs += cec-pin.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CEC_PIN_ERROR_INJ),y)
|
||||
cec-objs += cec-pin-error-inj.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_CEC_CORE) += cec.o
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter
|
||||
*
|
||||
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
@@ -85,8 +73,8 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr
|
||||
void cec_queue_event_fh(struct cec_fh *fh,
|
||||
const struct cec_event *new_ev, u64 ts)
|
||||
{
|
||||
static const u8 max_events[CEC_NUM_EVENTS] = {
|
||||
1, 1, 64, 64, 8, 8,
|
||||
static const u16 max_events[CEC_NUM_EVENTS] = {
|
||||
1, 1, 800, 800, 8, 8,
|
||||
};
|
||||
struct cec_event_entry *entry;
|
||||
unsigned int ev_idx = new_ev->event - 1;
|
||||
@@ -154,11 +142,13 @@ static void cec_queue_event(struct cec_adapter *adap,
|
||||
}
|
||||
|
||||
/* Notify userspace that the CEC pin changed state at the given time. */
|
||||
void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
|
||||
void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high,
|
||||
bool dropped_events, ktime_t ts)
|
||||
{
|
||||
struct cec_event ev = {
|
||||
.event = is_high ? CEC_EVENT_PIN_CEC_HIGH :
|
||||
CEC_EVENT_PIN_CEC_LOW,
|
||||
.flags = dropped_events ? CEC_EVENT_FL_DROPPED_EVENTS : 0,
|
||||
};
|
||||
struct cec_fh *fh;
|
||||
|
||||
@@ -711,16 +701,31 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
|
||||
else
|
||||
msg->flags = 0;
|
||||
|
||||
if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) {
|
||||
msg->msg[2] = adap->phys_addr >> 8;
|
||||
msg->msg[3] = adap->phys_addr & 0xff;
|
||||
}
|
||||
|
||||
/* Sanity checks */
|
||||
if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) {
|
||||
dprintk(1, "%s: invalid length %d\n", __func__, msg->len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len);
|
||||
|
||||
if (msg->timeout)
|
||||
dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n",
|
||||
__func__, msg->len, msg->msg, msg->reply,
|
||||
!block ? ", nb" : "");
|
||||
else
|
||||
dprintk(2, "%s: %*ph%s\n",
|
||||
__func__, msg->len, msg->msg, !block ? " (nb)" : "");
|
||||
|
||||
if (msg->timeout && msg->len == 1) {
|
||||
dprintk(1, "%s: can't reply for poll msg\n", __func__);
|
||||
dprintk(1, "%s: can't reply to poll msg\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len);
|
||||
if (msg->len == 1) {
|
||||
if (cec_msg_destination(msg) == 0xf) {
|
||||
dprintk(1, "%s: invalid poll message\n", __func__);
|
||||
@@ -780,19 +785,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
|
||||
if (!msg->sequence)
|
||||
msg->sequence = ++adap->sequence;
|
||||
|
||||
if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) {
|
||||
msg->msg[2] = adap->phys_addr >> 8;
|
||||
msg->msg[3] = adap->phys_addr & 0xff;
|
||||
}
|
||||
|
||||
if (msg->timeout)
|
||||
dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n",
|
||||
__func__, msg->len, msg->msg, msg->reply,
|
||||
!block ? ", nb" : "");
|
||||
else
|
||||
dprintk(2, "%s: %*ph%s\n",
|
||||
__func__, msg->len, msg->msg, !block ? " (nb)" : "");
|
||||
|
||||
data->msg = *msg;
|
||||
data->fh = fh;
|
||||
data->adap = adap;
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* cec-api.c - HDMI Consumer Electronics Control framework - API
|
||||
*
|
||||
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* cec-core.c - HDMI Consumer Electronics Control framework - Core
|
||||
*
|
||||
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
@@ -207,6 +195,55 @@ void cec_register_cec_notifier(struct cec_adapter *adap,
|
||||
EXPORT_SYMBOL_GPL(cec_register_cec_notifier);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static ssize_t cec_error_inj_write(struct file *file,
|
||||
const char __user *ubuf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *sf = file->private_data;
|
||||
struct cec_adapter *adap = sf->private;
|
||||
char *buf;
|
||||
char *line;
|
||||
char *p;
|
||||
|
||||
buf = memdup_user_nul(ubuf, min_t(size_t, PAGE_SIZE, count));
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
p = buf;
|
||||
while (p && *p) {
|
||||
p = skip_spaces(p);
|
||||
line = strsep(&p, "\n");
|
||||
if (!*line || *line == '#')
|
||||
continue;
|
||||
if (!adap->ops->error_inj_parse_line(adap, line)) {
|
||||
kfree(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
kfree(buf);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int cec_error_inj_show(struct seq_file *sf, void *unused)
|
||||
{
|
||||
struct cec_adapter *adap = sf->private;
|
||||
|
||||
return adap->ops->error_inj_show(adap, sf);
|
||||
}
|
||||
|
||||
static int cec_error_inj_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, cec_error_inj_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations cec_error_inj_fops = {
|
||||
.open = cec_error_inj_open,
|
||||
.write = cec_error_inj_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
||||
void *priv, const char *name, u32 caps,
|
||||
u8 available_las)
|
||||
@@ -346,7 +383,16 @@ int cec_register_adapter(struct cec_adapter *adap,
|
||||
pr_warn("cec-%s: Failed to create status file\n", adap->name);
|
||||
debugfs_remove_recursive(adap->cec_dir);
|
||||
adap->cec_dir = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line)
|
||||
return 0;
|
||||
adap->error_inj_file = debugfs_create_file("error-inj", 0644,
|
||||
adap->cec_dir, adap,
|
||||
&cec_error_inj_fops);
|
||||
if (IS_ERR_OR_NULL(adap->error_inj_file))
|
||||
pr_warn("cec-%s: Failed to create error-inj file\n",
|
||||
adap->name);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
|
||||
*
|
||||
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* cec-notifier.c - notify CEC drivers of physical address changes
|
||||
*
|
||||
* Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
|
||||
* Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
|
||||
342
drivers/media/cec/cec-pin-error-inj.c
Normal file
342
drivers/media/cec/cec-pin-error-inj.c
Normal file
@@ -0,0 +1,342 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched/types.h>
|
||||
|
||||
#include <media/cec-pin.h>
|
||||
#include "cec-pin-priv.h"
|
||||
|
||||
struct cec_error_inj_cmd {
|
||||
unsigned int mode_offset;
|
||||
int arg_idx;
|
||||
const char *cmd;
|
||||
};
|
||||
|
||||
static const struct cec_error_inj_cmd cec_error_inj_cmds[] = {
|
||||
{ CEC_ERROR_INJ_RX_NACK_OFFSET, -1, "rx-nack" },
|
||||
{ CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET,
|
||||
CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX, "rx-low-drive" },
|
||||
{ CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET, -1, "rx-add-byte" },
|
||||
{ CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET, -1, "rx-remove-byte" },
|
||||
{ CEC_ERROR_INJ_RX_ARB_LOST_OFFSET,
|
||||
CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX, "rx-arb-lost" },
|
||||
|
||||
{ CEC_ERROR_INJ_TX_NO_EOM_OFFSET, -1, "tx-no-eom" },
|
||||
{ CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET, -1, "tx-early-eom" },
|
||||
{ CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET,
|
||||
CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX, "tx-add-bytes" },
|
||||
{ CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET, -1, "tx-remove-byte" },
|
||||
{ CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET,
|
||||
CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX, "tx-short-bit" },
|
||||
{ CEC_ERROR_INJ_TX_LONG_BIT_OFFSET,
|
||||
CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX, "tx-long-bit" },
|
||||
{ CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET,
|
||||
CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX, "tx-custom-bit" },
|
||||
{ CEC_ERROR_INJ_TX_SHORT_START_OFFSET, -1, "tx-short-start" },
|
||||
{ CEC_ERROR_INJ_TX_LONG_START_OFFSET, -1, "tx-long-start" },
|
||||
{ CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET, -1, "tx-custom-start" },
|
||||
{ CEC_ERROR_INJ_TX_LAST_BIT_OFFSET,
|
||||
CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX, "tx-last-bit" },
|
||||
{ CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET,
|
||||
CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX, "tx-low-drive" },
|
||||
{ 0, -1, NULL }
|
||||
};
|
||||
|
||||
u16 cec_pin_rx_error_inj(struct cec_pin *pin)
|
||||
{
|
||||
u16 cmd = CEC_ERROR_INJ_OP_ANY;
|
||||
|
||||
/* Only when 18 bits have been received do we have a valid cmd */
|
||||
if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) &&
|
||||
pin->rx_bit >= 18)
|
||||
cmd = pin->rx_msg.msg[1];
|
||||
return (pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) ? cmd :
|
||||
CEC_ERROR_INJ_OP_ANY;
|
||||
}
|
||||
|
||||
u16 cec_pin_tx_error_inj(struct cec_pin *pin)
|
||||
{
|
||||
u16 cmd = CEC_ERROR_INJ_OP_ANY;
|
||||
|
||||
if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) &&
|
||||
pin->tx_msg.len > 1)
|
||||
cmd = pin->tx_msg.msg[1];
|
||||
return (pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) ? cmd :
|
||||
CEC_ERROR_INJ_OP_ANY;
|
||||
}
|
||||
|
||||
bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line)
|
||||
{
|
||||
static const char *delims = " \t\r";
|
||||
struct cec_pin *pin = adap->pin;
|
||||
unsigned int i;
|
||||
bool has_pos = false;
|
||||
char *p = line;
|
||||
char *token;
|
||||
char *comma;
|
||||
u64 *error;
|
||||
u8 *args;
|
||||
bool has_op;
|
||||
u32 op;
|
||||
u8 mode;
|
||||
u8 pos;
|
||||
u8 v;
|
||||
|
||||
p = skip_spaces(p);
|
||||
token = strsep(&p, delims);
|
||||
if (!strcmp(token, "clear")) {
|
||||
memset(pin->error_inj, 0, sizeof(pin->error_inj));
|
||||
pin->rx_toggle = pin->tx_toggle = false;
|
||||
pin->tx_ignore_nack_until_eom = false;
|
||||
pin->tx_custom_pulse = false;
|
||||
pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "rx-clear")) {
|
||||
for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++)
|
||||
pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK;
|
||||
pin->rx_toggle = false;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-clear")) {
|
||||
for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++)
|
||||
pin->error_inj[i] &= ~CEC_ERROR_INJ_TX_MASK;
|
||||
pin->tx_toggle = false;
|
||||
pin->tx_ignore_nack_until_eom = false;
|
||||
pin->tx_custom_pulse = false;
|
||||
pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-ignore-nack-until-eom")) {
|
||||
pin->tx_ignore_nack_until_eom = true;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-custom-pulse")) {
|
||||
pin->tx_custom_pulse = true;
|
||||
cec_pin_start_timer(pin);
|
||||
return true;
|
||||
}
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
p = skip_spaces(p);
|
||||
if (!strcmp(token, "tx-custom-low-usecs")) {
|
||||
u32 usecs;
|
||||
|
||||
if (kstrtou32(p, 0, &usecs) || usecs > 10000000)
|
||||
return false;
|
||||
pin->tx_custom_low_usecs = usecs;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-custom-high-usecs")) {
|
||||
u32 usecs;
|
||||
|
||||
if (kstrtou32(p, 0, &usecs) || usecs > 10000000)
|
||||
return false;
|
||||
pin->tx_custom_high_usecs = usecs;
|
||||
return true;
|
||||
}
|
||||
|
||||
comma = strchr(token, ',');
|
||||
if (comma)
|
||||
*comma++ = '\0';
|
||||
if (!strcmp(token, "any"))
|
||||
op = CEC_ERROR_INJ_OP_ANY;
|
||||
else if (!kstrtou8(token, 0, &v))
|
||||
op = v;
|
||||
else
|
||||
return false;
|
||||
mode = CEC_ERROR_INJ_MODE_ONCE;
|
||||
if (comma) {
|
||||
if (!strcmp(comma, "off"))
|
||||
mode = CEC_ERROR_INJ_MODE_OFF;
|
||||
else if (!strcmp(comma, "once"))
|
||||
mode = CEC_ERROR_INJ_MODE_ONCE;
|
||||
else if (!strcmp(comma, "always"))
|
||||
mode = CEC_ERROR_INJ_MODE_ALWAYS;
|
||||
else if (!strcmp(comma, "toggle"))
|
||||
mode = CEC_ERROR_INJ_MODE_TOGGLE;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
error = pin->error_inj + op;
|
||||
args = pin->error_inj_args[op];
|
||||
has_op = op <= 0xff;
|
||||
|
||||
token = strsep(&p, delims);
|
||||
if (p) {
|
||||
p = skip_spaces(p);
|
||||
has_pos = !kstrtou8(p, 0, &pos);
|
||||
}
|
||||
|
||||
if (!strcmp(token, "clear")) {
|
||||
*error = 0;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "rx-clear")) {
|
||||
*error &= ~CEC_ERROR_INJ_RX_MASK;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-clear")) {
|
||||
*error &= ~CEC_ERROR_INJ_TX_MASK;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; cec_error_inj_cmds[i].cmd; i++) {
|
||||
const char *cmd = cec_error_inj_cmds[i].cmd;
|
||||
unsigned int mode_offset;
|
||||
u64 mode_mask;
|
||||
int arg_idx;
|
||||
bool is_bit_pos = true;
|
||||
|
||||
if (strcmp(token, cmd))
|
||||
continue;
|
||||
|
||||
mode_offset = cec_error_inj_cmds[i].mode_offset;
|
||||
mode_mask = CEC_ERROR_INJ_MODE_MASK << mode_offset;
|
||||
arg_idx = cec_error_inj_cmds[i].arg_idx;
|
||||
|
||||
if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET ||
|
||||
mode_offset == CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET)
|
||||
is_bit_pos = false;
|
||||
|
||||
if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET) {
|
||||
if (has_op)
|
||||
return false;
|
||||
if (!has_pos)
|
||||
pos = 0x0f;
|
||||
}
|
||||
if (arg_idx >= 0 && is_bit_pos) {
|
||||
if (!has_pos || pos >= 160)
|
||||
return false;
|
||||
if (has_op && pos < 10 + 8)
|
||||
return false;
|
||||
/* Invalid bit position may not be the Ack bit */
|
||||
if ((mode_offset == CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET ||
|
||||
mode_offset == CEC_ERROR_INJ_TX_LONG_BIT_OFFSET ||
|
||||
mode_offset == CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET) &&
|
||||
(pos % 10) == 9)
|
||||
return false;
|
||||
}
|
||||
*error &= ~mode_mask;
|
||||
*error |= (u64)mode << mode_offset;
|
||||
if (arg_idx >= 0)
|
||||
args[arg_idx] = pos;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void cec_pin_show_cmd(struct seq_file *sf, u32 cmd, u8 mode)
|
||||
{
|
||||
if (cmd == CEC_ERROR_INJ_OP_ANY)
|
||||
seq_puts(sf, "any,");
|
||||
else
|
||||
seq_printf(sf, "0x%02x,", cmd);
|
||||
switch (mode) {
|
||||
case CEC_ERROR_INJ_MODE_ONCE:
|
||||
seq_puts(sf, "once ");
|
||||
break;
|
||||
case CEC_ERROR_INJ_MODE_ALWAYS:
|
||||
seq_puts(sf, "always ");
|
||||
break;
|
||||
case CEC_ERROR_INJ_MODE_TOGGLE:
|
||||
seq_puts(sf, "toggle ");
|
||||
break;
|
||||
default:
|
||||
seq_puts(sf, "off ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf)
|
||||
{
|
||||
struct cec_pin *pin = adap->pin;
|
||||
unsigned int i, j;
|
||||
|
||||
seq_puts(sf, "# Clear error injections:\n");
|
||||
seq_puts(sf, "# clear clear all rx and tx error injections\n");
|
||||
seq_puts(sf, "# rx-clear clear all rx error injections\n");
|
||||
seq_puts(sf, "# tx-clear clear all tx error injections\n");
|
||||
seq_puts(sf, "# <op> clear clear all rx and tx error injections for <op>\n");
|
||||
seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n");
|
||||
seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n");
|
||||
seq_puts(sf, "#\n");
|
||||
seq_puts(sf, "# RX error injection:\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] rx-add-byte add a spurious byte to the received CEC message\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] rx-remove-byte remove the last byte from the received CEC message\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] rx-arb-lost <poll> generate a POLL message to trigger an arbitration lost\n");
|
||||
seq_puts(sf, "#\n");
|
||||
seq_puts(sf, "# TX error injection settings:\n");
|
||||
seq_puts(sf, "# tx-ignore-nack-until-eom ignore early NACKs until EOM\n");
|
||||
seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n");
|
||||
seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n");
|
||||
seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n");
|
||||
seq_puts(sf, "#\n");
|
||||
seq_puts(sf, "# TX error injection:\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-no-eom don't set the EOM bit\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-early-eom set the EOM bit one byte too soon\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-add-bytes <num> append <num> (1-255) spurious bytes to the message\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-remove-byte drop the last byte from the message\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-short-bit <bit> make this bit shorter than allowed\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-long-bit <bit> make this bit longer than allowed\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-custom-bit <bit> send the custom pulse instead of this bit\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-short-start send a start pulse that's too short\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-long-start send a start pulse that's too long\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-custom-start send the custom pulse instead of the start pulse\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-last-bit <bit> stop sending after this bit\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-low-drive <bit> force a low-drive condition at this bit position\n");
|
||||
seq_puts(sf, "#\n");
|
||||
seq_puts(sf, "# <op> CEC message opcode (0-255) or 'any'\n");
|
||||
seq_puts(sf, "# <mode> 'once' (default), 'always', 'toggle' or 'off'\n");
|
||||
seq_puts(sf, "# <bit> CEC message bit (0-159)\n");
|
||||
seq_puts(sf, "# 10 bits per 'byte': bits 0-7: data, bit 8: EOM, bit 9: ACK\n");
|
||||
seq_puts(sf, "# <poll> CEC poll message used to test arbitration lost (0x00-0xff, default 0x0f)\n");
|
||||
seq_puts(sf, "# <usecs> microseconds (0-10000000, default 1000)\n");
|
||||
|
||||
seq_puts(sf, "\nclear\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pin->error_inj); i++) {
|
||||
u64 e = pin->error_inj[i];
|
||||
|
||||
for (j = 0; cec_error_inj_cmds[j].cmd; j++) {
|
||||
const char *cmd = cec_error_inj_cmds[j].cmd;
|
||||
unsigned int mode;
|
||||
unsigned int mode_offset;
|
||||
int arg_idx;
|
||||
|
||||
mode_offset = cec_error_inj_cmds[j].mode_offset;
|
||||
arg_idx = cec_error_inj_cmds[j].arg_idx;
|
||||
mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK;
|
||||
if (!mode)
|
||||
continue;
|
||||
cec_pin_show_cmd(sf, i, mode);
|
||||
seq_puts(sf, cmd);
|
||||
if (arg_idx >= 0)
|
||||
seq_printf(sf, " %u",
|
||||
pin->error_inj_args[i][arg_idx]);
|
||||
seq_puts(sf, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (pin->tx_ignore_nack_until_eom)
|
||||
seq_puts(sf, "tx-ignore-nack-until-eom\n");
|
||||
if (pin->tx_custom_pulse)
|
||||
seq_puts(sf, "tx-custom-pulse\n");
|
||||
if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT)
|
||||
seq_printf(sf, "tx-custom-low-usecs %u\n",
|
||||
pin->tx_custom_low_usecs);
|
||||
if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT)
|
||||
seq_printf(sf, "tx-custom-high-usecs %u\n",
|
||||
pin->tx_custom_high_usecs);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,20 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* cec-pin-priv.h - internal cec-pin header
|
||||
*
|
||||
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LINUX_CEC_PIN_PRIV_H
|
||||
@@ -40,14 +28,30 @@ enum cec_pin_state {
|
||||
CEC_ST_TX_START_BIT_LOW,
|
||||
/* Drive CEC high for the start bit */
|
||||
CEC_ST_TX_START_BIT_HIGH,
|
||||
/* Generate a start bit period that is too short */
|
||||
CEC_ST_TX_START_BIT_HIGH_SHORT,
|
||||
/* Generate a start bit period that is too long */
|
||||
CEC_ST_TX_START_BIT_HIGH_LONG,
|
||||
/* Drive CEC low for the start bit using the custom timing */
|
||||
CEC_ST_TX_START_BIT_LOW_CUSTOM,
|
||||
/* Drive CEC high for the start bit using the custom timing */
|
||||
CEC_ST_TX_START_BIT_HIGH_CUSTOM,
|
||||
/* Drive CEC low for the 0 bit */
|
||||
CEC_ST_TX_DATA_BIT_0_LOW,
|
||||
/* Drive CEC high for the 0 bit */
|
||||
CEC_ST_TX_DATA_BIT_0_HIGH,
|
||||
/* Generate a bit period that is too short */
|
||||
CEC_ST_TX_DATA_BIT_0_HIGH_SHORT,
|
||||
/* Generate a bit period that is too long */
|
||||
CEC_ST_TX_DATA_BIT_0_HIGH_LONG,
|
||||
/* Drive CEC low for the 1 bit */
|
||||
CEC_ST_TX_DATA_BIT_1_LOW,
|
||||
/* Drive CEC high for the 1 bit */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH,
|
||||
/* Generate a bit period that is too short */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_SHORT,
|
||||
/* Generate a bit period that is too long */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_LONG,
|
||||
/*
|
||||
* Wait for start of sample time to check for Ack bit or first
|
||||
* four initiator bits to check for Arbitration Lost.
|
||||
@@ -55,6 +59,20 @@ enum cec_pin_state {
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE,
|
||||
/* Wait for end of bit period after sampling */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE,
|
||||
/* Generate a bit period that is too short */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT,
|
||||
/* Generate a bit period that is too long */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG,
|
||||
/* Drive CEC low for a data bit using the custom timing */
|
||||
CEC_ST_TX_DATA_BIT_LOW_CUSTOM,
|
||||
/* Drive CEC high for a data bit using the custom timing */
|
||||
CEC_ST_TX_DATA_BIT_HIGH_CUSTOM,
|
||||
/* Drive CEC low for a standalone pulse using the custom timing */
|
||||
CEC_ST_TX_PULSE_LOW_CUSTOM,
|
||||
/* Drive CEC high for a standalone pulse using the custom timing */
|
||||
CEC_ST_TX_PULSE_HIGH_CUSTOM,
|
||||
/* Start low drive */
|
||||
CEC_ST_TX_LOW_DRIVE,
|
||||
|
||||
/* Rx states */
|
||||
|
||||
@@ -66,8 +84,8 @@ enum cec_pin_state {
|
||||
CEC_ST_RX_DATA_SAMPLE,
|
||||
/* Wait for earliest end of bit period after sampling */
|
||||
CEC_ST_RX_DATA_POST_SAMPLE,
|
||||
/* Wait for CEC to go high (i.e. end of bit period */
|
||||
CEC_ST_RX_DATA_HIGH,
|
||||
/* Wait for CEC to go low (i.e. end of bit period) */
|
||||
CEC_ST_RX_DATA_WAIT_FOR_LOW,
|
||||
/* Drive CEC low to send 0 Ack bit */
|
||||
CEC_ST_RX_ACK_LOW,
|
||||
/* End of 0 Ack time, wait for earliest end of bit period */
|
||||
@@ -76,9 +94,9 @@ enum cec_pin_state {
|
||||
CEC_ST_RX_ACK_HIGH_POST,
|
||||
/* Wait for earliest end of bit period and end of message */
|
||||
CEC_ST_RX_ACK_FINISH,
|
||||
|
||||
/* Start low drive */
|
||||
CEC_ST_LOW_DRIVE,
|
||||
CEC_ST_RX_LOW_DRIVE,
|
||||
|
||||
/* Monitor pin using interrupts */
|
||||
CEC_ST_RX_IRQ,
|
||||
|
||||
@@ -86,7 +104,58 @@ enum cec_pin_state {
|
||||
CEC_PIN_STATES
|
||||
};
|
||||
|
||||
#define CEC_NUM_PIN_EVENTS 128
|
||||
/* Error Injection */
|
||||
|
||||
/* Error injection modes */
|
||||
#define CEC_ERROR_INJ_MODE_OFF 0
|
||||
#define CEC_ERROR_INJ_MODE_ONCE 1
|
||||
#define CEC_ERROR_INJ_MODE_ALWAYS 2
|
||||
#define CEC_ERROR_INJ_MODE_TOGGLE 3
|
||||
#define CEC_ERROR_INJ_MODE_MASK 3ULL
|
||||
|
||||
/* Receive error injection options */
|
||||
#define CEC_ERROR_INJ_RX_NACK_OFFSET 0
|
||||
#define CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET 2
|
||||
#define CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET 4
|
||||
#define CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET 6
|
||||
#define CEC_ERROR_INJ_RX_ARB_LOST_OFFSET 8
|
||||
#define CEC_ERROR_INJ_RX_MASK 0xffffULL
|
||||
|
||||
/* Transmit error injection options */
|
||||
#define CEC_ERROR_INJ_TX_NO_EOM_OFFSET 16
|
||||
#define CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET 18
|
||||
#define CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET 20
|
||||
#define CEC_ERROR_INJ_TX_LONG_BIT_OFFSET 22
|
||||
#define CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET 24
|
||||
#define CEC_ERROR_INJ_TX_SHORT_START_OFFSET 26
|
||||
#define CEC_ERROR_INJ_TX_LONG_START_OFFSET 28
|
||||
#define CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET 30
|
||||
#define CEC_ERROR_INJ_TX_LAST_BIT_OFFSET 32
|
||||
#define CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET 34
|
||||
#define CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET 36
|
||||
#define CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET 38
|
||||
#define CEC_ERROR_INJ_TX_MASK 0xffffffffffff0000ULL
|
||||
|
||||
#define CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX 0
|
||||
#define CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX 1
|
||||
|
||||
#define CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX 2
|
||||
#define CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX 3
|
||||
#define CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX 4
|
||||
#define CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX 5
|
||||
#define CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX 6
|
||||
#define CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX 7
|
||||
#define CEC_ERROR_INJ_NUM_ARGS 8
|
||||
|
||||
/* Special CEC op values */
|
||||
#define CEC_ERROR_INJ_OP_ANY 0x00000100
|
||||
|
||||
/* The default for the low/high time of the custom pulse */
|
||||
#define CEC_TIM_CUSTOM_DEFAULT 1000
|
||||
|
||||
#define CEC_NUM_PIN_EVENTS 128
|
||||
#define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0)
|
||||
#define CEC_PIN_EVENT_FL_DROPPED (1 << 1)
|
||||
|
||||
#define CEC_PIN_IRQ_UNCHANGED 0
|
||||
#define CEC_PIN_IRQ_DISABLE 1
|
||||
@@ -110,24 +179,63 @@ struct cec_pin {
|
||||
u32 tx_bit;
|
||||
bool tx_nacked;
|
||||
u32 tx_signal_free_time;
|
||||
bool tx_toggle;
|
||||
struct cec_msg rx_msg;
|
||||
u32 rx_bit;
|
||||
bool rx_toggle;
|
||||
u32 rx_start_bit_low_too_short_cnt;
|
||||
u64 rx_start_bit_low_too_short_ts;
|
||||
u32 rx_start_bit_low_too_short_delta;
|
||||
u32 rx_start_bit_too_short_cnt;
|
||||
u64 rx_start_bit_too_short_ts;
|
||||
u32 rx_start_bit_too_short_delta;
|
||||
u32 rx_start_bit_too_long_cnt;
|
||||
u32 rx_data_bit_too_short_cnt;
|
||||
u64 rx_data_bit_too_short_ts;
|
||||
u32 rx_data_bit_too_short_delta;
|
||||
u32 rx_data_bit_too_long_cnt;
|
||||
u32 rx_low_drive_cnt;
|
||||
|
||||
struct cec_msg work_rx_msg;
|
||||
u8 work_tx_status;
|
||||
ktime_t work_tx_ts;
|
||||
atomic_t work_irq_change;
|
||||
atomic_t work_pin_events;
|
||||
atomic_t work_pin_num_events;
|
||||
unsigned int work_pin_events_wr;
|
||||
unsigned int work_pin_events_rd;
|
||||
ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS];
|
||||
bool work_pin_is_high[CEC_NUM_PIN_EVENTS];
|
||||
u8 work_pin_events[CEC_NUM_PIN_EVENTS];
|
||||
bool work_pin_events_dropped;
|
||||
u32 work_pin_events_dropped_cnt;
|
||||
ktime_t timer_ts;
|
||||
u32 timer_cnt;
|
||||
u32 timer_100ms_overruns;
|
||||
u32 timer_300ms_overruns;
|
||||
u32 timer_max_overrun;
|
||||
u32 timer_sum_overrun;
|
||||
|
||||
u32 tx_custom_low_usecs;
|
||||
u32 tx_custom_high_usecs;
|
||||
bool tx_ignore_nack_until_eom;
|
||||
bool tx_custom_pulse;
|
||||
bool tx_generated_poll;
|
||||
bool tx_post_eom;
|
||||
u8 tx_extra_bytes;
|
||||
u32 tx_low_drive_cnt;
|
||||
#ifdef CONFIG_CEC_PIN_ERROR_INJ
|
||||
u64 error_inj[CEC_ERROR_INJ_OP_ANY + 1];
|
||||
u8 error_inj_args[CEC_ERROR_INJ_OP_ANY + 1][CEC_ERROR_INJ_NUM_ARGS];
|
||||
#endif
|
||||
};
|
||||
|
||||
void cec_pin_start_timer(struct cec_pin *pin);
|
||||
|
||||
#ifdef CONFIG_CEC_PIN_ERROR_INJ
|
||||
bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line);
|
||||
int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf);
|
||||
|
||||
u16 cec_pin_rx_error_inj(struct cec_pin *pin);
|
||||
u16 cec_pin_tx_error_inj(struct cec_pin *pin);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* cec-priv.h - HDMI Consumer Electronics Control internal header
|
||||
*
|
||||
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _CEC_PRIV_H
|
||||
|
||||
@@ -631,7 +631,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
|
||||
|
||||
cb->p = buffer;
|
||||
cb->offset_in_common = buffer - (u8 *) common_buffer;
|
||||
cb->phys = common_buffer_phys + cb->offset_in_common;
|
||||
if (common_buffer_phys)
|
||||
cb->phys = common_buffer_phys + cb->offset_in_common;
|
||||
|
||||
return cb;
|
||||
}
|
||||
@@ -690,17 +691,21 @@ int smscore_register_device(struct smsdevice_params_t *params,
|
||||
|
||||
/* alloc common buffer */
|
||||
dev->common_buffer_size = params->buffer_size * params->num_buffers;
|
||||
dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
|
||||
&dev->common_buffer_phys,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!dev->common_buffer) {
|
||||
if (params->usb_device)
|
||||
buffer = kzalloc(dev->common_buffer_size, GFP_KERNEL);
|
||||
else
|
||||
buffer = dma_alloc_coherent(params->device,
|
||||
dev->common_buffer_size,
|
||||
&dev->common_buffer_phys,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!buffer) {
|
||||
smscore_unregister_device(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev->common_buffer = buffer;
|
||||
|
||||
/* prepare dma buffers */
|
||||
for (buffer = dev->common_buffer;
|
||||
dev->num_buffers < params->num_buffers;
|
||||
for (; dev->num_buffers < params->num_buffers;
|
||||
dev->num_buffers++, buffer += params->buffer_size) {
|
||||
struct smscore_buffer_t *cb;
|
||||
|
||||
@@ -720,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
|
||||
dev->board_id = SMS_BOARD_UNKNOWN;
|
||||
dev->context = params->context;
|
||||
dev->device = params->device;
|
||||
dev->usb_device = params->usb_device;
|
||||
dev->setmode_handler = params->setmode_handler;
|
||||
dev->detectmode_handler = params->detectmode_handler;
|
||||
dev->sendrequest_handler = params->sendrequest_handler;
|
||||
@@ -1231,10 +1237,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
|
||||
|
||||
pr_debug("freed %d buffers\n", num_buffers);
|
||||
|
||||
if (coredev->common_buffer)
|
||||
dma_free_coherent(NULL, coredev->common_buffer_size,
|
||||
coredev->common_buffer, coredev->common_buffer_phys);
|
||||
|
||||
if (coredev->common_buffer) {
|
||||
if (coredev->usb_device)
|
||||
kfree(coredev->common_buffer);
|
||||
else
|
||||
dma_free_coherent(coredev->device,
|
||||
coredev->common_buffer_size,
|
||||
coredev->common_buffer,
|
||||
coredev->common_buffer_phys);
|
||||
}
|
||||
kfree(coredev->fw_buf);
|
||||
|
||||
list_del(&coredev->entry);
|
||||
|
||||
@@ -134,6 +134,7 @@ struct smscore_buffer_t {
|
||||
|
||||
struct smsdevice_params_t {
|
||||
struct device *device;
|
||||
struct usb_device *usb_device;
|
||||
|
||||
int buffer_size;
|
||||
int num_buffers;
|
||||
@@ -176,6 +177,7 @@ struct smscore_device_t {
|
||||
|
||||
void *context;
|
||||
struct device *device;
|
||||
struct usb_device *usb_device;
|
||||
|
||||
char devpath[32];
|
||||
unsigned long device_flags;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* v4l2-tpg-colors.c - A table that converts colors to various colorspaces
|
||||
*
|
||||
@@ -20,19 +21,6 @@
|
||||
* in order to preserve precision.
|
||||
*
|
||||
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* v4l2-tpg-core.c - Test Pattern Generator
|
||||
*
|
||||
@@ -5,19 +6,6 @@
|
||||
* vivi.c source for the copyright information of those functions.
|
||||
*
|
||||
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -1155,13 +1143,13 @@ static void gen_twopix(struct tpg_data *tpg,
|
||||
case V4L2_PIX_FMT_NV24:
|
||||
buf[0][offset] = r_y_h;
|
||||
buf[1][2 * offset] = g_u_s;
|
||||
buf[1][2 * offset + 1] = b_v;
|
||||
buf[1][(2 * offset + 1) % 8] = b_v;
|
||||
break;
|
||||
|
||||
case V4L2_PIX_FMT_NV42:
|
||||
buf[0][offset] = r_y_h;
|
||||
buf[1][2 * offset] = b_v;
|
||||
buf[1][2 * offset + 1] = g_u_s;
|
||||
buf[1][(2 * offset + 1) %8] = g_u_s;
|
||||
break;
|
||||
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
|
||||
@@ -1696,6 +1696,15 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
|
||||
for (i = 0; i < q->num_buffers; ++i) {
|
||||
struct vb2_buffer *vb = q->bufs[i];
|
||||
|
||||
if (vb->state == VB2_BUF_STATE_PREPARED ||
|
||||
vb->state == VB2_BUF_STATE_QUEUED) {
|
||||
unsigned int plane;
|
||||
|
||||
for (plane = 0; plane < vb->num_planes; ++plane)
|
||||
call_void_memop(vb, finish,
|
||||
vb->planes[plane].mem_priv);
|
||||
}
|
||||
|
||||
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
|
||||
vb->state = VB2_BUF_STATE_PREPARED;
|
||||
call_void_vb_qop(vb, buf_finish, vb);
|
||||
|
||||
@@ -106,7 +106,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr,
|
||||
if (nums[i-1] + 1 != nums[i])
|
||||
goto fail_map;
|
||||
buf->vaddr = (__force void *)
|
||||
ioremap_nocache(nums[0] << PAGE_SHIFT, size);
|
||||
ioremap_nocache(__pfn_to_phys(nums[0]), size + offset);
|
||||
} else {
|
||||
buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
|
||||
PAGE_KERNEL);
|
||||
|
||||
@@ -1254,8 +1254,8 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca,
|
||||
ca->pub->slot_ts_enable(ca->pub, slot);
|
||||
sl->slot_state = DVB_CA_SLOTSTATE_RUNNING;
|
||||
dvb_ca_en50221_thread_update_delay(ca);
|
||||
pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
|
||||
ca->dvbdev->adapter->num);
|
||||
pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
|
||||
ca->dvbdev->adapter->num);
|
||||
break;
|
||||
|
||||
case DVB_CA_SLOTSTATE_RUNNING:
|
||||
|
||||
@@ -2294,7 +2294,7 @@ static int dvb_frontend_handle_ioctl(struct file *file,
|
||||
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
@@ -2328,7 +2328,7 @@ static int dvb_frontend_handle_ioctl(struct file *file,
|
||||
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
@@ -941,6 +942,55 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
struct i2c_client *dvb_module_probe(const char *module_name,
|
||||
const char *name,
|
||||
struct i2c_adapter *adap,
|
||||
unsigned char addr,
|
||||
void *platform_data)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct i2c_board_info *board_info;
|
||||
|
||||
board_info = kzalloc(sizeof(*board_info), GFP_KERNEL);
|
||||
if (!board_info)
|
||||
return NULL;
|
||||
|
||||
if (name)
|
||||
strlcpy(board_info->type, name, I2C_NAME_SIZE);
|
||||
else
|
||||
strlcpy(board_info->type, module_name, I2C_NAME_SIZE);
|
||||
|
||||
board_info->addr = addr;
|
||||
board_info->platform_data = platform_data;
|
||||
request_module(module_name);
|
||||
client = i2c_new_device(adap, board_info);
|
||||
if (client == NULL || client->dev.driver == NULL) {
|
||||
kfree(board_info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!try_module_get(client->dev.driver->owner)) {
|
||||
i2c_unregister_device(client);
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
kfree(board_info);
|
||||
return client;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dvb_module_probe);
|
||||
|
||||
void dvb_module_release(struct i2c_client *client)
|
||||
{
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
module_put(client->dev.driver->owner);
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dvb_module_release);
|
||||
#endif
|
||||
|
||||
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct dvb_device *dvbdev = dev_get_drvdata(dev);
|
||||
|
||||
@@ -462,7 +462,7 @@ config DVB_TDA10048
|
||||
|
||||
config DVB_AF9013
|
||||
tristate "Afatech AF9013 demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
depends on DVB_CORE && I2C && I2C_MUX
|
||||
select REGMAP
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
@@ -546,6 +546,8 @@ config DVB_GP8PSK_FE
|
||||
depends on DVB_CORE
|
||||
default DVB_USB_GP8PSK
|
||||
|
||||
source "drivers/media/dvb-frontends/cxd2880/Kconfig"
|
||||
|
||||
comment "DVB-C (cable) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
@@ -822,13 +824,6 @@ config DVB_A8293
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
config DVB_SP2
|
||||
tristate "CIMaX SP2"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
CIMaX SP2/SP2HF Common Interface module.
|
||||
|
||||
config DVB_LGS8GL5
|
||||
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
@@ -904,6 +899,27 @@ config DVB_HELENE
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Common Interface (EN50221) controller drivers"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_CXD2099
|
||||
tristate "CXD2099AR Common Interface driver"
|
||||
depends on DVB_CORE && I2C
|
||||
select REGMAP_I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for the CI controller currently found mostly on
|
||||
Digital Devices DuoFlex CI (single) addon modules.
|
||||
|
||||
Say Y when you want to support these devices.
|
||||
|
||||
config DVB_SP2
|
||||
tristate "CIMaX SP2"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
CIMaX SP2/SP2HF Common Interface module.
|
||||
|
||||
comment "Tools to develop new frontends"
|
||||
|
||||
config DVB_DUMMY_FE
|
||||
|
||||
@@ -129,3 +129,5 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o
|
||||
obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o
|
||||
obj-$(CONFIG_DVB_HELENE) += helene.o
|
||||
obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o
|
||||
obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
|
||||
obj-$(CONFIG_DVB_CXD2880) += cxd2880/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,13 +38,9 @@
|
||||
* @api_version: Firmware API version.
|
||||
* @gpio: GPIOs.
|
||||
* @get_dvb_frontend: Get DVB frontend callback.
|
||||
*
|
||||
* AF9013/5 GPIOs (mostly guessed):
|
||||
* * demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
|
||||
* * demod#1-gpio#1 - xtal setting (?)
|
||||
* * demod#1-gpio#3 - tuner#1
|
||||
* * demod#2-gpio#0 - tuner#2
|
||||
* * demod#2-gpio#1 - xtal setting (?)
|
||||
* @get_i2c_adapter: Get I2C adapter.
|
||||
* @pid_filter_ctrl: Control PID filter.
|
||||
* @pid_filter: Set PID to PID filter.
|
||||
*/
|
||||
struct af9013_platform_data {
|
||||
/*
|
||||
@@ -84,36 +80,18 @@ struct af9013_platform_data {
|
||||
u8 gpio[4];
|
||||
|
||||
struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
|
||||
|
||||
/* private: For legacy media attach wrapper. Do not set value. */
|
||||
bool attach_in_use;
|
||||
u8 i2c_addr;
|
||||
u32 clock;
|
||||
struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *);
|
||||
int (*pid_filter_ctrl)(struct dvb_frontend *, int);
|
||||
int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
|
||||
};
|
||||
|
||||
#define af9013_config af9013_platform_data
|
||||
#define AF9013_TS_USB AF9013_TS_MODE_USB
|
||||
#define AF9013_TS_PARALLEL AF9013_TS_MODE_PARALLEL
|
||||
#define AF9013_TS_SERIAL AF9013_TS_MODE_SERIAL
|
||||
|
||||
#if IS_REACHABLE(CONFIG_DVB_AF9013)
|
||||
/**
|
||||
* Attach an af9013 demod
|
||||
*
|
||||
* @config: pointer to &struct af9013_config with demod configuration.
|
||||
* @i2c: i2c adapter to use.
|
||||
*
|
||||
* return: FE pointer on success, NULL on failure.
|
||||
/*
|
||||
* AF9013/5 GPIOs (mostly guessed)
|
||||
* demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
|
||||
* demod#1-gpio#1 - xtal setting (?)
|
||||
* demod#1-gpio#3 - tuner#1
|
||||
* demod#2-gpio#0 - tuner#2
|
||||
* demod#2-gpio#1 - xtal setting (?)
|
||||
*/
|
||||
extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *af9013_attach(
|
||||
const struct af9013_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
pr_warn("%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_AF9013 */
|
||||
|
||||
#endif /* AF9013_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
704
drivers/media/dvb-frontends/cxd2099.c
Normal file
704
drivers/media/dvb-frontends/cxd2099.c
Normal file
@@ -0,0 +1,704 @@
|
||||
/*
|
||||
* cxd2099.c: Driver for the CXD2099AR Common Interface Controller
|
||||
*
|
||||
* Copyright (C) 2010-2013 Digital Devices GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "cxd2099.h"
|
||||
|
||||
static int buffermode;
|
||||
module_param(buffermode, int, 0444);
|
||||
MODULE_PARM_DESC(buffermode, "Enable CXD2099AR buffer mode (default: disabled)");
|
||||
|
||||
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
|
||||
|
||||
struct cxd {
|
||||
struct dvb_ca_en50221 en;
|
||||
|
||||
struct cxd2099_cfg cfg;
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
|
||||
u8 regs[0x23];
|
||||
u8 lastaddress;
|
||||
u8 clk_reg_f;
|
||||
u8 clk_reg_b;
|
||||
int mode;
|
||||
int ready;
|
||||
int dr;
|
||||
int write_busy;
|
||||
int slot_stat;
|
||||
|
||||
u8 amem[1024];
|
||||
int amem_read;
|
||||
|
||||
int cammode;
|
||||
struct mutex lock; /* device access lock */
|
||||
|
||||
u8 rbuf[1028];
|
||||
u8 wbuf[1028];
|
||||
};
|
||||
|
||||
static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (ci->lastaddress != adr)
|
||||
status = regmap_write(ci->regmap, 0, adr);
|
||||
if (!status) {
|
||||
ci->lastaddress = adr;
|
||||
|
||||
while (n) {
|
||||
int len = n;
|
||||
|
||||
if (ci->cfg.max_i2c && len > ci->cfg.max_i2c)
|
||||
len = ci->cfg.max_i2c;
|
||||
status = regmap_raw_read(ci->regmap, 1, data, len);
|
||||
if (status)
|
||||
return status;
|
||||
data += len;
|
||||
n -= len;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int read_reg(struct cxd *ci, u8 reg, u8 *val)
|
||||
{
|
||||
return read_block(ci, reg, val, 1);
|
||||
}
|
||||
|
||||
static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
|
||||
{
|
||||
int status;
|
||||
u8 addr[2] = {address & 0xff, address >> 8};
|
||||
|
||||
status = regmap_raw_write(ci->regmap, 2, addr, 2);
|
||||
if (!status)
|
||||
status = regmap_raw_read(ci->regmap, 3, data, n);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
|
||||
{
|
||||
int status;
|
||||
u8 addr[2] = {address & 0xff, address >> 8};
|
||||
|
||||
status = regmap_raw_write(ci->regmap, 2, addr, 2);
|
||||
if (!status) {
|
||||
u8 buf[256];
|
||||
|
||||
memcpy(buf, data, n);
|
||||
status = regmap_raw_write(ci->regmap, 3, buf, n);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int read_io(struct cxd *ci, u16 address, unsigned int *val)
|
||||
{
|
||||
int status;
|
||||
u8 addr[2] = {address & 0xff, address >> 8};
|
||||
|
||||
status = regmap_raw_write(ci->regmap, 2, addr, 2);
|
||||
if (!status)
|
||||
status = regmap_read(ci->regmap, 3, val);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int write_io(struct cxd *ci, u16 address, u8 val)
|
||||
{
|
||||
int status;
|
||||
u8 addr[2] = {address & 0xff, address >> 8};
|
||||
|
||||
status = regmap_raw_write(ci->regmap, 2, addr, 2);
|
||||
if (!status)
|
||||
status = regmap_write(ci->regmap, 3, val);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
|
||||
{
|
||||
int status = 0;
|
||||
unsigned int regval;
|
||||
|
||||
if (ci->lastaddress != reg)
|
||||
status = regmap_write(ci->regmap, 0, reg);
|
||||
if (!status && reg >= 6 && reg <= 8 && mask != 0xff) {
|
||||
status = regmap_read(ci->regmap, 1, ®val);
|
||||
ci->regs[reg] = regval;
|
||||
}
|
||||
ci->lastaddress = reg;
|
||||
ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
|
||||
if (!status)
|
||||
status = regmap_write(ci->regmap, 1, ci->regs[reg]);
|
||||
if (reg == 0x20)
|
||||
ci->regs[reg] &= 0x7f;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int write_reg(struct cxd *ci, u8 reg, u8 val)
|
||||
{
|
||||
return write_regm(ci, reg, val, 0xff);
|
||||
}
|
||||
|
||||
static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
|
||||
{
|
||||
int status = 0;
|
||||
u8 *buf = ci->wbuf;
|
||||
|
||||
if (ci->lastaddress != adr)
|
||||
status = regmap_write(ci->regmap, 0, adr);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
ci->lastaddress = adr;
|
||||
while (n) {
|
||||
int len = n;
|
||||
|
||||
if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
|
||||
len = ci->cfg.max_i2c - 1;
|
||||
memcpy(buf, data, len);
|
||||
status = regmap_raw_write(ci->regmap, 1, buf, len);
|
||||
if (status)
|
||||
return status;
|
||||
n -= len;
|
||||
data += len;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void set_mode(struct cxd *ci, int mode)
|
||||
{
|
||||
if (mode == ci->mode)
|
||||
return;
|
||||
|
||||
switch (mode) {
|
||||
case 0x00: /* IO mem */
|
||||
write_regm(ci, 0x06, 0x00, 0x07);
|
||||
break;
|
||||
case 0x01: /* ATT mem */
|
||||
write_regm(ci, 0x06, 0x02, 0x07);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ci->mode = mode;
|
||||
}
|
||||
|
||||
static void cam_mode(struct cxd *ci, int mode)
|
||||
{
|
||||
u8 dummy;
|
||||
|
||||
if (mode == ci->cammode)
|
||||
return;
|
||||
|
||||
switch (mode) {
|
||||
case 0x00:
|
||||
write_regm(ci, 0x20, 0x80, 0x80);
|
||||
break;
|
||||
case 0x01:
|
||||
if (!ci->en.read_data)
|
||||
return;
|
||||
ci->write_busy = 0;
|
||||
dev_info(&ci->client->dev, "enable cam buffer mode\n");
|
||||
write_reg(ci, 0x0d, 0x00);
|
||||
write_reg(ci, 0x0e, 0x01);
|
||||
write_regm(ci, 0x08, 0x40, 0x40);
|
||||
read_reg(ci, 0x12, &dummy);
|
||||
write_regm(ci, 0x08, 0x80, 0x80);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ci->cammode = mode;
|
||||
}
|
||||
|
||||
static int init(struct cxd *ci)
|
||||
{
|
||||
int status;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
ci->mode = -1;
|
||||
do {
|
||||
status = write_reg(ci, 0x00, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x01, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x02, 0x10);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x03, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x05, 0xFF);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x06, 0x1F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x07, 0x1F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x08, 0x28);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x14, 0x20);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
/* TOSTRT = 8, Mode B (gated clock), falling Edge,
|
||||
* Serial, POL=HIGH, MSB
|
||||
*/
|
||||
status = write_reg(ci, 0x0A, 0xA7);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
status = write_reg(ci, 0x0B, 0x33);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x0C, 0x33);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
status = write_regm(ci, 0x14, 0x00, 0x0F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x15, ci->clk_reg_b);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_regm(ci, 0x16, 0x00, 0x0F);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x17, ci->clk_reg_f);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
if (ci->cfg.clock_mode == 2) {
|
||||
/* bitrate*2^13/ 72000 */
|
||||
u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
|
||||
|
||||
if (ci->cfg.polarity) {
|
||||
status = write_reg(ci, 0x09, 0x6f);
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
status = write_reg(ci, 0x09, 0x6d);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
status = write_reg(ci, 0x20, 0x08);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x21, (reg >> 8) & 0xff);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x22, reg & 0xff);
|
||||
if (status < 0)
|
||||
break;
|
||||
} else if (ci->cfg.clock_mode == 1) {
|
||||
if (ci->cfg.polarity) {
|
||||
status = write_reg(ci, 0x09, 0x6f); /* D */
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
status = write_reg(ci, 0x09, 0x6d);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
status = write_reg(ci, 0x20, 0x68);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x21, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x22, 0x02);
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
if (ci->cfg.polarity) {
|
||||
status = write_reg(ci, 0x09, 0x4f); /* C */
|
||||
if (status < 0)
|
||||
break;
|
||||
} else {
|
||||
status = write_reg(ci, 0x09, 0x4d);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
status = write_reg(ci, 0x20, 0x28);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x21, 0x00);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x22, 0x07);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
status = write_regm(ci, 0x20, 0x80, 0x80);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_regm(ci, 0x03, 0x02, 0x02);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x01, 0x04);
|
||||
if (status < 0)
|
||||
break;
|
||||
status = write_reg(ci, 0x00, 0x31);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
||||
/* Put TS in bypass */
|
||||
status = write_regm(ci, 0x09, 0x08, 0x08);
|
||||
if (status < 0)
|
||||
break;
|
||||
ci->cammode = -1;
|
||||
cam_mode(ci, 0);
|
||||
} while (0);
|
||||
mutex_unlock(&ci->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_attribute_mem(struct dvb_ca_en50221 *ca,
|
||||
int slot, int address)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
u8 val;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
set_mode(ci, 1);
|
||||
read_pccard(ci, address, &val, 1);
|
||||
mutex_unlock(&ci->lock);
|
||||
return val;
|
||||
}
|
||||
|
||||
static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
|
||||
int address, u8 value)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
set_mode(ci, 1);
|
||||
write_pccard(ci, address, &value, 1);
|
||||
mutex_unlock(&ci->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_cam_control(struct dvb_ca_en50221 *ca,
|
||||
int slot, u8 address)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
unsigned int val;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
set_mode(ci, 0);
|
||||
read_io(ci, address, &val);
|
||||
mutex_unlock(&ci->lock);
|
||||
return val;
|
||||
}
|
||||
|
||||
static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
|
||||
u8 address, u8 value)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
set_mode(ci, 0);
|
||||
write_io(ci, address, value);
|
||||
mutex_unlock(&ci->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
|
||||
if (ci->cammode)
|
||||
read_data(ca, slot, ci->rbuf, 0);
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
cam_mode(ci, 0);
|
||||
write_reg(ci, 0x00, 0x21);
|
||||
write_reg(ci, 0x06, 0x1F);
|
||||
write_reg(ci, 0x00, 0x31);
|
||||
write_regm(ci, 0x20, 0x80, 0x80);
|
||||
write_reg(ci, 0x03, 0x02);
|
||||
ci->ready = 0;
|
||||
ci->mode = -1;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
usleep_range(10000, 11000);
|
||||
if (ci->ready)
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ci->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
|
||||
dev_dbg(&ci->client->dev, "%s\n", __func__);
|
||||
if (ci->cammode)
|
||||
read_data(ca, slot, ci->rbuf, 0);
|
||||
mutex_lock(&ci->lock);
|
||||
write_reg(ci, 0x00, 0x21);
|
||||
write_reg(ci, 0x06, 0x1F);
|
||||
msleep(300);
|
||||
|
||||
write_regm(ci, 0x09, 0x08, 0x08);
|
||||
write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
|
||||
write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
|
||||
|
||||
ci->mode = -1;
|
||||
ci->write_busy = 0;
|
||||
mutex_unlock(&ci->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
write_regm(ci, 0x09, 0x00, 0x08);
|
||||
set_mode(ci, 0);
|
||||
cam_mode(ci, 1);
|
||||
mutex_unlock(&ci->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int campoll(struct cxd *ci)
|
||||
{
|
||||
u8 istat;
|
||||
|
||||
read_reg(ci, 0x04, &istat);
|
||||
if (!istat)
|
||||
return 0;
|
||||
write_reg(ci, 0x05, istat);
|
||||
|
||||
if (istat & 0x40)
|
||||
ci->dr = 1;
|
||||
if (istat & 0x20)
|
||||
ci->write_busy = 0;
|
||||
|
||||
if (istat & 2) {
|
||||
u8 slotstat;
|
||||
|
||||
read_reg(ci, 0x01, &slotstat);
|
||||
if (!(2 & slotstat)) {
|
||||
if (!ci->slot_stat) {
|
||||
ci->slot_stat |=
|
||||
DVB_CA_EN50221_POLL_CAM_PRESENT;
|
||||
write_regm(ci, 0x03, 0x08, 0x08);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (ci->slot_stat) {
|
||||
ci->slot_stat = 0;
|
||||
write_regm(ci, 0x03, 0x00, 0x08);
|
||||
dev_info(&ci->client->dev, "NO CAM\n");
|
||||
ci->ready = 0;
|
||||
}
|
||||
}
|
||||
if ((istat & 8) &&
|
||||
ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
|
||||
ci->ready = 1;
|
||||
ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
u8 slotstat;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
campoll(ci);
|
||||
read_reg(ci, 0x01, &slotstat);
|
||||
mutex_unlock(&ci->lock);
|
||||
|
||||
return ci->slot_stat;
|
||||
}
|
||||
|
||||
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
u8 msb, lsb;
|
||||
u16 len;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
campoll(ci);
|
||||
mutex_unlock(&ci->lock);
|
||||
|
||||
if (!ci->dr)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&ci->lock);
|
||||
read_reg(ci, 0x0f, &msb);
|
||||
read_reg(ci, 0x10, &lsb);
|
||||
len = ((u16)msb << 8) | lsb;
|
||||
if (len > ecount || len < 2) {
|
||||
/* read it anyway or cxd may hang */
|
||||
read_block(ci, 0x12, ci->rbuf, len);
|
||||
mutex_unlock(&ci->lock);
|
||||
return -EIO;
|
||||
}
|
||||
read_block(ci, 0x12, ebuf, len);
|
||||
ci->dr = 0;
|
||||
mutex_unlock(&ci->lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
|
||||
{
|
||||
struct cxd *ci = ca->data;
|
||||
|
||||
if (ci->write_busy)
|
||||
return -EAGAIN;
|
||||
mutex_lock(&ci->lock);
|
||||
write_reg(ci, 0x0d, ecount >> 8);
|
||||
write_reg(ci, 0x0e, ecount & 0xff);
|
||||
write_block(ci, 0x11, ebuf, ecount);
|
||||
ci->write_busy = 1;
|
||||
mutex_unlock(&ci->lock);
|
||||
return ecount;
|
||||
}
|
||||
|
||||
static struct dvb_ca_en50221 en_templ = {
|
||||
.read_attribute_mem = read_attribute_mem,
|
||||
.write_attribute_mem = write_attribute_mem,
|
||||
.read_cam_control = read_cam_control,
|
||||
.write_cam_control = write_cam_control,
|
||||
.slot_reset = slot_reset,
|
||||
.slot_shutdown = slot_shutdown,
|
||||
.slot_ts_enable = slot_ts_enable,
|
||||
.poll_slot_status = poll_slot_status,
|
||||
.read_data = read_data,
|
||||
.write_data = write_data,
|
||||
};
|
||||
|
||||
static int cxd2099_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cxd *ci;
|
||||
struct cxd2099_cfg *cfg = client->dev.platform_data;
|
||||
static const struct regmap_config rm_cfg = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
|
||||
if (!ci) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ci->client = client;
|
||||
memcpy(&ci->cfg, cfg, sizeof(ci->cfg));
|
||||
|
||||
ci->regmap = regmap_init_i2c(client, &rm_cfg);
|
||||
if (IS_ERR(ci->regmap)) {
|
||||
ret = PTR_ERR(ci->regmap);
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
ret = regmap_read(ci->regmap, 0x00, &val);
|
||||
if (ret < 0) {
|
||||
dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n",
|
||||
client->addr);
|
||||
goto err_rmexit;
|
||||
}
|
||||
|
||||
mutex_init(&ci->lock);
|
||||
ci->lastaddress = 0xff;
|
||||
ci->clk_reg_b = 0x4a;
|
||||
ci->clk_reg_f = 0x1b;
|
||||
|
||||
ci->en = en_templ;
|
||||
ci->en.data = ci;
|
||||
init(ci);
|
||||
dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n", client->addr);
|
||||
|
||||
*cfg->en = &ci->en;
|
||||
|
||||
if (!buffermode) {
|
||||
ci->en.read_data = NULL;
|
||||
ci->en.write_data = NULL;
|
||||
} else {
|
||||
dev_info(&client->dev, "Using CXD2099AR buffer mode");
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, ci);
|
||||
|
||||
return 0;
|
||||
|
||||
err_rmexit:
|
||||
regmap_exit(ci->regmap);
|
||||
err_kfree:
|
||||
kfree(ci);
|
||||
err:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cxd2099_remove(struct i2c_client *client)
|
||||
{
|
||||
struct cxd *ci = i2c_get_clientdata(client);
|
||||
|
||||
regmap_exit(ci->regmap);
|
||||
kfree(ci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cxd2099_id[] = {
|
||||
{"cxd2099", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cxd2099_id);
|
||||
|
||||
static struct i2c_driver cxd2099_driver = {
|
||||
.driver = {
|
||||
.name = "cxd2099",
|
||||
},
|
||||
.probe = cxd2099_probe,
|
||||
.remove = cxd2099_remove,
|
||||
.id_table = cxd2099_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(cxd2099_driver);
|
||||
|
||||
MODULE_DESCRIPTION("CXD2099AR Common Interface controller driver");
|
||||
MODULE_AUTHOR("Ralph Metzler");
|
||||
MODULE_LICENSE("GPL");
|
||||
32
drivers/media/dvb-frontends/cxd2099.h
Normal file
32
drivers/media/dvb-frontends/cxd2099.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* cxd2099.h: Driver for the CXD2099AR Common Interface Controller
|
||||
*
|
||||
* Copyright (C) 2010-2011 Digital Devices GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _CXD2099_H_
|
||||
#define _CXD2099_H_
|
||||
|
||||
#include <media/dvb_ca_en50221.h>
|
||||
|
||||
struct cxd2099_cfg {
|
||||
u32 bitrate;
|
||||
u8 polarity;
|
||||
u8 clock_mode;
|
||||
|
||||
u32 max_i2c;
|
||||
|
||||
/* ptr to DVB CA struct */
|
||||
struct dvb_ca_en50221 **en;
|
||||
};
|
||||
|
||||
#endif
|
||||
8
drivers/media/dvb-frontends/cxd2880/Kconfig
Normal file
8
drivers/media/dvb-frontends/cxd2880/Kconfig
Normal file
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config DVB_CXD2880
|
||||
tristate "Sony CXD2880 DVB-T2/T tuner + demodulator"
|
||||
depends on DVB_CORE && SPI
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
18
drivers/media/dvb-frontends/cxd2880/Makefile
Normal file
18
drivers/media/dvb-frontends/cxd2880/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
cxd2880-objs := cxd2880_common.o \
|
||||
cxd2880_devio_spi.o \
|
||||
cxd2880_integ.o \
|
||||
cxd2880_io.o \
|
||||
cxd2880_spi_device.o \
|
||||
cxd2880_tnrdmd.o \
|
||||
cxd2880_tnrdmd_dvbt2.o \
|
||||
cxd2880_tnrdmd_dvbt2_mon.o \
|
||||
cxd2880_tnrdmd_dvbt.o \
|
||||
cxd2880_tnrdmd_dvbt_mon.o\
|
||||
cxd2880_tnrdmd_mon.o\
|
||||
cxd2880_top.o
|
||||
|
||||
obj-$(CONFIG_DVB_CXD2880) += cxd2880.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-frontends
|
||||
29
drivers/media/dvb-frontends/cxd2880/cxd2880.h
Normal file
29
drivers/media/dvb-frontends/cxd2880/cxd2880.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_H
|
||||
#define CXD2880_H
|
||||
|
||||
struct cxd2880_config {
|
||||
struct spi_device *spi;
|
||||
struct mutex *spi_mutex; /* For SPI access exclusive control */
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_DVB_CXD2880)
|
||||
extern struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
|
||||
struct cxd2880_config *cfg);
|
||||
#else
|
||||
static inline struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
|
||||
struct cxd2880_config *cfg)
|
||||
{
|
||||
pr_warn("%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_CXD2880 */
|
||||
|
||||
#endif /* CXD2880_H */
|
||||
21
drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
Normal file
21
drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_common.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* common functions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
|
||||
int cxd2880_convert2s_complement(u32 value, u32 bitlen)
|
||||
{
|
||||
if (!bitlen || bitlen >= 32)
|
||||
return (int)value;
|
||||
|
||||
if (value & (u32)(1 << (bitlen - 1)))
|
||||
return (int)(GENMASK(31, bitlen) | value);
|
||||
else
|
||||
return (int)(GENMASK(bitlen - 1, 0) & value);
|
||||
}
|
||||
19
drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
Normal file
19
drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_common.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_COMMON_H
|
||||
#define CXD2880_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
int cxd2880_convert2s_complement(u32 value, u32 bitlen);
|
||||
|
||||
#endif
|
||||
129
drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
Normal file
129
drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
Normal file
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_devio_spi.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* I/O interface via SPI
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include "cxd2880_devio_spi.h"
|
||||
|
||||
#define BURST_WRITE_MAX 128
|
||||
|
||||
static int cxd2880_io_spi_read_reg(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
u8 sub_address, u8 *data,
|
||||
u32 size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cxd2880_spi *spi = NULL;
|
||||
u8 send_data[6];
|
||||
u8 *read_data_top = data;
|
||||
|
||||
if (!io || !io->if_object || !data)
|
||||
return -EINVAL;
|
||||
|
||||
if (sub_address + size > 0x100)
|
||||
return -EINVAL;
|
||||
|
||||
spi = io->if_object;
|
||||
|
||||
if (tgt == CXD2880_IO_TGT_SYS)
|
||||
send_data[0] = 0x0b;
|
||||
else
|
||||
send_data[0] = 0x0a;
|
||||
|
||||
send_data[3] = 0;
|
||||
send_data[4] = 0;
|
||||
send_data[5] = 0;
|
||||
|
||||
while (size > 0) {
|
||||
send_data[1] = sub_address;
|
||||
if (size > 255)
|
||||
send_data[2] = 255;
|
||||
else
|
||||
send_data[2] = size;
|
||||
|
||||
ret =
|
||||
spi->write_read(spi, send_data, sizeof(send_data),
|
||||
read_data_top, send_data[2]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sub_address += send_data[2];
|
||||
read_data_top += send_data[2];
|
||||
size -= send_data[2];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cxd2880_io_spi_write_reg(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
u8 sub_address,
|
||||
const u8 *data, u32 size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cxd2880_spi *spi = NULL;
|
||||
u8 send_data[BURST_WRITE_MAX + 4];
|
||||
const u8 *write_data_top = data;
|
||||
|
||||
if (!io || !io->if_object || !data)
|
||||
return -EINVAL;
|
||||
|
||||
if (size > BURST_WRITE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (sub_address + size > 0x100)
|
||||
return -EINVAL;
|
||||
|
||||
spi = io->if_object;
|
||||
|
||||
if (tgt == CXD2880_IO_TGT_SYS)
|
||||
send_data[0] = 0x0f;
|
||||
else
|
||||
send_data[0] = 0x0e;
|
||||
|
||||
while (size > 0) {
|
||||
send_data[1] = sub_address;
|
||||
if (size > 255)
|
||||
send_data[2] = 255;
|
||||
else
|
||||
send_data[2] = size;
|
||||
|
||||
memcpy(&send_data[3], write_data_top, send_data[2]);
|
||||
|
||||
if (tgt == CXD2880_IO_TGT_SYS) {
|
||||
send_data[3 + send_data[2]] = 0x00;
|
||||
ret = spi->write(spi, send_data, send_data[2] + 4);
|
||||
} else {
|
||||
ret = spi->write(spi, send_data, send_data[2] + 3);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sub_address += send_data[2];
|
||||
write_data_top += send_data[2];
|
||||
size -= send_data[2];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_io_spi_create(struct cxd2880_io *io,
|
||||
struct cxd2880_spi *spi, u8 slave_select)
|
||||
{
|
||||
if (!io || !spi)
|
||||
return -EINVAL;
|
||||
|
||||
io->read_regs = cxd2880_io_spi_read_reg;
|
||||
io->write_regs = cxd2880_io_spi_write_reg;
|
||||
io->write_reg = cxd2880_io_common_write_one_reg;
|
||||
io->if_object = spi;
|
||||
io->i2c_address_sys = 0;
|
||||
io->i2c_address_demod = 0;
|
||||
io->slave_select = slave_select;
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
Normal file
23
drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_devio_spi.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* I/O interface via SPI
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_DEVIO_SPI_H
|
||||
#define CXD2880_DEVIO_SPI_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
#include "cxd2880_io.h"
|
||||
#include "cxd2880_spi.h"
|
||||
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
|
||||
int cxd2880_io_spi_create(struct cxd2880_io *io,
|
||||
struct cxd2880_spi *spi,
|
||||
u8 slave_select);
|
||||
|
||||
#endif
|
||||
29
drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
Normal file
29
drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_dtv.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* DTV related definitions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_DTV_H
|
||||
#define CXD2880_DTV_H
|
||||
|
||||
enum cxd2880_dtv_sys {
|
||||
CXD2880_DTV_SYS_UNKNOWN,
|
||||
CXD2880_DTV_SYS_DVBT,
|
||||
CXD2880_DTV_SYS_DVBT2,
|
||||
CXD2880_DTV_SYS_ANY
|
||||
};
|
||||
|
||||
enum cxd2880_dtv_bandwidth {
|
||||
CXD2880_DTV_BW_UNKNOWN = 0,
|
||||
CXD2880_DTV_BW_1_7_MHZ = 1,
|
||||
CXD2880_DTV_BW_5_MHZ = 5,
|
||||
CXD2880_DTV_BW_6_MHZ = 6,
|
||||
CXD2880_DTV_BW_7_MHZ = 7,
|
||||
CXD2880_DTV_BW_8_MHZ = 8
|
||||
};
|
||||
|
||||
#endif
|
||||
74
drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
Normal file
74
drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_dvbt.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* DVB-T related definitions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_DVBT_H
|
||||
#define CXD2880_DVBT_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
|
||||
enum cxd2880_dvbt_constellation {
|
||||
CXD2880_DVBT_CONSTELLATION_QPSK,
|
||||
CXD2880_DVBT_CONSTELLATION_16QAM,
|
||||
CXD2880_DVBT_CONSTELLATION_64QAM,
|
||||
CXD2880_DVBT_CONSTELLATION_RESERVED_3
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt_hierarchy {
|
||||
CXD2880_DVBT_HIERARCHY_NON,
|
||||
CXD2880_DVBT_HIERARCHY_1,
|
||||
CXD2880_DVBT_HIERARCHY_2,
|
||||
CXD2880_DVBT_HIERARCHY_4
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt_coderate {
|
||||
CXD2880_DVBT_CODERATE_1_2,
|
||||
CXD2880_DVBT_CODERATE_2_3,
|
||||
CXD2880_DVBT_CODERATE_3_4,
|
||||
CXD2880_DVBT_CODERATE_5_6,
|
||||
CXD2880_DVBT_CODERATE_7_8,
|
||||
CXD2880_DVBT_CODERATE_RESERVED_5,
|
||||
CXD2880_DVBT_CODERATE_RESERVED_6,
|
||||
CXD2880_DVBT_CODERATE_RESERVED_7
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt_guard {
|
||||
CXD2880_DVBT_GUARD_1_32,
|
||||
CXD2880_DVBT_GUARD_1_16,
|
||||
CXD2880_DVBT_GUARD_1_8,
|
||||
CXD2880_DVBT_GUARD_1_4
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt_mode {
|
||||
CXD2880_DVBT_MODE_2K,
|
||||
CXD2880_DVBT_MODE_8K,
|
||||
CXD2880_DVBT_MODE_RESERVED_2,
|
||||
CXD2880_DVBT_MODE_RESERVED_3
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt_profile {
|
||||
CXD2880_DVBT_PROFILE_HP = 0,
|
||||
CXD2880_DVBT_PROFILE_LP
|
||||
};
|
||||
|
||||
struct cxd2880_dvbt_tpsinfo {
|
||||
enum cxd2880_dvbt_constellation constellation;
|
||||
enum cxd2880_dvbt_hierarchy hierarchy;
|
||||
enum cxd2880_dvbt_coderate rate_hp;
|
||||
enum cxd2880_dvbt_coderate rate_lp;
|
||||
enum cxd2880_dvbt_guard guard;
|
||||
enum cxd2880_dvbt_mode mode;
|
||||
u8 fnum;
|
||||
u8 length_indicator;
|
||||
u16 cell_id;
|
||||
u8 cell_id_ok;
|
||||
u8 reserved_even;
|
||||
u8 reserved_odd;
|
||||
};
|
||||
|
||||
#endif
|
||||
385
drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
Normal file
385
drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
Normal file
@@ -0,0 +1,385 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_dvbt2.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* DVB-T2 related definitions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_DVBT2_H
|
||||
#define CXD2880_DVBT2_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
|
||||
enum cxd2880_dvbt2_profile {
|
||||
CXD2880_DVBT2_PROFILE_BASE,
|
||||
CXD2880_DVBT2_PROFILE_LITE,
|
||||
CXD2880_DVBT2_PROFILE_ANY
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_version {
|
||||
CXD2880_DVBT2_V111,
|
||||
CXD2880_DVBT2_V121,
|
||||
CXD2880_DVBT2_V131
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_s1 {
|
||||
CXD2880_DVBT2_S1_BASE_SISO = 0x00,
|
||||
CXD2880_DVBT2_S1_BASE_MISO = 0x01,
|
||||
CXD2880_DVBT2_S1_NON_DVBT2 = 0x02,
|
||||
CXD2880_DVBT2_S1_LITE_SISO = 0x03,
|
||||
CXD2880_DVBT2_S1_LITE_MISO = 0x04,
|
||||
CXD2880_DVBT2_S1_RSVD3 = 0x05,
|
||||
CXD2880_DVBT2_S1_RSVD4 = 0x06,
|
||||
CXD2880_DVBT2_S1_RSVD5 = 0x07,
|
||||
CXD2880_DVBT2_S1_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_base_s2 {
|
||||
CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00,
|
||||
CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01,
|
||||
CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02,
|
||||
CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03,
|
||||
CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04,
|
||||
CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05,
|
||||
CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06,
|
||||
CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07,
|
||||
CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_lite_s2 {
|
||||
CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00,
|
||||
CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01,
|
||||
CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02,
|
||||
CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03,
|
||||
CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04,
|
||||
CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05,
|
||||
CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06,
|
||||
CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07,
|
||||
CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_guard {
|
||||
CXD2880_DVBT2_G1_32 = 0x00,
|
||||
CXD2880_DVBT2_G1_16 = 0x01,
|
||||
CXD2880_DVBT2_G1_8 = 0x02,
|
||||
CXD2880_DVBT2_G1_4 = 0x03,
|
||||
CXD2880_DVBT2_G1_128 = 0x04,
|
||||
CXD2880_DVBT2_G19_128 = 0x05,
|
||||
CXD2880_DVBT2_G19_256 = 0x06,
|
||||
CXD2880_DVBT2_G_RSVD1 = 0x07,
|
||||
CXD2880_DVBT2_G_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_mode {
|
||||
CXD2880_DVBT2_M2K = 0x00,
|
||||
CXD2880_DVBT2_M8K = 0x01,
|
||||
CXD2880_DVBT2_M4K = 0x02,
|
||||
CXD2880_DVBT2_M1K = 0x03,
|
||||
CXD2880_DVBT2_M16K = 0x04,
|
||||
CXD2880_DVBT2_M32K = 0x05,
|
||||
CXD2880_DVBT2_M_RSVD1 = 0x06,
|
||||
CXD2880_DVBT2_M_RSVD2 = 0x07
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_bw {
|
||||
CXD2880_DVBT2_BW_8 = 0x00,
|
||||
CXD2880_DVBT2_BW_7 = 0x01,
|
||||
CXD2880_DVBT2_BW_6 = 0x02,
|
||||
CXD2880_DVBT2_BW_5 = 0x03,
|
||||
CXD2880_DVBT2_BW_10 = 0x04,
|
||||
CXD2880_DVBT2_BW_1_7 = 0x05,
|
||||
CXD2880_DVBT2_BW_RSVD1 = 0x06,
|
||||
CXD2880_DVBT2_BW_RSVD2 = 0x07,
|
||||
CXD2880_DVBT2_BW_RSVD3 = 0x08,
|
||||
CXD2880_DVBT2_BW_RSVD4 = 0x09,
|
||||
CXD2880_DVBT2_BW_RSVD5 = 0x0a,
|
||||
CXD2880_DVBT2_BW_RSVD6 = 0x0b,
|
||||
CXD2880_DVBT2_BW_RSVD7 = 0x0c,
|
||||
CXD2880_DVBT2_BW_RSVD8 = 0x0d,
|
||||
CXD2880_DVBT2_BW_RSVD9 = 0x0e,
|
||||
CXD2880_DVBT2_BW_RSVD10 = 0x0f,
|
||||
CXD2880_DVBT2_BW_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_l1pre_type {
|
||||
CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00,
|
||||
CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01,
|
||||
CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02,
|
||||
CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03,
|
||||
CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_papr {
|
||||
CXD2880_DVBT2_PAPR_0 = 0x00,
|
||||
CXD2880_DVBT2_PAPR_1 = 0x01,
|
||||
CXD2880_DVBT2_PAPR_2 = 0x02,
|
||||
CXD2880_DVBT2_PAPR_3 = 0x03,
|
||||
CXD2880_DVBT2_PAPR_RSVD1 = 0x04,
|
||||
CXD2880_DVBT2_PAPR_RSVD2 = 0x05,
|
||||
CXD2880_DVBT2_PAPR_RSVD3 = 0x06,
|
||||
CXD2880_DVBT2_PAPR_RSVD4 = 0x07,
|
||||
CXD2880_DVBT2_PAPR_RSVD5 = 0x08,
|
||||
CXD2880_DVBT2_PAPR_RSVD6 = 0x09,
|
||||
CXD2880_DVBT2_PAPR_RSVD7 = 0x0a,
|
||||
CXD2880_DVBT2_PAPR_RSVD8 = 0x0b,
|
||||
CXD2880_DVBT2_PAPR_RSVD9 = 0x0c,
|
||||
CXD2880_DVBT2_PAPR_RSVD10 = 0x0d,
|
||||
CXD2880_DVBT2_PAPR_RSVD11 = 0x0e,
|
||||
CXD2880_DVBT2_PAPR_RSVD12 = 0x0f,
|
||||
CXD2880_DVBT2_PAPR_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_l1post_constell {
|
||||
CXD2880_DVBT2_L1POST_BPSK = 0x00,
|
||||
CXD2880_DVBT2_L1POST_QPSK = 0x01,
|
||||
CXD2880_DVBT2_L1POST_QAM16 = 0x02,
|
||||
CXD2880_DVBT2_L1POST_QAM64 = 0x03,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e,
|
||||
CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f,
|
||||
CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_l1post_cr {
|
||||
CXD2880_DVBT2_L1POST_R1_2 = 0x00,
|
||||
CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01,
|
||||
CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02,
|
||||
CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03,
|
||||
CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_l1post_fec_type {
|
||||
CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00,
|
||||
CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01,
|
||||
CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02,
|
||||
CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03,
|
||||
CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_pp {
|
||||
CXD2880_DVBT2_PP1 = 0x00,
|
||||
CXD2880_DVBT2_PP2 = 0x01,
|
||||
CXD2880_DVBT2_PP3 = 0x02,
|
||||
CXD2880_DVBT2_PP4 = 0x03,
|
||||
CXD2880_DVBT2_PP5 = 0x04,
|
||||
CXD2880_DVBT2_PP6 = 0x05,
|
||||
CXD2880_DVBT2_PP7 = 0x06,
|
||||
CXD2880_DVBT2_PP8 = 0x07,
|
||||
CXD2880_DVBT2_PP_RSVD1 = 0x08,
|
||||
CXD2880_DVBT2_PP_RSVD2 = 0x09,
|
||||
CXD2880_DVBT2_PP_RSVD3 = 0x0a,
|
||||
CXD2880_DVBT2_PP_RSVD4 = 0x0b,
|
||||
CXD2880_DVBT2_PP_RSVD5 = 0x0c,
|
||||
CXD2880_DVBT2_PP_RSVD6 = 0x0d,
|
||||
CXD2880_DVBT2_PP_RSVD7 = 0x0e,
|
||||
CXD2880_DVBT2_PP_RSVD8 = 0x0f,
|
||||
CXD2880_DVBT2_PP_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_plp_code_rate {
|
||||
CXD2880_DVBT2_R1_2 = 0x00,
|
||||
CXD2880_DVBT2_R3_5 = 0x01,
|
||||
CXD2880_DVBT2_R2_3 = 0x02,
|
||||
CXD2880_DVBT2_R3_4 = 0x03,
|
||||
CXD2880_DVBT2_R4_5 = 0x04,
|
||||
CXD2880_DVBT2_R5_6 = 0x05,
|
||||
CXD2880_DVBT2_R1_3 = 0x06,
|
||||
CXD2880_DVBT2_R2_5 = 0x07,
|
||||
CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_plp_constell {
|
||||
CXD2880_DVBT2_QPSK = 0x00,
|
||||
CXD2880_DVBT2_QAM16 = 0x01,
|
||||
CXD2880_DVBT2_QAM64 = 0x02,
|
||||
CXD2880_DVBT2_QAM256 = 0x03,
|
||||
CXD2880_DVBT2_CON_RSVD1 = 0x04,
|
||||
CXD2880_DVBT2_CON_RSVD2 = 0x05,
|
||||
CXD2880_DVBT2_CON_RSVD3 = 0x06,
|
||||
CXD2880_DVBT2_CON_RSVD4 = 0x07,
|
||||
CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_plp_type {
|
||||
CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00,
|
||||
CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01,
|
||||
CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02,
|
||||
CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03,
|
||||
CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04,
|
||||
CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05,
|
||||
CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06,
|
||||
CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07,
|
||||
CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_plp_payload {
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f,
|
||||
CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_plp_fec {
|
||||
CXD2880_DVBT2_FEC_LDPC_16K = 0x00,
|
||||
CXD2880_DVBT2_FEC_LDPC_64K = 0x01,
|
||||
CXD2880_DVBT2_FEC_RSVD1 = 0x02,
|
||||
CXD2880_DVBT2_FEC_RSVD2 = 0x03,
|
||||
CXD2880_DVBT2_FEC_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_plp_mode {
|
||||
CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00,
|
||||
CXD2880_DVBT2_PLP_MODE_NM = 0x01,
|
||||
CXD2880_DVBT2_PLP_MODE_HEM = 0x02,
|
||||
CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03,
|
||||
CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_plp_btype {
|
||||
CXD2880_DVBT2_PLP_COMMON,
|
||||
CXD2880_DVBT2_PLP_DATA
|
||||
};
|
||||
|
||||
enum cxd2880_dvbt2_stream {
|
||||
CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00,
|
||||
CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01,
|
||||
CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02,
|
||||
CXD2880_DVBT2_STREAM_TRANSPORT = 0x03,
|
||||
CXD2880_DVBT2_STREAM_UNKNOWN = 0xff
|
||||
};
|
||||
|
||||
struct cxd2880_dvbt2_l1pre {
|
||||
enum cxd2880_dvbt2_l1pre_type type;
|
||||
u8 bw_ext;
|
||||
enum cxd2880_dvbt2_s1 s1;
|
||||
u8 s2;
|
||||
u8 mixed;
|
||||
enum cxd2880_dvbt2_mode fft_mode;
|
||||
u8 l1_rep;
|
||||
enum cxd2880_dvbt2_guard gi;
|
||||
enum cxd2880_dvbt2_papr papr;
|
||||
enum cxd2880_dvbt2_l1post_constell mod;
|
||||
enum cxd2880_dvbt2_l1post_cr cr;
|
||||
enum cxd2880_dvbt2_l1post_fec_type fec;
|
||||
u32 l1_post_size;
|
||||
u32 l1_post_info_size;
|
||||
enum cxd2880_dvbt2_pp pp;
|
||||
u8 tx_id_availability;
|
||||
u16 cell_id;
|
||||
u16 network_id;
|
||||
u16 sys_id;
|
||||
u8 num_frames;
|
||||
u16 num_symbols;
|
||||
u8 regen;
|
||||
u8 post_ext;
|
||||
u8 num_rf_freqs;
|
||||
u8 rf_idx;
|
||||
enum cxd2880_dvbt2_version t2_version;
|
||||
u8 l1_post_scrambled;
|
||||
u8 t2_base_lite;
|
||||
u32 crc32;
|
||||
};
|
||||
|
||||
struct cxd2880_dvbt2_plp {
|
||||
u8 id;
|
||||
enum cxd2880_dvbt2_plp_type type;
|
||||
enum cxd2880_dvbt2_plp_payload payload;
|
||||
u8 ff;
|
||||
u8 first_rf_idx;
|
||||
u8 first_frm_idx;
|
||||
u8 group_id;
|
||||
enum cxd2880_dvbt2_plp_constell constell;
|
||||
enum cxd2880_dvbt2_plp_code_rate plp_cr;
|
||||
u8 rot;
|
||||
enum cxd2880_dvbt2_plp_fec fec;
|
||||
u16 num_blocks_max;
|
||||
u8 frm_int;
|
||||
u8 til_len;
|
||||
u8 til_type;
|
||||
u8 in_band_a_flag;
|
||||
u8 in_band_b_flag;
|
||||
u16 rsvd;
|
||||
enum cxd2880_dvbt2_plp_mode plp_mode;
|
||||
u8 static_flag;
|
||||
u8 static_padding_flag;
|
||||
};
|
||||
|
||||
struct cxd2880_dvbt2_l1post {
|
||||
u16 sub_slices_per_frame;
|
||||
u8 num_plps;
|
||||
u8 num_aux;
|
||||
u8 aux_cfg_rfu;
|
||||
u8 rf_idx;
|
||||
u32 freq;
|
||||
u8 fef_type;
|
||||
u32 fef_length;
|
||||
u8 fef_intvl;
|
||||
};
|
||||
|
||||
struct cxd2880_dvbt2_ofdm {
|
||||
u8 mixed;
|
||||
u8 is_miso;
|
||||
enum cxd2880_dvbt2_mode mode;
|
||||
enum cxd2880_dvbt2_guard gi;
|
||||
enum cxd2880_dvbt2_pp pp;
|
||||
u8 bw_ext;
|
||||
enum cxd2880_dvbt2_papr papr;
|
||||
u16 num_symbols;
|
||||
};
|
||||
|
||||
struct cxd2880_dvbt2_bbheader {
|
||||
enum cxd2880_dvbt2_stream stream_input;
|
||||
u8 is_single_input_stream;
|
||||
u8 is_constant_coding_modulation;
|
||||
u8 issy_indicator;
|
||||
u8 null_packet_deletion;
|
||||
u8 ext;
|
||||
u8 input_stream_identifier;
|
||||
u16 user_packet_length;
|
||||
u16 data_field_length;
|
||||
u8 sync_byte;
|
||||
u32 issy;
|
||||
enum cxd2880_dvbt2_plp_mode plp_mode;
|
||||
};
|
||||
|
||||
#endif
|
||||
72
drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
Normal file
72
drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
Normal file
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_integ.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* integration layer common functions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
#include "cxd2880_tnrdmd_mon.h"
|
||||
#include "cxd2880_integ.h"
|
||||
|
||||
int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd)
|
||||
{
|
||||
int ret;
|
||||
ktime_t start;
|
||||
u8 cpu_task_completed = 0;
|
||||
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cxd2880_tnrdmd_init1(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
start = ktime_get();
|
||||
|
||||
while (1) {
|
||||
ret =
|
||||
cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
|
||||
&cpu_task_completed);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cpu_task_completed)
|
||||
break;
|
||||
|
||||
if (ktime_to_ms(ktime_sub(ktime_get(), start)) >
|
||||
CXD2880_TNRDMD_WAIT_INIT_TIMEOUT)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
usleep_range(CXD2880_TNRDMD_WAIT_INIT_INTVL,
|
||||
CXD2880_TNRDMD_WAIT_INIT_INTVL + 1000);
|
||||
}
|
||||
|
||||
return cxd2880_tnrdmd_init2(tnr_dmd);
|
||||
}
|
||||
|
||||
int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd)
|
||||
{
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
atomic_set(&tnr_dmd->cancel, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd *tnr_dmd)
|
||||
{
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
if (atomic_read(&tnr_dmd->cancel) != 0)
|
||||
return -ECANCELED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
27
drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
Normal file
27
drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_integ.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* integration layer common interface
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_INTEG_H
|
||||
#define CXD2880_INTEG_H
|
||||
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
|
||||
#define CXD2880_TNRDMD_WAIT_INIT_TIMEOUT 500
|
||||
#define CXD2880_TNRDMD_WAIT_INIT_INTVL 10
|
||||
|
||||
#define CXD2880_TNRDMD_WAIT_AGC_STABLE 100
|
||||
|
||||
int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd);
|
||||
|
||||
int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd);
|
||||
|
||||
int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd
|
||||
*tnr_dmd);
|
||||
|
||||
#endif
|
||||
66
drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
Normal file
66
drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_io.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* register I/O interface functions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include "cxd2880_io.h"
|
||||
|
||||
int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
u8 sub_address, u8 data)
|
||||
{
|
||||
if (!io)
|
||||
return -EINVAL;
|
||||
|
||||
return io->write_regs(io, tgt, sub_address, &data, 1);
|
||||
}
|
||||
|
||||
int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
u8 sub_address, u8 data, u8 mask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!io)
|
||||
return -EINVAL;
|
||||
|
||||
if (mask == 0x00)
|
||||
return 0;
|
||||
|
||||
if (mask != 0xff) {
|
||||
u8 rdata = 0x00;
|
||||
|
||||
ret = io->read_regs(io, tgt, sub_address, &rdata, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data = (data & mask) | (rdata & (mask ^ 0xff));
|
||||
}
|
||||
|
||||
return io->write_reg(io, tgt, sub_address, data);
|
||||
}
|
||||
|
||||
int cxd2880_io_write_multi_regs(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
const struct cxd2880_reg_value reg_value[],
|
||||
u8 size)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!io)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < size ; i++) {
|
||||
ret = io->write_reg(io, tgt, reg_value[i].addr,
|
||||
reg_value[i].value);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
54
drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
Normal file
54
drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_io.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* register I/O interface definitions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_IO_H
|
||||
#define CXD2880_IO_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
|
||||
enum cxd2880_io_tgt {
|
||||
CXD2880_IO_TGT_SYS,
|
||||
CXD2880_IO_TGT_DMD
|
||||
};
|
||||
|
||||
struct cxd2880_reg_value {
|
||||
u8 addr;
|
||||
u8 value;
|
||||
};
|
||||
|
||||
struct cxd2880_io {
|
||||
int (*read_regs)(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt, u8 sub_address,
|
||||
u8 *data, u32 size);
|
||||
int (*write_regs)(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt, u8 sub_address,
|
||||
const u8 *data, u32 size);
|
||||
int (*write_reg)(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt, u8 sub_address,
|
||||
u8 data);
|
||||
void *if_object;
|
||||
u8 i2c_address_sys;
|
||||
u8 i2c_address_demod;
|
||||
u8 slave_select;
|
||||
void *user;
|
||||
};
|
||||
|
||||
int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
u8 sub_address, u8 data);
|
||||
|
||||
int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
u8 sub_address, u8 data, u8 mask);
|
||||
|
||||
int cxd2880_io_write_multi_regs(struct cxd2880_io *io,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
const struct cxd2880_reg_value reg_value[],
|
||||
u8 size);
|
||||
#endif
|
||||
34
drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
Normal file
34
drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_spi.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* SPI access definitions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_SPI_H
|
||||
#define CXD2880_SPI_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
|
||||
enum cxd2880_spi_mode {
|
||||
CXD2880_SPI_MODE_0,
|
||||
CXD2880_SPI_MODE_1,
|
||||
CXD2880_SPI_MODE_2,
|
||||
CXD2880_SPI_MODE_3
|
||||
};
|
||||
|
||||
struct cxd2880_spi {
|
||||
int (*read)(struct cxd2880_spi *spi, u8 *data,
|
||||
u32 size);
|
||||
int (*write)(struct cxd2880_spi *spi, const u8 *data,
|
||||
u32 size);
|
||||
int (*write_read)(struct cxd2880_spi *spi,
|
||||
const u8 *tx_data, u32 tx_size,
|
||||
u8 *rx_data, u32 rx_size);
|
||||
u32 flags;
|
||||
void *user;
|
||||
};
|
||||
|
||||
#endif
|
||||
113
drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
Normal file
113
drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
Normal file
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_spi_device.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* SPI access functions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "cxd2880_spi_device.h"
|
||||
|
||||
static int cxd2880_spi_device_write(struct cxd2880_spi *spi,
|
||||
const u8 *data, u32 size)
|
||||
{
|
||||
struct cxd2880_spi_device *spi_device = NULL;
|
||||
struct spi_message msg;
|
||||
struct spi_transfer tx;
|
||||
int result = 0;
|
||||
|
||||
if (!spi || !spi->user || !data || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
spi_device = spi->user;
|
||||
|
||||
memset(&tx, 0, sizeof(tx));
|
||||
tx.tx_buf = data;
|
||||
tx.len = size;
|
||||
|
||||
spi_message_init(&msg);
|
||||
spi_message_add_tail(&tx, &msg);
|
||||
result = spi_sync(spi_device->spi, &msg);
|
||||
|
||||
if (result < 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
|
||||
const u8 *tx_data,
|
||||
u32 tx_size,
|
||||
u8 *rx_data,
|
||||
u32 rx_size)
|
||||
{
|
||||
struct cxd2880_spi_device *spi_device = NULL;
|
||||
int result = 0;
|
||||
|
||||
if (!spi || !spi->user || !tx_data ||
|
||||
!tx_size || !rx_data || !rx_size)
|
||||
return -EINVAL;
|
||||
|
||||
spi_device = spi->user;
|
||||
|
||||
result = spi_write_then_read(spi_device->spi, tx_data,
|
||||
tx_size, rx_data, rx_size);
|
||||
if (result < 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
|
||||
enum cxd2880_spi_mode mode,
|
||||
u32 speed_hz)
|
||||
{
|
||||
int result = 0;
|
||||
struct spi_device *spi = spi_device->spi;
|
||||
|
||||
switch (mode) {
|
||||
case CXD2880_SPI_MODE_0:
|
||||
spi->mode = SPI_MODE_0;
|
||||
break;
|
||||
case CXD2880_SPI_MODE_1:
|
||||
spi->mode = SPI_MODE_1;
|
||||
break;
|
||||
case CXD2880_SPI_MODE_2:
|
||||
spi->mode = SPI_MODE_2;
|
||||
break;
|
||||
case CXD2880_SPI_MODE_3:
|
||||
spi->mode = SPI_MODE_3;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spi->max_speed_hz = speed_hz;
|
||||
spi->bits_per_word = 8;
|
||||
result = spi_setup(spi);
|
||||
if (result != 0) {
|
||||
pr_err("spi_setup failed %d\n", result);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
|
||||
struct cxd2880_spi_device *spi_device)
|
||||
{
|
||||
if (!spi || !spi_device)
|
||||
return -EINVAL;
|
||||
|
||||
spi->read = NULL;
|
||||
spi->write = cxd2880_spi_device_write;
|
||||
spi->write_read = cxd2880_spi_device_write_read;
|
||||
spi->flags = 0;
|
||||
spi->user = spi_device;
|
||||
|
||||
return 0;
|
||||
}
|
||||
26
drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
Normal file
26
drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_spi_device.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* SPI access interface
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_SPI_DEVICE_H
|
||||
#define CXD2880_SPI_DEVICE_H
|
||||
|
||||
#include "cxd2880_spi.h"
|
||||
|
||||
struct cxd2880_spi_device {
|
||||
struct spi_device *spi;
|
||||
};
|
||||
|
||||
int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
|
||||
enum cxd2880_spi_mode mode,
|
||||
u32 speedHz);
|
||||
|
||||
int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
|
||||
struct cxd2880_spi_device *spi_device);
|
||||
|
||||
#endif /* CXD2880_SPI_DEVICE_H */
|
||||
3519
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
Normal file
3519
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
Normal file
File diff suppressed because it is too large
Load Diff
365
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
Normal file
365
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
Normal file
@@ -0,0 +1,365 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_tnrdmd.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* common control interface
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_TNRDMD_H
|
||||
#define CXD2880_TNRDMD_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
#include "cxd2880_io.h"
|
||||
#include "cxd2880_dtv.h"
|
||||
#include "cxd2880_dvbt.h"
|
||||
#include "cxd2880_dvbt2.h"
|
||||
|
||||
#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100
|
||||
|
||||
#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\
|
||||
((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00)))
|
||||
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW 0x0001
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW 0x0002
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY 0x0004
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL 0x0008
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY 0x0010
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND 0x0020
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS 0x0040
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR 0x0100
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK 0x0200
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK 0x0400
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM 0x0800
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS 0x1000
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW 0x2000
|
||||
#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL 0x4000
|
||||
|
||||
#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK 0x01
|
||||
#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK 0x02
|
||||
#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK 0x04
|
||||
|
||||
enum cxd2880_tnrdmd_chip_id {
|
||||
CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00,
|
||||
CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62,
|
||||
CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a
|
||||
};
|
||||
|
||||
#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) \
|
||||
(((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
|
||||
((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))
|
||||
|
||||
enum cxd2880_tnrdmd_state {
|
||||
CXD2880_TNRDMD_STATE_UNKNOWN,
|
||||
CXD2880_TNRDMD_STATE_SLEEP,
|
||||
CXD2880_TNRDMD_STATE_ACTIVE,
|
||||
CXD2880_TNRDMD_STATE_INVALID
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_divermode {
|
||||
CXD2880_TNRDMD_DIVERMODE_SINGLE,
|
||||
CXD2880_TNRDMD_DIVERMODE_MAIN,
|
||||
CXD2880_TNRDMD_DIVERMODE_SUB
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_clockmode {
|
||||
CXD2880_TNRDMD_CLOCKMODE_UNKNOWN,
|
||||
CXD2880_TNRDMD_CLOCKMODE_A,
|
||||
CXD2880_TNRDMD_CLOCKMODE_B,
|
||||
CXD2880_TNRDMD_CLOCKMODE_C
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_tsout_if {
|
||||
CXD2880_TNRDMD_TSOUT_IF_TS,
|
||||
CXD2880_TNRDMD_TSOUT_IF_SPI,
|
||||
CXD2880_TNRDMD_TSOUT_IF_SDIO
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_xtal_share {
|
||||
CXD2880_TNRDMD_XTAL_SHARE_NONE,
|
||||
CXD2880_TNRDMD_XTAL_SHARE_EXTREF,
|
||||
CXD2880_TNRDMD_XTAL_SHARE_MASTER,
|
||||
CXD2880_TNRDMD_XTAL_SHARE_SLAVE
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_spectrum_sense {
|
||||
CXD2880_TNRDMD_SPECTRUM_NORMAL,
|
||||
CXD2880_TNRDMD_SPECTRUM_INV
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_cfg_id {
|
||||
CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB,
|
||||
CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI,
|
||||
CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI,
|
||||
CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI,
|
||||
CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE,
|
||||
CXD2880_TNRDMD_CFG_TSCLK_CONT,
|
||||
CXD2880_TNRDMD_CFG_TSCLK_MASK,
|
||||
CXD2880_TNRDMD_CFG_TSVALID_MASK,
|
||||
CXD2880_TNRDMD_CFG_TSERR_MASK,
|
||||
CXD2880_TNRDMD_CFG_TSERR_VALID_DIS,
|
||||
CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
|
||||
CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL,
|
||||
CXD2880_TNRDMD_CFG_TSPIN_PULLUP,
|
||||
CXD2880_TNRDMD_CFG_TSCLK_FREQ,
|
||||
CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL,
|
||||
CXD2880_TNRDMD_CFG_TS_PACKET_GAP,
|
||||
CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE,
|
||||
CXD2880_TNRDMD_CFG_PWM_VALUE,
|
||||
CXD2880_TNRDMD_CFG_INTERRUPT,
|
||||
CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL,
|
||||
CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL,
|
||||
CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS,
|
||||
CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS,
|
||||
CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS,
|
||||
CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE,
|
||||
CXD2880_TNRDMD_CFG_CABLE_INPUT,
|
||||
CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE,
|
||||
CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE,
|
||||
CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST,
|
||||
CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
|
||||
CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
|
||||
CXD2880_TNRDMD_CFG_DVBT_PER_MES,
|
||||
CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
|
||||
CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
|
||||
CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_lock_result {
|
||||
CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT,
|
||||
CXD2880_TNRDMD_LOCK_RESULT_LOCKED,
|
||||
CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_gpio_mode {
|
||||
CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00,
|
||||
CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01,
|
||||
CXD2880_TNRDMD_GPIO_MODE_INT = 0x02,
|
||||
CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03,
|
||||
CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04,
|
||||
CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05,
|
||||
CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06
|
||||
};
|
||||
|
||||
enum cxd2880_tnrdmd_serial_ts_clk {
|
||||
CXD2880_TNRDMD_SERIAL_TS_CLK_FULL,
|
||||
CXD2880_TNRDMD_SERIAL_TS_CLK_HALF
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_cfg_mem {
|
||||
enum cxd2880_io_tgt tgt;
|
||||
u8 bank;
|
||||
u8 address;
|
||||
u8 value;
|
||||
u8 bit_mask;
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_pid_cfg {
|
||||
u8 is_en;
|
||||
u16 pid;
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_pid_ftr_cfg {
|
||||
u8 is_negative;
|
||||
struct cxd2880_tnrdmd_pid_cfg pid_cfg[32];
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_lna_thrs {
|
||||
u8 off_on;
|
||||
u8 on_off;
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_lna_thrs_tbl_air {
|
||||
struct cxd2880_tnrdmd_lna_thrs thrs[24];
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_lna_thrs_tbl_cable {
|
||||
struct cxd2880_tnrdmd_lna_thrs thrs[32];
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_create_param {
|
||||
enum cxd2880_tnrdmd_tsout_if ts_output_if;
|
||||
u8 en_internal_ldo;
|
||||
enum cxd2880_tnrdmd_xtal_share xtal_share_type;
|
||||
u8 xosc_cap;
|
||||
u8 xosc_i;
|
||||
u8 is_cxd2881gg;
|
||||
u8 stationary_use;
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd_diver_create_param {
|
||||
enum cxd2880_tnrdmd_tsout_if ts_output_if;
|
||||
u8 en_internal_ldo;
|
||||
u8 xosc_cap_main;
|
||||
u8 xosc_i_main;
|
||||
u8 xosc_i_sub;
|
||||
u8 is_cxd2881gg;
|
||||
u8 stationary_use;
|
||||
};
|
||||
|
||||
struct cxd2880_tnrdmd {
|
||||
struct cxd2880_tnrdmd *diver_sub;
|
||||
struct cxd2880_io *io;
|
||||
struct cxd2880_tnrdmd_create_param create_param;
|
||||
enum cxd2880_tnrdmd_divermode diver_mode;
|
||||
enum cxd2880_tnrdmd_clockmode fixed_clk_mode;
|
||||
u8 is_cable_input;
|
||||
u8 en_fef_intmtnt_base;
|
||||
u8 en_fef_intmtnt_lite;
|
||||
u8 blind_tune_dvbt2_first;
|
||||
int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *rf_lvl_db);
|
||||
struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air;
|
||||
struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable;
|
||||
u8 srl_ts_clk_mod_cnts;
|
||||
enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq;
|
||||
u8 ts_byte_clk_manual_setting;
|
||||
u8 is_ts_backwards_compatible_mode;
|
||||
struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT];
|
||||
u8 cfg_mem_last_entry;
|
||||
struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg;
|
||||
u8 pid_ftr_cfg_en;
|
||||
void *user;
|
||||
enum cxd2880_tnrdmd_chip_id chip_id;
|
||||
enum cxd2880_tnrdmd_state state;
|
||||
enum cxd2880_tnrdmd_clockmode clk_mode;
|
||||
u32 frequency_khz;
|
||||
enum cxd2880_dtv_sys sys;
|
||||
enum cxd2880_dtv_bandwidth bandwidth;
|
||||
u8 scan_mode;
|
||||
atomic_t cancel;
|
||||
};
|
||||
|
||||
int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_io *io,
|
||||
struct cxd2880_tnrdmd_create_param
|
||||
*create_param);
|
||||
|
||||
int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
|
||||
*tnr_dmd_main,
|
||||
struct cxd2880_io *io_main,
|
||||
struct cxd2880_tnrdmd *tnr_dmd_sub,
|
||||
struct cxd2880_io *io_sub,
|
||||
struct
|
||||
cxd2880_tnrdmd_diver_create_param
|
||||
*create_param);
|
||||
|
||||
int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd);
|
||||
|
||||
int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd);
|
||||
|
||||
int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u8 *task_completed);
|
||||
|
||||
int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dtv_sys sys,
|
||||
u32 frequency_khz,
|
||||
enum cxd2880_dtv_bandwidth
|
||||
bandwidth, u8 one_seg_opt,
|
||||
u8 one_seg_opt_shft_dir);
|
||||
|
||||
int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dtv_sys sys,
|
||||
u8 en_fef_intmtnt_ctrl);
|
||||
|
||||
int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd);
|
||||
|
||||
int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
enum cxd2880_tnrdmd_cfg_id id,
|
||||
int value);
|
||||
|
||||
int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 id,
|
||||
u8 en,
|
||||
enum cxd2880_tnrdmd_gpio_mode mode,
|
||||
u8 open_drain, u8 invert);
|
||||
|
||||
int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 id,
|
||||
u8 en,
|
||||
enum cxd2880_tnrdmd_gpio_mode
|
||||
mode, u8 open_drain,
|
||||
u8 invert);
|
||||
|
||||
int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 id, u8 *value);
|
||||
|
||||
int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 id, u8 *value);
|
||||
|
||||
int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 id, u8 value);
|
||||
|
||||
int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 id, u8 value);
|
||||
|
||||
int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u16 *value);
|
||||
|
||||
int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u16 value);
|
||||
|
||||
int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 clear_overflow_flag,
|
||||
u8 clear_underflow_flag,
|
||||
u8 clear_buf);
|
||||
|
||||
int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
enum cxd2880_tnrdmd_chip_id *chip_id);
|
||||
|
||||
int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_io_tgt tgt,
|
||||
u8 bank, u8 address,
|
||||
u8 value, u8 bit_mask);
|
||||
|
||||
int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
enum cxd2880_dtv_sys sys,
|
||||
u8 scan_mode_end);
|
||||
|
||||
int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_tnrdmd_pid_ftr_cfg
|
||||
*pid_ftr_cfg);
|
||||
|
||||
int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
int (*rf_lvl_cmpstn)
|
||||
(struct cxd2880_tnrdmd *,
|
||||
int *));
|
||||
|
||||
int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int (*rf_lvl_cmpstn)
|
||||
(struct cxd2880_tnrdmd *,
|
||||
int *));
|
||||
|
||||
int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct
|
||||
cxd2880_tnrdmd_lna_thrs_tbl_air
|
||||
*tbl_air,
|
||||
struct
|
||||
cxd2880_tnrdmd_lna_thrs_tbl_cable
|
||||
*tbl_cable);
|
||||
|
||||
int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct
|
||||
cxd2880_tnrdmd_lna_thrs_tbl_air
|
||||
*tbl_air,
|
||||
struct
|
||||
cxd2880_tnrdmd_lna_thrs_tbl_cable
|
||||
*tbl_cable);
|
||||
|
||||
int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 en, u8 value);
|
||||
|
||||
int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 en);
|
||||
|
||||
int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_tnrdmd_driver_version.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* version information
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.4"
|
||||
|
||||
#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2018-01-17"
|
||||
919
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
Normal file
919
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
Normal file
@@ -0,0 +1,919 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_tnrdmd_dvbt.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* control functions for DVB-T
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#include "cxd2880_tnrdmd_dvbt.h"
|
||||
#include "cxd2880_tnrdmd_dvbt_mon.h"
|
||||
|
||||
static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
|
||||
{0x00, 0x00}, {0x31, 0x01},
|
||||
};
|
||||
|
||||
static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
|
||||
{0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03},
|
||||
{0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25},
|
||||
};
|
||||
|
||||
static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = {
|
||||
{0x00, 0x12}, {0x44, 0x00},
|
||||
};
|
||||
|
||||
static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = {
|
||||
{0x00, 0x11}, {0x87, 0xd2},
|
||||
};
|
||||
|
||||
static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = {
|
||||
{0x00, 0x00}, {0xfd, 0x01},
|
||||
};
|
||||
|
||||
static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = {
|
||||
{0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00},
|
||||
};
|
||||
|
||||
static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = {
|
||||
{0x00, 0x11}, {0x87, 0x04},
|
||||
};
|
||||
|
||||
static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dtv_bandwidth
|
||||
bandwidth,
|
||||
enum cxd2880_tnrdmd_clockmode
|
||||
clk_mode)
|
||||
{
|
||||
static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 };
|
||||
static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 };
|
||||
static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 };
|
||||
static const u8 ratectl_margin[2] = { 0x01, 0xf0 };
|
||||
static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 };
|
||||
static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa };
|
||||
static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 };
|
||||
|
||||
static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00};
|
||||
static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa};
|
||||
static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 };
|
||||
static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 };
|
||||
static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 };
|
||||
static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 };
|
||||
static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 };
|
||||
static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 };
|
||||
static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 };
|
||||
|
||||
static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00};
|
||||
static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55};
|
||||
static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c };
|
||||
static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 };
|
||||
static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 };
|
||||
static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 };
|
||||
static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa };
|
||||
static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
|
||||
static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 };
|
||||
|
||||
static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00};
|
||||
static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38};
|
||||
static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 };
|
||||
static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 };
|
||||
static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c };
|
||||
static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
|
||||
static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 };
|
||||
static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff };
|
||||
static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 };
|
||||
|
||||
static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99};
|
||||
static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa};
|
||||
static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d };
|
||||
static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 };
|
||||
static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 };
|
||||
static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 };
|
||||
static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 };
|
||||
static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc };
|
||||
static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 };
|
||||
const u8 *data = NULL;
|
||||
u8 sst_data;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
tune_dmd_setting_seq1,
|
||||
ARRAY_SIZE(tune_dmd_setting_seq1));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x04);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = clk_mode_ckffrq_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = clk_mode_ckffrq_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = clk_mode_ckffrq_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x65, data, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x5d, 0x07);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
|
||||
u8 data[2] = { 0x01, 0x01 };
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x00);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0xce, data, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
tune_dmd_setting_seq2,
|
||||
ARRAY_SIZE(tune_dmd_setting_seq2));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0xf0, ratectl_margin, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN ||
|
||||
tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
|
||||
ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
tune_dmd_setting_seq3,
|
||||
ARRAY_SIZE(tune_dmd_setting_seq3));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
|
||||
ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
tune_dmd_setting_seq4,
|
||||
ARRAY_SIZE(tune_dmd_setting_seq4));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x04);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = maxclkcnt_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = maxclkcnt_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = maxclkcnt_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x68, data, 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x04);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (bandwidth) {
|
||||
case CXD2880_DTV_BW_8_MHZ:
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw8_nomi_ac;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw8_nomi_b;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x60, data, 5);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4a, 0x00);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw8_gtdofst_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw8_gtdofst_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw8_gtdofst_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x7d, data, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
sst_data = 0x35;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
sst_data = 0x34;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x71, sst_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw8_mrc_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw8_mrc_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw8_mrc_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4b, &data[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x51, &data[2], 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x72, &bw8_notch[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x6b, &bw8_notch[2], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
case CXD2880_DTV_BW_7_MHZ:
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw7_nomi_ac;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw7_nomi_b;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x60, data, 5);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4a, 0x02);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw7_gtdofst_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw7_gtdofst_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw7_gtdofst_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x7d, data, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
sst_data = 0x2f;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
sst_data = 0x2e;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x71, sst_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw7_mrc_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw7_mrc_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw7_mrc_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4b, &data[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x51, &data[2], 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x72, &bw7_notch[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x6b, &bw7_notch[2], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
case CXD2880_DTV_BW_6_MHZ:
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw6_nomi_ac;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw6_nomi_b;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x60, data, 5);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4a, 0x04);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw6_gtdofst_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw6_gtdofst_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw6_gtdofst_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x7d, data, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
sst_data = 0x29;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
sst_data = 0x2a;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x71, sst_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw6_mrc_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw6_mrc_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw6_mrc_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4b, &data[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x51, &data[2], 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x72, &bw6_notch[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x6b, &bw6_notch[2], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
case CXD2880_DTV_BW_5_MHZ:
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw5_nomi_ac;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw5_nomi_b;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x60, data, 5);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4a, 0x06);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw5_gtdofst_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw5_gtdofst_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw5_gtdofst_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x7d, data, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
sst_data = 0x24;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
sst_data = 0x23;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x71, sst_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
|
||||
switch (clk_mode) {
|
||||
case CXD2880_TNRDMD_CLOCKMODE_A:
|
||||
data = bw5_mrc_a;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_B:
|
||||
data = bw5_mrc_b;
|
||||
break;
|
||||
case CXD2880_TNRDMD_CLOCKMODE_C:
|
||||
data = bw5_mrc_c;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x4b, &data[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x51, &data[2], 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x72, &bw5_notch[0], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x6b, &bw5_notch[2], 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return cxd2880_io_write_multi_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
tune_dmd_setting_seq5,
|
||||
ARRAY_SIZE(tune_dmd_setting_seq5));
|
||||
}
|
||||
|
||||
static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
|
||||
*tnr_dmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
sleep_dmd_setting_seq1,
|
||||
ARRAY_SIZE(sleep_dmd_setting_seq1));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
sleep_dmd_setting_seq2,
|
||||
ARRAY_SIZE(sleep_dmd_setting_seq2));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
enum cxd2880_dvbt_profile profile)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x10);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x67,
|
||||
(profile == CXD2880_DVBT_PROFILE_HP)
|
||||
? 0x00 : 0x01);
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt_tune_param
|
||||
*tune_param)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !tune_param)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
|
||||
tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
|
||||
tune_param->center_freq_khz,
|
||||
tune_param->bandwidth, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret =
|
||||
x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
|
||||
tnr_dmd->clk_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
|
||||
ret =
|
||||
x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
|
||||
tune_param->bandwidth,
|
||||
tnr_dmd->diver_sub->clk_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return dvbt_set_profile(tnr_dmd, tune_param->profile);
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt_tune_param
|
||||
*tune_param)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !tune_param)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
|
||||
tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
|
||||
0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
|
||||
tnr_dmd->frequency_khz = tune_param->center_freq_khz;
|
||||
tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
|
||||
tnr_dmd->bandwidth = tune_param->bandwidth;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
|
||||
tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
|
||||
tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
|
||||
tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
|
||||
tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
|
||||
tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
ret = x_sleep_dvbt_demod_setting(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_lock_result
|
||||
*lock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
u8 sync_stat = 0;
|
||||
u8 ts_lock = 0;
|
||||
u8 unlock_detected = 0;
|
||||
u8 unlock_detected_sub = 0;
|
||||
|
||||
if (!tnr_dmd || !lock)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
|
||||
&unlock_detected);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
|
||||
if (sync_stat == 6)
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
|
||||
else if (unlock_detected)
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
|
||||
else
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sync_stat == 6) {
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
|
||||
&unlock_detected_sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sync_stat == 6)
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
|
||||
else if (unlock_detected && unlock_detected_sub)
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
|
||||
else
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_lock_result
|
||||
*lock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
u8 sync_stat = 0;
|
||||
u8 ts_lock = 0;
|
||||
u8 unlock_detected = 0;
|
||||
u8 unlock_detected_sub = 0;
|
||||
|
||||
if (!tnr_dmd || !lock)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
|
||||
&unlock_detected);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
|
||||
if (ts_lock)
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
|
||||
else if (unlock_detected)
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
|
||||
else
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ts_lock) {
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
|
||||
return ret;
|
||||
} else if (!unlock_detected) {
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
|
||||
&unlock_detected_sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unlock_detected && unlock_detected_sub)
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
|
||||
else
|
||||
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
45
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
Normal file
45
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_tnrdmd_dvbt.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* control interface for DVB-T
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_TNRDMD_DVBT_H
|
||||
#define CXD2880_TNRDMD_DVBT_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
|
||||
struct cxd2880_dvbt_tune_param {
|
||||
u32 center_freq_khz;
|
||||
enum cxd2880_dtv_bandwidth bandwidth;
|
||||
enum cxd2880_dvbt_profile profile;
|
||||
};
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt_tune_param
|
||||
*tune_param);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt_tune_param
|
||||
*tune_param);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
|
||||
*tnr_dmd);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_lock_result
|
||||
*lock);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_lock_result
|
||||
*lock);
|
||||
|
||||
#endif
|
||||
1217
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
Normal file
1217
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
Normal file
File diff suppressed because it is too large
Load Diff
65
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
Normal file
65
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_tnrdmd_dvbt2.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* control interface for DVB-T2
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_TNRDMD_DVBT2_H
|
||||
#define CXD2880_TNRDMD_DVBT2_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
|
||||
enum cxd2880_tnrdmd_dvbt2_tune_info {
|
||||
CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK,
|
||||
CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID
|
||||
};
|
||||
|
||||
struct cxd2880_dvbt2_tune_param {
|
||||
u32 center_freq_khz;
|
||||
enum cxd2880_dtv_bandwidth bandwidth;
|
||||
u16 data_plp_id;
|
||||
enum cxd2880_dvbt2_profile profile;
|
||||
enum cxd2880_tnrdmd_dvbt2_tune_info tune_info;
|
||||
};
|
||||
|
||||
#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO 0xffff
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt2_tune_param
|
||||
*tune_param);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt2_tune_param
|
||||
*tune_param);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
|
||||
*tnr_dmd);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_lock_result
|
||||
*lock);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_lock_result
|
||||
*lock);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 auto_plp,
|
||||
u8 plp_id);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
|
||||
*tnr_dmd);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u8 *l1_post_valid);
|
||||
|
||||
#endif
|
||||
1878
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
Normal file
1878
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
Normal file
File diff suppressed because it is too large
Load Diff
135
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
Normal file
135
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_tnrdmd_dvbt2_mon.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* DVB-T2 monitor interface
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_TNRDMD_DVBT2_MON_H
|
||||
#define CXD2880_TNRDMD_DVBT2_MON_H
|
||||
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
#include "cxd2880_dvbt2.h"
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *sync_stat,
|
||||
u8 *ts_lock_stat,
|
||||
u8 *unlock_detected);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u8 *sync_stat,
|
||||
u8 *unlock_detected);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *offset);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
int *offset);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt2_l1pre
|
||||
*l1_pre);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dvbt2_version
|
||||
*ver);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
struct cxd2880_dvbt2_ofdm *ofdm);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *plp_ids,
|
||||
u8 *num_plps);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_dvbt2_plp_btype
|
||||
type,
|
||||
struct cxd2880_dvbt2_plp
|
||||
*plp_info);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u8 *plp_error);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *l1_change);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
struct cxd2880_dvbt2_l1post
|
||||
*l1_post);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dvbt2_plp_btype
|
||||
type,
|
||||
struct cxd2880_dvbt2_bbheader
|
||||
*bbheader);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_dvbt2_plp_btype
|
||||
type,
|
||||
u32 *ts_rate_bps);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_spectrum_sense
|
||||
*sense);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *snr);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *snr,
|
||||
int *snr_main,
|
||||
int *snr_sub);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u32 *pen);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *ppm);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
int *ppm);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
enum cxd2880_dvbt2_plp_btype type,
|
||||
enum cxd2880_dvbt2_plp_constell
|
||||
*qam);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dvbt2_plp_btype
|
||||
type,
|
||||
enum
|
||||
cxd2880_dvbt2_plp_code_rate
|
||||
*code_rate);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dvbt2_profile
|
||||
*profile);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 *ssi);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *ssi);
|
||||
|
||||
#endif
|
||||
775
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
Normal file
775
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
Normal file
@@ -0,0 +1,775 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_tnrdmd_dvbt_mon.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* DVB-T monitor functions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include "cxd2880_tnrdmd_mon.h"
|
||||
#include "cxd2880_tnrdmd_dvbt.h"
|
||||
#include "cxd2880_tnrdmd_dvbt_mon.h"
|
||||
|
||||
#include <media/dvb_math.h>
|
||||
|
||||
static const int ref_dbm_1000[3][5] = {
|
||||
{-93000, -91000, -90000, -89000, -88000},
|
||||
{-87000, -85000, -84000, -83000, -82000},
|
||||
{-82000, -80000, -78000, -77000, -76000},
|
||||
};
|
||||
|
||||
static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *sync_stat,
|
||||
u8 *ts_lock_stat,
|
||||
u8 *unlock_detected)
|
||||
{
|
||||
u8 rdata = 0x00;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x10, &rdata, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*unlock_detected = (rdata & 0x10) ? 1 : 0;
|
||||
*sync_stat = rdata & 0x07;
|
||||
*ts_lock_stat = (rdata & 0x20) ? 1 : 0;
|
||||
|
||||
if (*sync_stat == 0x07)
|
||||
return -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *sync_stat,
|
||||
u8 *unlock_detected)
|
||||
{
|
||||
u8 ts_lock_stat = 0;
|
||||
|
||||
if (!tnr_dmd || !sync_stat || !unlock_detected)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
return -EINVAL;
|
||||
|
||||
return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub,
|
||||
sync_stat,
|
||||
&ts_lock_stat,
|
||||
unlock_detected);
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dvbt_mode
|
||||
*mode,
|
||||
enum cxd2880_dvbt_guard
|
||||
*guard)
|
||||
{
|
||||
u8 rdata = 0x00;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !mode || !guard)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = slvt_freeze_reg(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = is_tps_locked(tnr_dmd);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub,
|
||||
mode, guard);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x1b, &rdata, 1);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
*mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
|
||||
*guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *offset)
|
||||
{
|
||||
u8 rdata[4];
|
||||
u32 ctl_val = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !offset)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = slvt_freeze_reg(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = is_tps_locked(tnr_dmd);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x1d, rdata, 4);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
ctl_val =
|
||||
((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
|
||||
(rdata[3]);
|
||||
*offset = cxd2880_convert2s_complement(ctl_val, 29);
|
||||
*offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
int *offset)
|
||||
{
|
||||
if (!tnr_dmd || !offset)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
return -EINVAL;
|
||||
|
||||
return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub,
|
||||
offset);
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
struct cxd2880_dvbt_tpsinfo
|
||||
*info)
|
||||
{
|
||||
u8 rdata[7];
|
||||
u8 cell_id_ok = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !info)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = slvt_freeze_reg(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = is_tps_locked(tnr_dmd);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
|
||||
info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x29, rdata, 7);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x11);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0xd5, &cell_id_ok, 1);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
info->constellation =
|
||||
(enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
|
||||
info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
|
||||
info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
|
||||
info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
|
||||
info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
|
||||
info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
|
||||
info->fnum = (rdata[2] >> 6) & 0x03;
|
||||
info->length_indicator = rdata[2] & 0x3f;
|
||||
info->cell_id = (rdata[3] << 8) | rdata[4];
|
||||
info->reserved_even = rdata[5] & 0x3f;
|
||||
info->reserved_odd = rdata[6] & 0x3f;
|
||||
|
||||
info->cell_id_ok = cell_id_ok & 0x01;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u32 *pen)
|
||||
{
|
||||
u8 rdata[3];
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !pen)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x26, rdata, 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(rdata[0] & 0x01))
|
||||
return -EAGAIN;
|
||||
|
||||
*pen = (rdata[1] << 8) | rdata[2];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_spectrum_sense
|
||||
*sense)
|
||||
{
|
||||
u8 data = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !sense)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = slvt_freeze_reg(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = is_tps_locked(tnr_dmd);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub,
|
||||
sense);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x1c, &data, sizeof(data));
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
*sense =
|
||||
(data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
|
||||
CXD2880_TNRDMD_SPECTRUM_NORMAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u16 *reg_value)
|
||||
{
|
||||
u8 rdata[2];
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !reg_value)
|
||||
return -EINVAL;
|
||||
|
||||
ret = slvt_freeze_reg(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = is_tps_locked(tnr_dmd);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x13, rdata, 2);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
*reg_value = (rdata[0] << 8) | rdata[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u32 reg_value, int *snr)
|
||||
{
|
||||
if (!tnr_dmd || !snr)
|
||||
return -EINVAL;
|
||||
|
||||
if (reg_value == 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (reg_value > 4996)
|
||||
reg_value = 4996;
|
||||
|
||||
*snr = intlog10(reg_value) - intlog10(5350 - reg_value);
|
||||
*snr = (*snr + 839) / 1678 + 28500;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *snr)
|
||||
{
|
||||
u16 reg_value = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !snr)
|
||||
return -EINVAL;
|
||||
|
||||
*snr = -1000 * 1000;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
|
||||
ret = dvbt_read_snr_reg(tnr_dmd, ®_value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
|
||||
} else {
|
||||
int snr_main = 0;
|
||||
int snr_sub = 0;
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
|
||||
&snr_sub);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *snr,
|
||||
int *snr_main, int *snr_sub)
|
||||
{
|
||||
u16 reg_value = 0;
|
||||
u32 reg_value_sum = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !snr || !snr_main || !snr_sub)
|
||||
return -EINVAL;
|
||||
|
||||
*snr = -1000 * 1000;
|
||||
*snr_main = -1000 * 1000;
|
||||
*snr_sub = -1000 * 1000;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dvbt_read_snr_reg(tnr_dmd, ®_value);
|
||||
if (!ret) {
|
||||
ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
|
||||
if (ret)
|
||||
reg_value = 0;
|
||||
} else if (ret == -EAGAIN) {
|
||||
reg_value = 0;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_value_sum += reg_value;
|
||||
|
||||
ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value);
|
||||
if (!ret) {
|
||||
ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
|
||||
if (ret)
|
||||
reg_value = 0;
|
||||
} else if (ret == -EAGAIN) {
|
||||
reg_value = 0;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg_value_sum += reg_value;
|
||||
|
||||
return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *ppm)
|
||||
{
|
||||
u8 ctl_val_reg[5];
|
||||
u8 nominal_rate_reg[5];
|
||||
u32 trl_ctl_val = 0;
|
||||
u32 trcg_nominal_rate = 0;
|
||||
int num;
|
||||
int den;
|
||||
s8 diff_upper = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !ppm)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = slvt_freeze_reg(tnr_dmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = is_tps_locked(tnr_dmd);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x0d);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x21, ctl_val_reg,
|
||||
sizeof(ctl_val_reg));
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x04);
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x60, nominal_rate_reg,
|
||||
sizeof(nominal_rate_reg));
|
||||
if (ret) {
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
slvt_unfreeze_reg(tnr_dmd);
|
||||
|
||||
diff_upper =
|
||||
(ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
|
||||
|
||||
if (diff_upper < -1 || diff_upper > 1)
|
||||
return -EAGAIN;
|
||||
|
||||
trl_ctl_val = ctl_val_reg[1] << 24;
|
||||
trl_ctl_val |= ctl_val_reg[2] << 16;
|
||||
trl_ctl_val |= ctl_val_reg[3] << 8;
|
||||
trl_ctl_val |= ctl_val_reg[4];
|
||||
|
||||
trcg_nominal_rate = nominal_rate_reg[1] << 24;
|
||||
trcg_nominal_rate |= nominal_rate_reg[2] << 16;
|
||||
trcg_nominal_rate |= nominal_rate_reg[3] << 8;
|
||||
trcg_nominal_rate |= nominal_rate_reg[4];
|
||||
|
||||
trl_ctl_val >>= 1;
|
||||
trcg_nominal_rate >>= 1;
|
||||
|
||||
if (diff_upper == 1)
|
||||
num =
|
||||
(int)((trl_ctl_val + 0x80000000u) -
|
||||
trcg_nominal_rate);
|
||||
else if (diff_upper == -1)
|
||||
num =
|
||||
-(int)((trcg_nominal_rate + 0x80000000u) -
|
||||
trl_ctl_val);
|
||||
else
|
||||
num = (int)(trl_ctl_val - trcg_nominal_rate);
|
||||
|
||||
den = (nominal_rate_reg[0] & 0x7f) << 24;
|
||||
den |= nominal_rate_reg[1] << 16;
|
||||
den |= nominal_rate_reg[2] << 8;
|
||||
den |= nominal_rate_reg[3];
|
||||
den = (den + (390625 / 2)) / 390625;
|
||||
|
||||
den >>= 1;
|
||||
|
||||
if (num >= 0)
|
||||
*ppm = (num + (den / 2)) / den;
|
||||
else
|
||||
*ppm = (num - (den / 2)) / den;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd, int *ppm)
|
||||
{
|
||||
if (!tnr_dmd || !ppm)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
return -EINVAL;
|
||||
|
||||
return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
|
||||
}
|
||||
|
||||
static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int rf_lvl, u8 *ssi)
|
||||
{
|
||||
struct cxd2880_dvbt_tpsinfo tps;
|
||||
int prel;
|
||||
int temp_ssi = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !ssi)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 ||
|
||||
tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5)
|
||||
return -EINVAL;
|
||||
|
||||
prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
|
||||
|
||||
if (prel < -15000)
|
||||
temp_ssi = 0;
|
||||
else if (prel < 0)
|
||||
temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
|
||||
else if (prel < 20000)
|
||||
temp_ssi = (((4 * prel) + 500) / 1000) + 10;
|
||||
else if (prel < 35000)
|
||||
temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
|
||||
else
|
||||
temp_ssi = 100;
|
||||
|
||||
*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 *ssi)
|
||||
{
|
||||
int rf_lvl = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !ssi)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 *ssi)
|
||||
{
|
||||
int rf_lvl = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !ssi)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
|
||||
}
|
||||
|
||||
static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
|
||||
{
|
||||
u8 sync = 0;
|
||||
u8 tslock = 0;
|
||||
u8 early_unlock = 0;
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd)
|
||||
return -EINVAL;
|
||||
|
||||
ret =
|
||||
cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
|
||||
&early_unlock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sync != 6)
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_tnrdmd_dvbt_mon.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* DVB-T monitor interface
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_TNRDMD_DVBT_MON_H
|
||||
#define CXD2880_TNRDMD_DVBT_MON_H
|
||||
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
#include "cxd2880_dvbt.h"
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *sync_stat,
|
||||
u8 *ts_lock_stat,
|
||||
u8 *unlock_detected);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u8 *sync_stat,
|
||||
u8 *unlock_detected);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum cxd2880_dvbt_mode
|
||||
*mode,
|
||||
enum cxd2880_dvbt_guard
|
||||
*guard);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *offset);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
int *offset);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
struct cxd2880_dvbt_tpsinfo
|
||||
*info);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u32 *pen);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
enum
|
||||
cxd2880_tnrdmd_spectrum_sense
|
||||
*sense);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *snr);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *snr,
|
||||
int *snr_main, int *snr_sub);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, int *ppm);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
int *ppm);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 *ssi);
|
||||
|
||||
int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
u8 *ssi);
|
||||
|
||||
#endif
|
||||
150
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
Normal file
150
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
Normal file
@@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cxd2880_tnrdmd_mon.c
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* common monitor functions
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
#include "cxd2880_tnrdmd_mon.h"
|
||||
|
||||
static const u8 rf_lvl_seq[2] = {
|
||||
0x80, 0x00,
|
||||
};
|
||||
|
||||
int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *rf_lvl_db)
|
||||
{
|
||||
u8 rdata[2];
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !rf_lvl_db)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x00);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x10, 0x01);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
0x00, 0x10);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
0x5b, rf_lvl_seq, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
0x00, 0x1a);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
0x15, rdata, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rdata[0] || rdata[1])
|
||||
return -EINVAL;
|
||||
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
0x11, rdata, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*rf_lvl_db =
|
||||
cxd2880_convert2s_complement((rdata[0] << 3) |
|
||||
((rdata[1] & 0xe0) >> 5), 11);
|
||||
|
||||
*rf_lvl_db *= 125;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x00, 0x00);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_DMD,
|
||||
0x10, 0x00);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tnr_dmd->rf_lvl_cmpstn)
|
||||
ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *rf_lvl_db)
|
||||
{
|
||||
if (!tnr_dmd || !rf_lvl_db)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
return -EINVAL;
|
||||
|
||||
return cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u16 *status)
|
||||
{
|
||||
u8 data[2] = { 0 };
|
||||
int ret;
|
||||
|
||||
if (!tnr_dmd || !status)
|
||||
return -EINVAL;
|
||||
|
||||
ret = tnr_dmd->io->write_reg(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
0x00, 0x1a);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = tnr_dmd->io->read_regs(tnr_dmd->io,
|
||||
CXD2880_IO_TGT_SYS,
|
||||
0x15, data, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*status = (data[0] << 8) | data[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u16 *status)
|
||||
{
|
||||
if (!tnr_dmd || !status)
|
||||
return -EINVAL;
|
||||
|
||||
if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
|
||||
return -EINVAL;
|
||||
|
||||
return cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub,
|
||||
status);
|
||||
}
|
||||
29
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
Normal file
29
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cxd2880_tnrdmd_mon.h
|
||||
* Sony CXD2880 DVB-T2/T tuner + demodulator driver
|
||||
* common monitor interface
|
||||
*
|
||||
* Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
|
||||
*/
|
||||
|
||||
#ifndef CXD2880_TNRDMD_MON_H
|
||||
#define CXD2880_TNRDMD_MON_H
|
||||
|
||||
#include "cxd2880_common.h"
|
||||
#include "cxd2880_tnrdmd.h"
|
||||
|
||||
int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *rf_lvl_db);
|
||||
|
||||
int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
|
||||
int *rf_lvl_db);
|
||||
|
||||
int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
|
||||
*tnr_dmd, u16 *status);
|
||||
|
||||
int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
|
||||
cxd2880_tnrdmd
|
||||
*tnr_dmd,
|
||||
u16 *status);
|
||||
#endif
|
||||
1947
drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
Normal file
1947
drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1285,7 +1285,7 @@ int dib0090_gain_control(struct dvb_frontend *fe)
|
||||
#endif
|
||||
|
||||
if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
|
||||
if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
|
||||
if (abs(adc_error) < 50 || state->agc_step++ > 5) {
|
||||
|
||||
#ifdef CONFIG_STANDARD_DAB
|
||||
if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
|
||||
@@ -1754,7 +1754,7 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front
|
||||
*tune_state = CT_TUNER_STEP_1;
|
||||
} else {
|
||||
/* the minimum was what we have seen in the step before */
|
||||
if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
|
||||
if (abs(state->adc_diff) > abs(state->min_adc_diff)) {
|
||||
dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step\n", state->adc_diff, state->min_adc_diff);
|
||||
state->step--;
|
||||
}
|
||||
|
||||
@@ -809,7 +809,7 @@ static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
|
||||
{
|
||||
u32 internal = dib7000p_get_internal_freq(state);
|
||||
s32 unit_khz_dds_val;
|
||||
u32 abs_offset_khz = ABS(offset_khz);
|
||||
u32 abs_offset_khz = abs(offset_khz);
|
||||
u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
|
||||
u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
|
||||
if (internal == 0) {
|
||||
|
||||
@@ -2677,7 +2677,7 @@ static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
|
||||
static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
|
||||
{
|
||||
s16 unit_khz_dds_val;
|
||||
u32 abs_offset_khz = ABS(offset_khz);
|
||||
u32 abs_offset_khz = abs(offset_khz);
|
||||
u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
|
||||
u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
|
||||
u8 ratio;
|
||||
|
||||
@@ -424,7 +424,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_algorithm *algo, const char *name,
|
||||
struct dibx000_i2c_master *mst)
|
||||
{
|
||||
strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
|
||||
strlcpy(i2c_adap->name, name, sizeof(i2c_adap->name));
|
||||
i2c_adap->algo = algo;
|
||||
i2c_adap->algo_data = NULL;
|
||||
i2c_set_adapdata(i2c_adap, mst);
|
||||
|
||||
@@ -223,8 +223,6 @@ struct dvb_frontend_parametersContext {
|
||||
|
||||
#define FE_CALLBACK_TIME_NEVER 0xffffffff
|
||||
|
||||
#define ABS(x) ((x < 0) ? (-x) : (x))
|
||||
|
||||
#define DATA_BUS_ACCESS_MODE_8BIT 0x01
|
||||
#define DATA_BUS_ACCESS_MODE_16BIT 0x02
|
||||
#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
I2C API, implementation depends on board specifics
|
||||
|
||||
Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Trident Microsystems nor Hauppauge Computer Works
|
||||
nor the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
This module encapsulates I2C access.In some applications several devices
|
||||
share one I2C bus. If these devices have the same I2C address some kind
|
||||
off "switch" must be implemented to ensure error free communication with
|
||||
one device. In case such a "switch" is used, the device ID can be used
|
||||
to implement control over this "switch".
|
||||
*/
|
||||
|
||||
#ifndef __BSPI2C_H__
|
||||
#define __BSPI2C_H__
|
||||
|
||||
#include "bsp_types.h"
|
||||
|
||||
/*
|
||||
* This structure contains the I2C address, the device ID and a user_data pointer.
|
||||
* The user_data pointer can be used for application specific purposes.
|
||||
*/
|
||||
struct i2c_device_addr {
|
||||
u16 i2c_addr; /* The I2C address of the device. */
|
||||
u16 i2c_dev_id; /* The device identifier. */
|
||||
void *user_data; /* User data pointer */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* \def IS_I2C_10BIT( addr )
|
||||
* \brief Determine if I2C address 'addr' is a 10 bits address or not.
|
||||
* \param addr The I2C address.
|
||||
* \return int.
|
||||
* \retval 0 if address is not a 10 bits I2C address.
|
||||
* \retval 1 if address is a 10 bits I2C address.
|
||||
*/
|
||||
#define IS_I2C_10BIT(addr) \
|
||||
(((addr) & 0xF8) == 0xF0)
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
Exported FUNCTIONS
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* \fn drxbsp_i2c_init()
|
||||
* \brief Initialize I2C communication module.
|
||||
* \return drx_status_t Return status.
|
||||
* \retval 0 Initialization successful.
|
||||
* \retval -EIO Initialization failed.
|
||||
*/
|
||||
drx_status_t drxbsp_i2c_init(void);
|
||||
|
||||
/*
|
||||
* \fn drxbsp_i2c_term()
|
||||
* \brief Terminate I2C communication module.
|
||||
* \return drx_status_t Return status.
|
||||
* \retval 0 Termination successful.
|
||||
* \retval -EIO Termination failed.
|
||||
*/
|
||||
drx_status_t drxbsp_i2c_term(void);
|
||||
|
||||
/*
|
||||
* \fn drx_status_t drxbsp_i2c_write_read( struct i2c_device_addr *w_dev_addr,
|
||||
* u16 w_count,
|
||||
* u8 *wData,
|
||||
* struct i2c_device_addr *r_dev_addr,
|
||||
* u16 r_count,
|
||||
* u8 *r_data)
|
||||
* \brief Read and/or write count bytes from I2C bus, store them in data[].
|
||||
* \param w_dev_addr The device i2c address and the device ID to write to
|
||||
* \param w_count The number of bytes to write
|
||||
* \param wData The array to write the data to
|
||||
* \param r_dev_addr The device i2c address and the device ID to read from
|
||||
* \param r_count The number of bytes to read
|
||||
* \param r_data The array to read the data from
|
||||
* \return drx_status_t Return status.
|
||||
* \retval 0 Succes.
|
||||
* \retval -EIO Failure.
|
||||
* \retval -EINVAL Parameter 'wcount' is not zero but parameter
|
||||
* 'wdata' contains NULL.
|
||||
* Idem for 'rcount' and 'rdata'.
|
||||
* Both w_dev_addr and r_dev_addr are NULL.
|
||||
*
|
||||
* This function must implement an atomic write and/or read action on the I2C bus
|
||||
* No other process may use the I2C bus when this function is executing.
|
||||
* The critical section of this function runs from and including the I2C
|
||||
* write, up to and including the I2C read action.
|
||||
*
|
||||
* The device ID can be useful if several devices share an I2C address.
|
||||
* It can be used to control a "switch" on the I2C bus to the correct device.
|
||||
*/
|
||||
drx_status_t drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr,
|
||||
u16 w_count,
|
||||
u8 *w_data,
|
||||
struct i2c_device_addr *r_dev_addr,
|
||||
u16 r_count, u8 *r_data);
|
||||
|
||||
/*
|
||||
* \fn drxbsp_i2c_error_text()
|
||||
* \brief Returns a human readable error.
|
||||
* Counter part of numerical drx_i2c_error_g.
|
||||
*
|
||||
* \return char* Pointer to human readable error text.
|
||||
*/
|
||||
char *drxbsp_i2c_error_text(void);
|
||||
|
||||
/*
|
||||
* \var drx_i2c_error_g;
|
||||
* \brief I2C specific error codes, platform dependent.
|
||||
*/
|
||||
extern int drx_i2c_error_g;
|
||||
|
||||
#endif /* __BSPI2C_H__ */
|
||||
@@ -30,6 +30,17 @@ static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
|
||||
|
||||
/*
|
||||
* Older drivers treated QAM64 and QAM256 the same; that is the HW always
|
||||
* used "Auto" mode during detection. Setting "forced_manual"=1 allows
|
||||
* the user to treat these modes as separate. For backwards compatibility,
|
||||
* it's off by default. QAM_AUTO can now be specified to achive that
|
||||
* effect even if "forced_manual"=1
|
||||
*/
|
||||
static int forced_manual;
|
||||
module_param(forced_manual, int, 0644);
|
||||
MODULE_PARM_DESC(forced_manual, "if set, QAM64 and QAM256 will only lock to modulation specified");
|
||||
|
||||
#define DBG_INFO 1
|
||||
#define DBG_REG 2
|
||||
#define DBG_DUMP 4 /* FGR - comment out to remove dump code */
|
||||
@@ -566,7 +577,12 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
|
||||
/* 3. : 64QAM/256QAM detection(manual, auto) */
|
||||
ret = lgdt3306a_read_reg(state, 0x0009, &val);
|
||||
val &= 0xfc;
|
||||
val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */
|
||||
/* Check for forced Manual modulation modes; otherwise always "auto" */
|
||||
if(forced_manual && (modulation != QAM_AUTO)){
|
||||
val |= 0x01; /* STDOPDETCMODE[1:0]= 1=Manual */
|
||||
} else {
|
||||
val |= 0x02; /* STDOPDETCMODE[1:0]= 2=Auto */
|
||||
}
|
||||
ret = lgdt3306a_write_reg(state, 0x0009, val);
|
||||
if (lg_chkerr(ret))
|
||||
goto fail;
|
||||
@@ -598,6 +614,28 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
|
||||
if (lg_chkerr(ret))
|
||||
goto fail;
|
||||
|
||||
/* 5.1 V0.36 SRDCHKALWAYS : For better QAM detection */
|
||||
ret = lgdt3306a_read_reg(state, 0x000a, &val);
|
||||
val &= 0xfd;
|
||||
val |= 0x02;
|
||||
ret = lgdt3306a_write_reg(state, 0x000a, val);
|
||||
if (lg_chkerr(ret))
|
||||
goto fail;
|
||||
|
||||
/* 5.2 V0.36 Control of "no signal" detector function */
|
||||
ret = lgdt3306a_read_reg(state, 0x2849, &val);
|
||||
val &= 0xdf;
|
||||
ret = lgdt3306a_write_reg(state, 0x2849, val);
|
||||
if (lg_chkerr(ret))
|
||||
goto fail;
|
||||
|
||||
/* 5.3 Fix for Blonder Tongue HDE-2H-QAM and AQM modulators */
|
||||
ret = lgdt3306a_read_reg(state, 0x302b, &val);
|
||||
val &= 0x7f; /* SELFSYNCFINDEN_CQS=0; disable auto reset */
|
||||
ret = lgdt3306a_write_reg(state, 0x302b, val);
|
||||
if (lg_chkerr(ret))
|
||||
goto fail;
|
||||
|
||||
/* 6. Reset */
|
||||
ret = lgdt3306a_soft_reset(state);
|
||||
if (lg_chkerr(ret))
|
||||
@@ -620,10 +658,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state,
|
||||
ret = lgdt3306a_set_vsb(state);
|
||||
break;
|
||||
case QAM_64:
|
||||
ret = lgdt3306a_set_qam(state, QAM_64);
|
||||
break;
|
||||
case QAM_256:
|
||||
ret = lgdt3306a_set_qam(state, QAM_256);
|
||||
case QAM_AUTO:
|
||||
ret = lgdt3306a_set_qam(state, p->modulation);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -650,6 +687,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state,
|
||||
break;
|
||||
case QAM_64:
|
||||
case QAM_256:
|
||||
case QAM_AUTO:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -704,6 +742,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state,
|
||||
break;
|
||||
case QAM_64:
|
||||
case QAM_256:
|
||||
case QAM_AUTO:
|
||||
/* Auto ok for QAM */
|
||||
ret = lgdt3306a_set_inversion_auto(state, 1);
|
||||
break;
|
||||
@@ -727,6 +766,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state,
|
||||
break;
|
||||
case QAM_64:
|
||||
case QAM_256:
|
||||
case QAM_AUTO:
|
||||
if_freq_khz = state->cfg->qam_if_khz;
|
||||
break;
|
||||
default:
|
||||
@@ -1585,6 +1625,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe,
|
||||
switch (state->current_modulation) {
|
||||
case QAM_256:
|
||||
case QAM_64:
|
||||
case QAM_AUTO:
|
||||
if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) {
|
||||
*status |= FE_HAS_VITERBI;
|
||||
*status |= FE_HAS_SYNC;
|
||||
@@ -1628,6 +1669,7 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
|
||||
* Calculate some sort of "strength" from SNR
|
||||
*/
|
||||
struct lgdt3306a_state *state = fe->demodulator_priv;
|
||||
u8 val;
|
||||
u16 snr; /* snr_x10 */
|
||||
int ret;
|
||||
u32 ref_snr; /* snr*100 */
|
||||
@@ -1640,11 +1682,15 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
|
||||
ref_snr = 1600; /* 16dB */
|
||||
break;
|
||||
case QAM_64:
|
||||
ref_snr = 2200; /* 22dB */
|
||||
break;
|
||||
case QAM_256:
|
||||
ref_snr = 2800; /* 28dB */
|
||||
break;
|
||||
case QAM_AUTO:
|
||||
/* need to know actual modulation to set proper SNR baseline */
|
||||
lgdt3306a_read_reg(state, 0x00a6, &val);
|
||||
if(val & 0x04)
|
||||
ref_snr = 2800; /* QAM-256 28dB */
|
||||
else
|
||||
ref_snr = 2200; /* QAM-64 22dB */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2114,7 +2160,7 @@ static const struct dvb_frontend_ops lgdt3306a_ops = {
|
||||
.frequency_min = 54000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 62500,
|
||||
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
|
||||
.caps = FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
|
||||
},
|
||||
.i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl,
|
||||
.init = lgdt3306a_init,
|
||||
@@ -2177,6 +2223,7 @@ static int lgdt3306a_probe(struct i2c_client *client,
|
||||
|
||||
i2c_set_clientdata(client, fe->demodulator_priv);
|
||||
state = fe->demodulator_priv;
|
||||
state->frontend.ops.release = NULL;
|
||||
|
||||
/* create mux i2c adapter for tuner */
|
||||
state->muxc = i2c_mux_alloc(client->adapter, &client->dev,
|
||||
@@ -2196,6 +2243,8 @@ static int lgdt3306a_probe(struct i2c_client *client,
|
||||
*config->i2c_adapter = state->muxc->adapter[0];
|
||||
*config->fe = fe;
|
||||
|
||||
dev_info(&client->dev, "LG Electronics LGDT3306A successfully identified\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_kfree:
|
||||
@@ -2203,7 +2252,7 @@ err_kfree:
|
||||
err_fe:
|
||||
kfree(config);
|
||||
fail:
|
||||
dev_dbg(&client->dev, "failed=%d\n", ret);
|
||||
dev_warn(&client->dev, "probe failed = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
static unsigned int verbose = 5;
|
||||
module_param(verbose, int, 0644);
|
||||
|
||||
#define ABS(x) ((x) < 0 ? (-x) : (x))
|
||||
|
||||
struct mb86a16_state {
|
||||
struct i2c_adapter *i2c_adap;
|
||||
const struct mb86a16_config *config;
|
||||
@@ -1202,12 +1200,12 @@ static int mb86a16_set_fe(struct mb86a16_state *state)
|
||||
|
||||
signal_dupl = 0;
|
||||
for (j = 0; j < prev_freq_num; j++) {
|
||||
if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
|
||||
if ((abs(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
|
||||
signal_dupl = 1;
|
||||
dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
|
||||
}
|
||||
}
|
||||
if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
|
||||
if ((signal_dupl == 0) && (swp_freq > 0) && (abs(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
|
||||
dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
|
||||
prev_swp_freq[prev_freq_num] = swp_freq;
|
||||
prev_freq_num++;
|
||||
@@ -1381,7 +1379,7 @@ static int mb86a16_set_fe(struct mb86a16_state *state)
|
||||
dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
|
||||
swp_freq += delta_freq;
|
||||
dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
|
||||
if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
|
||||
if (abs(state->frequency * 1000 - swp_freq) > 3800) {
|
||||
dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !");
|
||||
} else {
|
||||
|
||||
|
||||
@@ -380,6 +380,38 @@ static int get_algo(struct dvb_frontend *fe)
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
|
||||
static u32 gold2root(u32 gold)
|
||||
{
|
||||
u32 x, g, tmp = gold;
|
||||
|
||||
if (tmp >= 0x3ffff)
|
||||
tmp = 0;
|
||||
for (g = 0, x = 1; g < tmp; g++)
|
||||
x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
|
||||
return x;
|
||||
}
|
||||
|
||||
static int cfg_scrambler(struct mxl *state, u32 gold)
|
||||
{
|
||||
u32 root;
|
||||
u8 buf[26] = {
|
||||
MXL_HYDRA_PLID_CMD_WRITE, 24,
|
||||
0, MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD, 0, 0,
|
||||
state->demod, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0,
|
||||
};
|
||||
|
||||
root = gold2root(gold);
|
||||
|
||||
buf[25] = (root >> 24) & 0xff;
|
||||
buf[24] = (root >> 16) & 0xff;
|
||||
buf[23] = (root >> 8) & 0xff;
|
||||
buf[22] = root & 0xff;
|
||||
|
||||
return send_command(state, sizeof(buf), buf);
|
||||
}
|
||||
|
||||
static int cfg_demod_abort_tune(struct mxl *state)
|
||||
{
|
||||
struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd;
|
||||
@@ -437,7 +469,7 @@ static int set_parameters(struct dvb_frontend *fe)
|
||||
demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO;
|
||||
demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO;
|
||||
demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO;
|
||||
/* cfg_scrambler(state); */
|
||||
cfg_scrambler(state, p->scrambling_sequence_index);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
@@ -498,7 +498,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
|
||||
* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
|
||||
* / ConstWithBandwidthMode)
|
||||
*/
|
||||
num = dev->pdata->clk * 7;
|
||||
num = dev->pdata->clk * 7ULL;
|
||||
num *= 0x400000;
|
||||
num = div_u64(num, bw_mode);
|
||||
resamp_ratio = num & 0x3ffffff;
|
||||
@@ -511,7 +511,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
|
||||
* / (CrystalFreqHz * 7))
|
||||
*/
|
||||
num = bw_mode << 20;
|
||||
num2 = dev->pdata->clk * 7;
|
||||
num2 = dev->pdata->clk * 7ULL;
|
||||
num = div_u64(num, num2);
|
||||
num = -num;
|
||||
cfreq_off_ratio = num & 0xfffff;
|
||||
|
||||
@@ -682,17 +682,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
|
||||
|
||||
val = s5h1409_readreg(state, 0xac) & 0xcfff;
|
||||
switch (mode) {
|
||||
case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
|
||||
case S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK:
|
||||
val |= 0x0000;
|
||||
break;
|
||||
case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
|
||||
case S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK:
|
||||
dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
|
||||
val |= 0x1000;
|
||||
break;
|
||||
case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
|
||||
case S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK:
|
||||
val |= 0x2000;
|
||||
break;
|
||||
case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
|
||||
case S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK:
|
||||
val |= 0x3000;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -52,10 +52,10 @@ struct s5h1409_config {
|
||||
u8 status_mode;
|
||||
|
||||
/* MPEG signal timing */
|
||||
#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
|
||||
#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
|
||||
#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
|
||||
#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
|
||||
#define S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0
|
||||
#define S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1
|
||||
#define S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2
|
||||
#define S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3
|
||||
u16 mpeg_timing;
|
||||
|
||||
/* HVR-1600 optimizations (to better work with MXL5005s)
|
||||
|
||||
@@ -433,17 +433,17 @@ static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
|
||||
|
||||
val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
|
||||
switch (mode) {
|
||||
case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
|
||||
case S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK:
|
||||
val |= 0x0000;
|
||||
break;
|
||||
case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
|
||||
case S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK:
|
||||
dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
|
||||
val |= 0x1000;
|
||||
break;
|
||||
case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
|
||||
case S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK:
|
||||
val |= 0x2000;
|
||||
break;
|
||||
case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
|
||||
case S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK:
|
||||
val |= 0x3000;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -40,10 +40,10 @@ struct s5h1411_config {
|
||||
u8 gpio;
|
||||
|
||||
/* MPEG signal timing */
|
||||
#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
|
||||
#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
|
||||
#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
|
||||
#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
|
||||
#define S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0
|
||||
#define S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1
|
||||
#define S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2
|
||||
#define S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3
|
||||
u16 mpeg_timing;
|
||||
|
||||
/* IF Freq for QAM and VSB in KHz */
|
||||
|
||||
@@ -42,10 +42,10 @@ struct s5h1432_config {
|
||||
u8 gpio;
|
||||
|
||||
/* MPEG signal timing */
|
||||
#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
|
||||
#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
|
||||
#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
|
||||
#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
|
||||
#define S5H1432_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0
|
||||
#define S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1
|
||||
#define S5H1432_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2
|
||||
#define S5H1432_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3
|
||||
u16 mpeg_timing;
|
||||
|
||||
/* IF Freq for QAM and VSB in KHz */
|
||||
|
||||
@@ -82,6 +82,30 @@ err_mutex_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
|
||||
{
|
||||
struct i2c_client *client = fe->demodulator_priv;
|
||||
struct si2168_dev *dev = i2c_get_clientdata(client);
|
||||
struct si2168_cmd cmd;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire);
|
||||
|
||||
/* set TS_MODE property */
|
||||
memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
|
||||
if (acquire)
|
||||
cmd.args[4] |= dev->ts_mode;
|
||||
else
|
||||
cmd.args[4] |= SI2168_TS_TRISTATE;
|
||||
if (dev->ts_clock_gapped)
|
||||
cmd.args[4] |= 0x40;
|
||||
cmd.wlen = 6;
|
||||
cmd.rlen = 4;
|
||||
ret = si2168_cmd_execute(client, &cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
struct i2c_client *client = fe->demodulator_priv;
|
||||
@@ -339,6 +363,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
|
||||
|
||||
memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
|
||||
cmd.args[4] = delivery_system | bandwidth;
|
||||
if (dev->spectral_inversion)
|
||||
cmd.args[5] |= 1;
|
||||
cmd.wlen = 6;
|
||||
cmd.rlen = 4;
|
||||
ret = si2168_cmd_execute(client, &cmd);
|
||||
@@ -403,6 +429,11 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
|
||||
|
||||
dev->delivery_system = c->delivery_system;
|
||||
|
||||
/* enable ts bus */
|
||||
ret = si2168_ts_bus_ctrl(fe, 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_dbg(&client->dev, "failed=%d\n", ret);
|
||||
@@ -541,13 +572,7 @@ static int si2168_init(struct dvb_frontend *fe)
|
||||
dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
|
||||
|
||||
/* set ts mode */
|
||||
memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
|
||||
cmd.args[4] |= dev->ts_mode;
|
||||
if (dev->ts_clock_gapped)
|
||||
cmd.args[4] |= 0x40;
|
||||
cmd.wlen = 6;
|
||||
cmd.rlen = 4;
|
||||
ret = si2168_cmd_execute(client, &cmd);
|
||||
ret = si2168_ts_bus_ctrl(fe, 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@@ -584,7 +609,12 @@ static int si2168_sleep(struct dvb_frontend *fe)
|
||||
|
||||
dev->active = false;
|
||||
|
||||
/* Firmware B 4.0-11 or later loses warm state during sleep */
|
||||
/* tri-state data bus */
|
||||
ret = si2168_ts_bus_ctrl(fe, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Firmware later than B 4.0-11 loses warm state during sleep */
|
||||
if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0))
|
||||
dev->warm = false;
|
||||
|
||||
@@ -776,6 +806,7 @@ static int si2168_probe(struct i2c_client *client,
|
||||
dev->ts_mode = config->ts_mode;
|
||||
dev->ts_clock_inv = config->ts_clock_inv;
|
||||
dev->ts_clock_gapped = config->ts_clock_gapped;
|
||||
dev->spectral_inversion = config->spectral_inversion;
|
||||
|
||||
dev_info(&client->dev, "Silicon Labs Si2168-%c%d%d successfully identified\n",
|
||||
dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
|
||||
@@ -788,7 +819,7 @@ static int si2168_probe(struct i2c_client *client,
|
||||
err_kfree:
|
||||
kfree(dev);
|
||||
err:
|
||||
dev_dbg(&client->dev, "failed=%d\n", ret);
|
||||
dev_warn(&client->dev, "probe failed = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ struct si2168_config {
|
||||
/* TS mode */
|
||||
#define SI2168_TS_PARALLEL 0x06
|
||||
#define SI2168_TS_SERIAL 0x03
|
||||
#define SI2168_TS_TRISTATE 0x00
|
||||
u8 ts_mode;
|
||||
|
||||
/* TS clock inverted */
|
||||
@@ -45,6 +46,9 @@ struct si2168_config {
|
||||
|
||||
/* TS clock gapped */
|
||||
bool ts_clock_gapped;
|
||||
|
||||
/* Inverted spectrum */
|
||||
bool spectral_inversion;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,6 +48,7 @@ struct si2168_dev {
|
||||
u8 ts_mode;
|
||||
bool ts_clock_inv;
|
||||
bool ts_clock_gapped;
|
||||
bool spectral_inversion;
|
||||
};
|
||||
|
||||
/* firmware command struct */
|
||||
|
||||
@@ -136,7 +136,7 @@ static void sp887x_setup_agc (struct sp887x_state* state)
|
||||
static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
|
||||
{
|
||||
struct sp887x_state* state = fe->demodulator_priv;
|
||||
u8 buf [BLOCKSIZE+2];
|
||||
u8 buf [BLOCKSIZE + 2];
|
||||
int i;
|
||||
int fw_size = fw->size;
|
||||
const unsigned char *mem = fw->data;
|
||||
@@ -144,7 +144,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
|
||||
if (fw_size < FW_SIZE+10)
|
||||
if (fw_size < FW_SIZE + 10)
|
||||
return -ENODEV;
|
||||
|
||||
mem = fw->data + 10;
|
||||
@@ -167,7 +167,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
|
||||
int c = BLOCKSIZE;
|
||||
int err;
|
||||
|
||||
if (i+c > FW_SIZE)
|
||||
if (c > FW_SIZE - i)
|
||||
c = FW_SIZE - i;
|
||||
|
||||
/* bit 0x8000 in address is set to enable 13bit mode */
|
||||
|
||||
@@ -374,22 +374,22 @@
|
||||
|
||||
#define STB0899_OFF0_IF_AGC_GAIN 0xf30c
|
||||
#define STB0899_BASE_IF_AGC_GAIN 0x00000000
|
||||
#define STB0899_IF_AGC_GAIN (0x3fff < 0)
|
||||
#define STB0899_IF_AGC_GAIN (0x3fff << 0)
|
||||
#define STB0899_OFFST_IF_AGC_GAIN 0
|
||||
#define STB0899_WIDTH_IF_AGC_GAIN 14
|
||||
|
||||
#define STB0899_OFF0_BB_AGC_GAIN 0xf310
|
||||
#define STB0899_BASE_BB_AGC_GAIN 0x00000000
|
||||
#define STB0899_BB_AGC_GAIN (0x3fff < 0)
|
||||
#define STB0899_BB_AGC_GAIN (0x3fff << 0)
|
||||
#define STB0899_OFFST_BB_AGC_GAIN 0
|
||||
#define STB0899_WIDTH_BB_AGC_GAIN 14
|
||||
|
||||
#define STB0899_OFF0_DC_OFFSET 0xf314
|
||||
#define STB0899_BASE_DC_OFFSET 0x00000000
|
||||
#define STB0899_I (0xff < 8)
|
||||
#define STB0899_I (0xff << 8)
|
||||
#define STB0899_OFFST_I 8
|
||||
#define STB0899_WIDTH_I 8
|
||||
#define STB0899_Q (0xff < 0)
|
||||
#define STB0899_Q (0xff << 0)
|
||||
#define STB0899_OFFST_Q 8
|
||||
#define STB0899_WIDTH_Q 8
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#endif
|
||||
|
||||
/* MACRO definitions */
|
||||
#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
|
||||
#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y))
|
||||
#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y))
|
||||
#define INRANGE(X, Y, Z) \
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
|
||||
#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \
|
||||
|| (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
|
||||
|
||||
|
||||
@@ -1255,14 +1255,14 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
|
||||
else
|
||||
intp->freq[d] = stv0900_get_tuner_freq(fe);
|
||||
|
||||
if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
|
||||
if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
|
||||
range = STV0900_RANGEOK;
|
||||
else if (ABS(offsetFreq) <=
|
||||
else if (abs(offsetFreq) <=
|
||||
(stv0900_carrier_width(result->symbol_rate,
|
||||
result->rolloff) / 2000))
|
||||
range = STV0900_RANGEOK;
|
||||
|
||||
} else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
|
||||
} else if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
|
||||
range = STV0900_RANGEOK;
|
||||
|
||||
dprintk("%s: range %d\n", __func__, range);
|
||||
|
||||
@@ -1673,15 +1673,15 @@ static int send_master_cmd(struct dvb_frontend *fe,
|
||||
struct dvb_diseqc_master_cmd *cmd)
|
||||
{
|
||||
struct stv *state = fe->demodulator_priv;
|
||||
u16 offs = state->nr ? 0x40 : 0;
|
||||
int i;
|
||||
|
||||
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E);
|
||||
SET_FIELD(DISEQC_MODE, 2);
|
||||
SET_FIELD(DIS_PRECHARGE, 1);
|
||||
for (i = 0; i < cmd->msg_len; i++) {
|
||||
wait_dis(state, 0x40, 0x00);
|
||||
write_reg(state, RSTV0910_P1_DISTXFIFO + offs, cmd->msg[i]);
|
||||
SET_REG(DISTXFIFO, cmd->msg[i]);
|
||||
}
|
||||
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A);
|
||||
SET_FIELD(DIS_PRECHARGE, 0);
|
||||
wait_dis(state, 0x20, 0x20);
|
||||
return 0;
|
||||
}
|
||||
@@ -1689,19 +1689,20 @@ static int send_master_cmd(struct dvb_frontend *fe,
|
||||
static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
|
||||
{
|
||||
struct stv *state = fe->demodulator_priv;
|
||||
u16 offs = state->nr ? 0x40 : 0;
|
||||
u8 value;
|
||||
|
||||
if (burst == SEC_MINI_A) {
|
||||
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3F);
|
||||
SET_FIELD(DISEQC_MODE, 3);
|
||||
value = 0x00;
|
||||
} else {
|
||||
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E);
|
||||
SET_FIELD(DISEQC_MODE, 2);
|
||||
value = 0xFF;
|
||||
}
|
||||
|
||||
SET_FIELD(DIS_PRECHARGE, 1);
|
||||
wait_dis(state, 0x40, 0x00);
|
||||
write_reg(state, RSTV0910_P1_DISTXFIFO + offs, value);
|
||||
write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A);
|
||||
SET_REG(DISTXFIFO, value);
|
||||
SET_FIELD(DIS_PRECHARGE, 0);
|
||||
wait_dis(state, 0x20, 0x20);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -137,7 +137,7 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
|
||||
NDEC = 3;
|
||||
|
||||
/* yeuch! */
|
||||
fpxin = state->config->xin * 10;
|
||||
fpxin = state->config->xin * 10ULL;
|
||||
fptmp = fpxin; do_div(fptmp, 123);
|
||||
if (symbolrate < fptmp)
|
||||
SFIL = 1;
|
||||
|
||||
@@ -56,6 +56,17 @@ config VIDEO_TDA9840
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tda9840.
|
||||
|
||||
config VIDEO_TDA1997X
|
||||
tristate "NXP TDA1997x HDMI receiver"
|
||||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
depends on SND_SOC
|
||||
select SND_PCM
|
||||
---help---
|
||||
V4L2 subdevice driver for the NXP TDA1997x HDMI receivers.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tda1997x.
|
||||
|
||||
config VIDEO_TEA6415C
|
||||
tristate "Philips TEA6415C audio processor"
|
||||
depends on I2C
|
||||
@@ -423,6 +434,15 @@ config VIDEO_TW9906
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tw9906.
|
||||
|
||||
config VIDEO_TW9910
|
||||
tristate "Techwell TW9910 video decoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
Support for Techwell TW9910 NTSC/PAL/SECAM video decoder.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tw9910.
|
||||
|
||||
config VIDEO_VPX3220
|
||||
tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
@@ -586,6 +606,18 @@ config VIDEO_OV2659
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ov2659.
|
||||
|
||||
config VIDEO_OV2685
|
||||
tristate "OmniVision OV2685 sensor support"
|
||||
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
select V4L2_FWNODE
|
||||
---help---
|
||||
This is a Video4Linux2 sensor-level driver for the OmniVision
|
||||
OV2685 camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ov2685.
|
||||
|
||||
config VIDEO_OV5640
|
||||
tristate "OmniVision OV5640 sensor support"
|
||||
depends on OF
|
||||
@@ -645,6 +677,28 @@ config VIDEO_OV5670
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ov5670.
|
||||
|
||||
config VIDEO_OV5695
|
||||
tristate "OmniVision OV5695 sensor support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
---help---
|
||||
This is a Video4Linux2 sensor-level driver for the OmniVision
|
||||
OV5695 camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ov5695.
|
||||
|
||||
config VIDEO_OV772X
|
||||
tristate "OmniVision OV772x sensor support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
---help---
|
||||
This is a Video4Linux2 sensor-level driver for the OmniVision
|
||||
OV772x camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ov772x.
|
||||
|
||||
config VIDEO_OV7640
|
||||
tristate "OmniVision OV7640 sensor support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
@@ -660,6 +714,7 @@ config VIDEO_OV7670
|
||||
tristate "OmniVision OV7670 sensor support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
select V4L2_FWNODE
|
||||
---help---
|
||||
This is a Video4Linux2 sensor-level driver for the OmniVision
|
||||
OV7670 VGA camera. It currently only works with the M88ALP01
|
||||
@@ -733,6 +788,17 @@ config VIDEO_MT9T001
|
||||
This is a Video4Linux2 sensor-level driver for the Aptina
|
||||
(Micron) mt0t001 3 Mpixel camera.
|
||||
|
||||
config VIDEO_MT9T112
|
||||
tristate "Aptina MT9T111/MT9T112 support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
---help---
|
||||
This is a Video4Linux2 sensor-level driver for the Aptina
|
||||
(Micron) MT9T111 and MT9T112 3 Mpixel camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mt9t112.
|
||||
|
||||
config VIDEO_MT9V011
|
||||
tristate "Micron mt9v011 sensor support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
|
||||
@@ -13,6 +13,7 @@ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
|
||||
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
|
||||
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
|
||||
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
|
||||
obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o
|
||||
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
|
||||
obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
|
||||
obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
|
||||
@@ -48,6 +49,7 @@ obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
|
||||
obj-$(CONFIG_VIDEO_TW2804) += tw2804.o
|
||||
obj-$(CONFIG_VIDEO_TW9903) += tw9903.o
|
||||
obj-$(CONFIG_VIDEO_TW9906) += tw9906.o
|
||||
obj-$(CONFIG_VIDEO_TW9910) += tw9910.o
|
||||
obj-$(CONFIG_VIDEO_CS3308) += cs3308.o
|
||||
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
|
||||
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
|
||||
@@ -61,13 +63,16 @@ obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o
|
||||
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
|
||||
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
|
||||
obj-$(CONFIG_VIDEO_OV2640) += ov2640.o
|
||||
obj-$(CONFIG_VIDEO_OV2685) += ov2685.o
|
||||
obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
|
||||
obj-$(CONFIG_VIDEO_OV5645) += ov5645.o
|
||||
obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
|
||||
obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
|
||||
obj-$(CONFIG_VIDEO_OV5695) += ov5695.o
|
||||
obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
|
||||
obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
|
||||
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
|
||||
obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
|
||||
obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
|
||||
obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
|
||||
obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
|
||||
@@ -75,6 +80,7 @@ obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
|
||||
obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
|
||||
obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
|
||||
obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
|
||||
obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o
|
||||
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
|
||||
obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
|
||||
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Analog Devices AD9389B/AD9889B video encoder driver
|
||||
*
|
||||
* Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -35,96 +35,28 @@
|
||||
* Register manipulation
|
||||
*/
|
||||
|
||||
#define ADV748X_REGMAP_CONF(n) \
|
||||
{ \
|
||||
.name = n, \
|
||||
.reg_bits = 8, \
|
||||
.val_bits = 8, \
|
||||
.max_register = 0xff, \
|
||||
.cache_type = REGCACHE_NONE, \
|
||||
}
|
||||
|
||||
static const struct regmap_config adv748x_regmap_cnf[] = {
|
||||
{
|
||||
.name = "io",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "dpll",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "cp",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "hdmi",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "edid",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "repeater",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "infoframe",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "cec",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "sdp",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
|
||||
{
|
||||
.name = "txb",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
{
|
||||
.name = "txa",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = 0xff,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
},
|
||||
ADV748X_REGMAP_CONF("io"),
|
||||
ADV748X_REGMAP_CONF("dpll"),
|
||||
ADV748X_REGMAP_CONF("cp"),
|
||||
ADV748X_REGMAP_CONF("hdmi"),
|
||||
ADV748X_REGMAP_CONF("edid"),
|
||||
ADV748X_REGMAP_CONF("repeater"),
|
||||
ADV748X_REGMAP_CONF("infoframe"),
|
||||
ADV748X_REGMAP_CONF("cbus"),
|
||||
ADV748X_REGMAP_CONF("cec"),
|
||||
ADV748X_REGMAP_CONF("sdp"),
|
||||
ADV748X_REGMAP_CONF("txa"),
|
||||
ADV748X_REGMAP_CONF("txb"),
|
||||
};
|
||||
|
||||
static int adv748x_configure_regmap(struct adv748x_state *state, int region)
|
||||
@@ -148,20 +80,24 @@ static int adv748x_configure_regmap(struct adv748x_state *state, int region)
|
||||
|
||||
return 0;
|
||||
}
|
||||
struct adv748x_register_map {
|
||||
const char *name;
|
||||
u8 default_addr;
|
||||
};
|
||||
|
||||
/* Default addresses for the I2C pages */
|
||||
static int adv748x_i2c_addresses[ADV748X_PAGE_MAX] = {
|
||||
ADV748X_I2C_IO,
|
||||
ADV748X_I2C_DPLL,
|
||||
ADV748X_I2C_CP,
|
||||
ADV748X_I2C_HDMI,
|
||||
ADV748X_I2C_EDID,
|
||||
ADV748X_I2C_REPEATER,
|
||||
ADV748X_I2C_INFOFRAME,
|
||||
ADV748X_I2C_CEC,
|
||||
ADV748X_I2C_SDP,
|
||||
ADV748X_I2C_TXB,
|
||||
ADV748X_I2C_TXA,
|
||||
static const struct adv748x_register_map adv748x_default_addresses[] = {
|
||||
[ADV748X_PAGE_IO] = { "main", 0x70 },
|
||||
[ADV748X_PAGE_DPLL] = { "dpll", 0x26 },
|
||||
[ADV748X_PAGE_CP] = { "cp", 0x22 },
|
||||
[ADV748X_PAGE_HDMI] = { "hdmi", 0x34 },
|
||||
[ADV748X_PAGE_EDID] = { "edid", 0x36 },
|
||||
[ADV748X_PAGE_REPEATER] = { "repeater", 0x32 },
|
||||
[ADV748X_PAGE_INFOFRAME] = { "infoframe", 0x31 },
|
||||
[ADV748X_PAGE_CBUS] = { "cbus", 0x30 },
|
||||
[ADV748X_PAGE_CEC] = { "cec", 0x41 },
|
||||
[ADV748X_PAGE_SDP] = { "sdp", 0x79 },
|
||||
[ADV748X_PAGE_TXB] = { "txb", 0x48 },
|
||||
[ADV748X_PAGE_TXA] = { "txa", 0x4a },
|
||||
};
|
||||
|
||||
static int adv748x_read_check(struct adv748x_state *state,
|
||||
@@ -210,15 +146,20 @@ int adv748x_write_block(struct adv748x_state *state, int client_page,
|
||||
return regmap_raw_write(regmap, init_reg, val, val_len);
|
||||
}
|
||||
|
||||
static struct i2c_client *adv748x_dummy_client(struct adv748x_state *state,
|
||||
u8 addr, u8 io_reg)
|
||||
static int adv748x_set_slave_addresses(struct adv748x_state *state)
|
||||
{
|
||||
struct i2c_client *client = state->client;
|
||||
struct i2c_client *client;
|
||||
unsigned int i;
|
||||
u8 io_reg;
|
||||
|
||||
if (addr)
|
||||
io_write(state, io_reg, addr << 1);
|
||||
for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) {
|
||||
io_reg = ADV748X_IO_SLAVE_ADDR_BASE + i;
|
||||
client = state->i2c_clients[i];
|
||||
|
||||
return i2c_new_dummy(client->adapter, io_read(state, io_reg) >> 1);
|
||||
io_write(state, io_reg, client->addr << 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adv748x_unregister_clients(struct adv748x_state *state)
|
||||
@@ -231,13 +172,15 @@ static void adv748x_unregister_clients(struct adv748x_state *state)
|
||||
|
||||
static int adv748x_initialise_clients(struct adv748x_state *state)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) {
|
||||
state->i2c_clients[i] =
|
||||
adv748x_dummy_client(state, adv748x_i2c_addresses[i],
|
||||
ADV748X_IO_SLAVE_ADDR_BASE + i);
|
||||
state->i2c_clients[i] = i2c_new_secondary_device(
|
||||
state->client,
|
||||
adv748x_default_addresses[i].name,
|
||||
adv748x_default_addresses[i].default_addr);
|
||||
|
||||
if (state->i2c_clients[i] == NULL) {
|
||||
adv_err(state, "failed to create i2c client %u\n", i);
|
||||
return -ENOMEM;
|
||||
@@ -248,7 +191,7 @@ static int adv748x_initialise_clients(struct adv748x_state *state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return adv748x_set_slave_addresses(state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,20 +357,6 @@ static const struct adv748x_reg_value adv748x_sw_reset[] = {
|
||||
{ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */
|
||||
};
|
||||
|
||||
static const struct adv748x_reg_value adv748x_set_slave_address[] = {
|
||||
{ADV748X_PAGE_IO, 0xf3, ADV748X_I2C_DPLL << 1},
|
||||
{ADV748X_PAGE_IO, 0xf4, ADV748X_I2C_CP << 1},
|
||||
{ADV748X_PAGE_IO, 0xf5, ADV748X_I2C_HDMI << 1},
|
||||
{ADV748X_PAGE_IO, 0xf6, ADV748X_I2C_EDID << 1},
|
||||
{ADV748X_PAGE_IO, 0xf7, ADV748X_I2C_REPEATER << 1},
|
||||
{ADV748X_PAGE_IO, 0xf8, ADV748X_I2C_INFOFRAME << 1},
|
||||
{ADV748X_PAGE_IO, 0xfa, ADV748X_I2C_CEC << 1},
|
||||
{ADV748X_PAGE_IO, 0xfb, ADV748X_I2C_SDP << 1},
|
||||
{ADV748X_PAGE_IO, 0xfc, ADV748X_I2C_TXB << 1},
|
||||
{ADV748X_PAGE_IO, 0xfd, ADV748X_I2C_TXA << 1},
|
||||
{ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */
|
||||
};
|
||||
|
||||
/* Supported Formats For Script Below */
|
||||
/* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */
|
||||
static const struct adv748x_reg_value adv748x_init_txa_4lane[] = {
|
||||
@@ -558,7 +487,7 @@ static int adv748x_reset(struct adv748x_state *state)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adv748x_write_regs(state, adv748x_set_slave_address);
|
||||
ret = adv748x_set_slave_addresses(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -715,7 +644,7 @@ static int adv748x_probe(struct i2c_client *client,
|
||||
ret = adv748x_identify_chip(state);
|
||||
if (ret) {
|
||||
adv_err(state, "Failed to identify chip");
|
||||
goto err_cleanup_clients;
|
||||
goto err_cleanup_dt;
|
||||
}
|
||||
|
||||
/* Configure remaining pages as I2C clients with regmap access */
|
||||
|
||||
@@ -105,6 +105,9 @@ static void adv748x_hdmi_fill_format(struct adv748x_hdmi *hdmi,
|
||||
|
||||
fmt->width = hdmi->timings.bt.width;
|
||||
fmt->height = hdmi->timings.bt.height;
|
||||
|
||||
if (fmt->field == V4L2_FIELD_ALTERNATE)
|
||||
fmt->height /= 2;
|
||||
}
|
||||
|
||||
static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings *timings)
|
||||
|
||||
@@ -27,19 +27,6 @@
|
||||
#ifndef _ADV748X_H_
|
||||
#define _ADV748X_H_
|
||||
|
||||
/* I2C slave addresses */
|
||||
#define ADV748X_I2C_IO 0x70 /* IO Map */
|
||||
#define ADV748X_I2C_DPLL 0x26 /* DPLL Map */
|
||||
#define ADV748X_I2C_CP 0x22 /* CP Map */
|
||||
#define ADV748X_I2C_HDMI 0x34 /* HDMI Map */
|
||||
#define ADV748X_I2C_EDID 0x36 /* EDID Map */
|
||||
#define ADV748X_I2C_REPEATER 0x32 /* HDMI RX Repeater Map */
|
||||
#define ADV748X_I2C_INFOFRAME 0x31 /* HDMI RX InfoFrame Map */
|
||||
#define ADV748X_I2C_CEC 0x41 /* CEC Map */
|
||||
#define ADV748X_I2C_SDP 0x79 /* SDP Map */
|
||||
#define ADV748X_I2C_TXB 0x48 /* CSI-TXB Map */
|
||||
#define ADV748X_I2C_TXA 0x4a /* CSI-TXA Map */
|
||||
|
||||
enum adv748x_page {
|
||||
ADV748X_PAGE_IO,
|
||||
ADV748X_PAGE_DPLL,
|
||||
@@ -48,6 +35,7 @@ enum adv748x_page {
|
||||
ADV748X_PAGE_EDID,
|
||||
ADV748X_PAGE_REPEATER,
|
||||
ADV748X_PAGE_INFOFRAME,
|
||||
ADV748X_PAGE_CBUS,
|
||||
ADV748X_PAGE_CEC,
|
||||
ADV748X_PAGE_SDP,
|
||||
ADV748X_PAGE_TXB,
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Analog Devices ADV7511 HDMI Transmitter Device Driver
|
||||
*
|
||||
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* adv7604 - Analog Devices ADV7604 video decoder driver
|
||||
*
|
||||
* Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -2734,6 +2722,27 @@ static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color = {
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct adv76xx_register_map {
|
||||
const char *name;
|
||||
u8 default_addr;
|
||||
};
|
||||
|
||||
static const struct adv76xx_register_map adv76xx_default_addresses[] = {
|
||||
[ADV76XX_PAGE_IO] = { "main", 0x4c },
|
||||
[ADV7604_PAGE_AVLINK] = { "avlink", 0x42 },
|
||||
[ADV76XX_PAGE_CEC] = { "cec", 0x40 },
|
||||
[ADV76XX_PAGE_INFOFRAME] = { "infoframe", 0x3e },
|
||||
[ADV7604_PAGE_ESDP] = { "esdp", 0x38 },
|
||||
[ADV7604_PAGE_DPP] = { "dpp", 0x3c },
|
||||
[ADV76XX_PAGE_AFE] = { "afe", 0x26 },
|
||||
[ADV76XX_PAGE_REP] = { "rep", 0x32 },
|
||||
[ADV76XX_PAGE_EDID] = { "edid", 0x36 },
|
||||
[ADV76XX_PAGE_HDMI] = { "hdmi", 0x34 },
|
||||
[ADV76XX_PAGE_TEST] = { "test", 0x30 },
|
||||
[ADV76XX_PAGE_CP] = { "cp", 0x22 },
|
||||
[ADV7604_PAGE_VDP] = { "vdp", 0x24 },
|
||||
};
|
||||
|
||||
static int adv76xx_core_init(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv76xx_state *state = to_state(sd);
|
||||
@@ -2834,13 +2843,26 @@ static void adv76xx_unregister_clients(struct adv76xx_state *state)
|
||||
}
|
||||
|
||||
static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd,
|
||||
u8 addr, u8 io_reg)
|
||||
unsigned int page)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct adv76xx_state *state = to_state(sd);
|
||||
struct adv76xx_platform_data *pdata = &state->pdata;
|
||||
unsigned int io_reg = 0xf2 + page;
|
||||
struct i2c_client *new_client;
|
||||
|
||||
if (addr)
|
||||
io_write(sd, io_reg, addr << 1);
|
||||
return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1);
|
||||
if (pdata && pdata->i2c_addresses[page])
|
||||
new_client = i2c_new_dummy(client->adapter,
|
||||
pdata->i2c_addresses[page]);
|
||||
else
|
||||
new_client = i2c_new_secondary_device(client,
|
||||
adv76xx_default_addresses[page].name,
|
||||
adv76xx_default_addresses[page].default_addr);
|
||||
|
||||
if (new_client)
|
||||
io_write(sd, io_reg, new_client->addr << 1);
|
||||
|
||||
return new_client;
|
||||
}
|
||||
|
||||
static const struct adv76xx_reg_seq adv7604_recommended_settings_afe[] = {
|
||||
@@ -3115,20 +3137,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
|
||||
/* Disable the interrupt for now as no DT-based board uses it. */
|
||||
state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED;
|
||||
|
||||
/* Use the default I2C addresses. */
|
||||
state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_CEC] = 0x40;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_INFOFRAME] = 0x3e;
|
||||
state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38;
|
||||
state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_AFE] = 0x26;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_REP] = 0x32;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_EDID] = 0x36;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_HDMI] = 0x34;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_TEST] = 0x30;
|
||||
state->pdata.i2c_addresses[ADV76XX_PAGE_CP] = 0x22;
|
||||
state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24;
|
||||
|
||||
/* Hardcode the remaining platform data fields. */
|
||||
state->pdata.disable_pwrdnb = 0;
|
||||
state->pdata.disable_cable_det_rst = 0;
|
||||
@@ -3478,11 +3486,9 @@ static int adv76xx_probe(struct i2c_client *client,
|
||||
if (!(BIT(i) & state->info->page_mask))
|
||||
continue;
|
||||
|
||||
state->i2c_clients[i] =
|
||||
adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i],
|
||||
0xf2 + i);
|
||||
state->i2c_clients[i] = adv76xx_dummy_client(sd, i);
|
||||
if (!state->i2c_clients[i]) {
|
||||
err = -ENOMEM;
|
||||
err = -EINVAL;
|
||||
v4l2_err(sd, "failed to create i2c client %u\n", i);
|
||||
goto err_i2c;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* adv7842 - Analog Devices ADV7842 video decoder driver
|
||||
*
|
||||
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -463,8 +463,13 @@ static void cx23885_initialize(struct i2c_client *client)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
|
||||
u32 clk_freq = 0;
|
||||
struct workqueue_struct *q;
|
||||
|
||||
/* cx23885 sets hostdata to clk_freq pointer */
|
||||
if (v4l2_get_subdev_hostdata(&state->sd))
|
||||
clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd));
|
||||
|
||||
/*
|
||||
* Come out of digital power down
|
||||
* The CX23888, at least, needs this, otherwise registers aside from
|
||||
@@ -500,8 +505,13 @@ static void cx23885_initialize(struct i2c_client *client)
|
||||
* 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
|
||||
* 572.73 MHz before post divide
|
||||
*/
|
||||
/* HVR1850 or 50MHz xtal */
|
||||
cx25840_write(client, 0x2, 0x71);
|
||||
if (clk_freq == 25000000) {
|
||||
/* 888/ImpactVCBe or 25Mhz xtal */
|
||||
; /* nothing to do */
|
||||
} else {
|
||||
/* HVR1850 or 50MHz xtal */
|
||||
cx25840_write(client, 0x2, 0x71);
|
||||
}
|
||||
cx25840_write4(client, 0x11c, 0x01d1744c);
|
||||
cx25840_write4(client, 0x118, 0x00000416);
|
||||
cx25840_write4(client, 0x404, 0x0010253e);
|
||||
@@ -544,9 +554,15 @@ static void cx23885_initialize(struct i2c_client *client)
|
||||
/* HVR1850 */
|
||||
switch (state->id) {
|
||||
case CX23888_AV:
|
||||
/* 888/HVR1250 specific */
|
||||
cx25840_write4(client, 0x10c, 0x13333333);
|
||||
cx25840_write4(client, 0x108, 0x00000515);
|
||||
if (clk_freq == 25000000) {
|
||||
/* 888/ImpactVCBe or 25MHz xtal */
|
||||
cx25840_write4(client, 0x10c, 0x01b6db7b);
|
||||
cx25840_write4(client, 0x108, 0x00000512);
|
||||
} else {
|
||||
/* 888/HVR1250 or 50MHz xtal */
|
||||
cx25840_write4(client, 0x10c, 0x13333333);
|
||||
cx25840_write4(client, 0x108, 0x00000515);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cx25840_write4(client, 0x10c, 0x002be2c9);
|
||||
@@ -576,7 +592,7 @@ static void cx23885_initialize(struct i2c_client *client)
|
||||
* 368.64 MHz before post divide
|
||||
* 122.88 MHz / 0xa = 12.288 MHz
|
||||
*/
|
||||
/* HVR1850 or 50MHz xtal */
|
||||
/* HVR1850 or 50MHz xtal or 25MHz xtal */
|
||||
cx25840_write4(client, 0x114, 0x017dbf48);
|
||||
cx25840_write4(client, 0x110, 0x000a030e);
|
||||
break;
|
||||
|
||||
@@ -168,11 +168,15 @@ static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
u32 *scancode, u8 *toggle)
|
||||
{
|
||||
int rc;
|
||||
unsigned char b;
|
||||
|
||||
/* poll IR chip */
|
||||
if (1 != i2c_master_recv(ir->c, &b, 1)) {
|
||||
rc = i2c_master_recv(ir->c, &b, 1);
|
||||
if (rc != 1) {
|
||||
dev_dbg(&ir->rc->dev, "read error\n");
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -185,11 +189,15 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
u32 *scancode, u8 *toggle)
|
||||
{
|
||||
int rc;
|
||||
unsigned char buf[4];
|
||||
|
||||
/* poll IR chip */
|
||||
if (4 != i2c_master_recv(ir->c, buf, 4)) {
|
||||
rc = i2c_master_recv(ir->c, buf, 4);
|
||||
if (rc != 4) {
|
||||
dev_dbg(&ir->rc->dev, "read error\n");
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -209,11 +217,15 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
u32 *scancode, u8 *toggle)
|
||||
{
|
||||
int rc;
|
||||
unsigned char b;
|
||||
|
||||
/* poll IR chip */
|
||||
if (1 != i2c_master_recv(ir->c, &b, 1)) {
|
||||
rc = i2c_master_recv(ir->c, &b, 1);
|
||||
if (rc != 1) {
|
||||
dev_dbg(&ir->rc->dev, "read error\n");
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -571,7 +583,7 @@ static int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf,
|
||||
/* first copy any leading non-repeating */
|
||||
int leading = c - rep * 3;
|
||||
|
||||
if (leading + rep >= ARRAY_SIZE(code_block->codes) - 3) {
|
||||
if (leading >= ARRAY_SIZE(code_block->codes) - 3 - rep) {
|
||||
dev_warn(&rcdev->dev, "IR too long, cannot transmit\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -643,7 +643,7 @@ static int max2175_set_nco_freq(struct max2175 *ctx, s32 nco_freq)
|
||||
if (abs_nco_freq < clock_rate / 2) {
|
||||
nco_val_desired = 2 * nco_freq;
|
||||
} else {
|
||||
nco_val_desired = 2 * (clock_rate - abs_nco_freq);
|
||||
nco_val_desired = 2LL * (clock_rate - abs_nco_freq);
|
||||
if (nco_freq < 0)
|
||||
nco_val_desired = -nco_val_desired;
|
||||
}
|
||||
|
||||
1140
drivers/media/i2c/mt9t112.c
Normal file
1140
drivers/media/i2c/mt9t112.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -364,33 +364,22 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
|
||||
static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *ival)
|
||||
{
|
||||
struct v4l2_captureparm *cp = &parms->parm.capture;
|
||||
|
||||
if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
memset(cp, 0, sizeof(struct v4l2_captureparm));
|
||||
cp->capability = V4L2_CAP_TIMEPERFRAME;
|
||||
calc_fps(sd,
|
||||
&cp->timeperframe.numerator,
|
||||
&cp->timeperframe.denominator);
|
||||
&ival->interval.numerator,
|
||||
&ival->interval.denominator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
|
||||
static int mt9v011_s_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *ival)
|
||||
{
|
||||
struct v4l2_captureparm *cp = &parms->parm.capture;
|
||||
struct v4l2_fract *tpf = &cp->timeperframe;
|
||||
struct v4l2_fract *tpf = &ival->interval;
|
||||
u16 speed;
|
||||
|
||||
if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
if (cp->extendedmode != 0)
|
||||
return -EINVAL;
|
||||
|
||||
speed = calc_speed(sd, tpf->numerator, tpf->denominator);
|
||||
|
||||
mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed);
|
||||
@@ -469,8 +458,8 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
|
||||
.g_parm = mt9v011_g_parm,
|
||||
.s_parm = mt9v011_s_parm,
|
||||
.g_frame_interval = mt9v011_g_frame_interval,
|
||||
.s_frame_interval = mt9v011_s_frame_interval,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = {
|
||||
|
||||
@@ -194,6 +194,7 @@ static const struct ov13858_reg mode_4224x3136_regs[] = {
|
||||
{0x3624, 0x1c},
|
||||
{0x3640, 0x10},
|
||||
{0x3641, 0x70},
|
||||
{0x3660, 0x04},
|
||||
{0x3661, 0x80},
|
||||
{0x3662, 0x12},
|
||||
{0x3664, 0x73},
|
||||
@@ -384,6 +385,7 @@ static const struct ov13858_reg mode_2112x1568_regs[] = {
|
||||
{0x3624, 0x1c},
|
||||
{0x3640, 0x10},
|
||||
{0x3641, 0x70},
|
||||
{0x3660, 0x04},
|
||||
{0x3661, 0x80},
|
||||
{0x3662, 0x10},
|
||||
{0x3664, 0x73},
|
||||
@@ -574,6 +576,7 @@ static const struct ov13858_reg mode_2112x1188_regs[] = {
|
||||
{0x3624, 0x1c},
|
||||
{0x3640, 0x10},
|
||||
{0x3641, 0x70},
|
||||
{0x3660, 0x04},
|
||||
{0x3661, 0x80},
|
||||
{0x3662, 0x10},
|
||||
{0x3664, 0x73},
|
||||
@@ -764,6 +767,7 @@ static const struct ov13858_reg mode_1056x784_regs[] = {
|
||||
{0x3624, 0x1c},
|
||||
{0x3640, 0x10},
|
||||
{0x3641, 0x70},
|
||||
{0x3660, 0x04},
|
||||
{0x3661, 0x80},
|
||||
{0x3662, 0x08},
|
||||
{0x3664, 0x73},
|
||||
@@ -1057,14 +1061,15 @@ struct ov13858 {
|
||||
#define to_ov13858(_sd) container_of(_sd, struct ov13858, sd)
|
||||
|
||||
/* Read registers up to 4 at a time */
|
||||
static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val)
|
||||
static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len,
|
||||
u32 *val)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
|
||||
struct i2c_msg msgs[2];
|
||||
u8 *data_be_p;
|
||||
int ret;
|
||||
u32 data_be = 0;
|
||||
u16 reg_addr_be = cpu_to_be16(reg);
|
||||
__be32 data_be = 0;
|
||||
__be16 reg_addr_be = cpu_to_be16(reg);
|
||||
|
||||
if (len > 4)
|
||||
return -EINVAL;
|
||||
@@ -1092,11 +1097,13 @@ static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val)
|
||||
}
|
||||
|
||||
/* Write registers up to 4 at a time */
|
||||
static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val)
|
||||
static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len,
|
||||
u32 __val)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
|
||||
int buf_i, val_i;
|
||||
u8 buf[6], *val_p;
|
||||
__be32 val;
|
||||
|
||||
if (len > 4)
|
||||
return -EINVAL;
|
||||
@@ -1104,7 +1111,7 @@ static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val)
|
||||
buf[0] = reg >> 8;
|
||||
buf[1] = reg & 0xff;
|
||||
|
||||
val = cpu_to_be32(val);
|
||||
val = cpu_to_be32(__val);
|
||||
val_p = (u8 *)&val;
|
||||
buf_i = 2;
|
||||
val_i = 4 - len;
|
||||
@@ -1348,39 +1355,6 @@ static int ov13858_get_pad_format(struct v4l2_subdev *sd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate resolution distance
|
||||
*/
|
||||
static int
|
||||
ov13858_get_resolution_dist(const struct ov13858_mode *mode,
|
||||
struct v4l2_mbus_framefmt *framefmt)
|
||||
{
|
||||
return abs(mode->width - framefmt->width) +
|
||||
abs(mode->height - framefmt->height);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the closest supported resolution to the requested resolution
|
||||
*/
|
||||
static const struct ov13858_mode *
|
||||
ov13858_find_best_fit(struct ov13858 *ov13858,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
int i, dist, cur_best_fit = 0, cur_best_fit_dist = -1;
|
||||
struct v4l2_mbus_framefmt *framefmt = &fmt->format;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
|
||||
dist = ov13858_get_resolution_dist(&supported_modes[i],
|
||||
framefmt);
|
||||
if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
|
||||
cur_best_fit_dist = dist;
|
||||
cur_best_fit = i;
|
||||
}
|
||||
}
|
||||
|
||||
return &supported_modes[cur_best_fit];
|
||||
}
|
||||
|
||||
static int
|
||||
ov13858_set_pad_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
@@ -1401,7 +1375,8 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
|
||||
if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10)
|
||||
fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
|
||||
|
||||
mode = ov13858_find_best_fit(ov13858, fmt);
|
||||
mode = v4l2_find_nearest_size(supported_modes, width, height,
|
||||
fmt->format.width, fmt->format.height);
|
||||
ov13858_update_pad_format(mode, fmt);
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
|
||||
@@ -1565,7 +1540,7 @@ static int __maybe_unused ov13858_resume(struct device *dev)
|
||||
|
||||
error:
|
||||
ov13858_stop_streaming(ov13858);
|
||||
ov13858->streaming = 0;
|
||||
ov13858->streaming = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
846
drivers/media/i2c/ov2685.c
Normal file
846
drivers/media/i2c/ov2685.c
Normal file
@@ -0,0 +1,846 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ov2685 driver
|
||||
*
|
||||
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#define CHIP_ID 0x2685
|
||||
#define OV2685_REG_CHIP_ID 0x300a
|
||||
|
||||
#define OV2685_XVCLK_FREQ 24000000
|
||||
|
||||
#define REG_SC_CTRL_MODE 0x0100
|
||||
#define SC_CTRL_MODE_STANDBY 0x0
|
||||
#define SC_CTRL_MODE_STREAMING BIT(0)
|
||||
|
||||
#define OV2685_REG_EXPOSURE 0x3500
|
||||
#define OV2685_EXPOSURE_MIN 4
|
||||
#define OV2685_EXPOSURE_STEP 1
|
||||
|
||||
#define OV2685_REG_VTS 0x380e
|
||||
#define OV2685_VTS_MAX 0x7fff
|
||||
|
||||
#define OV2685_REG_GAIN 0x350a
|
||||
#define OV2685_GAIN_MIN 0
|
||||
#define OV2685_GAIN_MAX 0x07ff
|
||||
#define OV2685_GAIN_STEP 0x1
|
||||
#define OV2685_GAIN_DEFAULT 0x0036
|
||||
|
||||
#define OV2685_REG_TEST_PATTERN 0x5080
|
||||
#define OV2685_TEST_PATTERN_DISABLED 0x00
|
||||
#define OV2685_TEST_PATTERN_COLOR_BAR 0x80
|
||||
#define OV2685_TEST_PATTERN_RANDOM 0x81
|
||||
#define OV2685_TEST_PATTERN_COLOR_BAR_FADE 0x88
|
||||
#define OV2685_TEST_PATTERN_BW_SQUARE 0x92
|
||||
#define OV2685_TEST_PATTERN_COLOR_SQUARE 0x82
|
||||
|
||||
#define REG_NULL 0xFFFF
|
||||
|
||||
#define OV2685_REG_VALUE_08BIT 1
|
||||
#define OV2685_REG_VALUE_16BIT 2
|
||||
#define OV2685_REG_VALUE_24BIT 3
|
||||
|
||||
#define OV2685_LANES 1
|
||||
#define OV2685_BITS_PER_SAMPLE 10
|
||||
|
||||
static const char * const ov2685_supply_names[] = {
|
||||
"avdd", /* Analog power */
|
||||
"dovdd", /* Digital I/O power */
|
||||
"dvdd", /* Digital core power */
|
||||
};
|
||||
|
||||
#define OV2685_NUM_SUPPLIES ARRAY_SIZE(ov2685_supply_names)
|
||||
|
||||
struct regval {
|
||||
u16 addr;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct ov2685_mode {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 exp_def;
|
||||
u32 hts_def;
|
||||
u32 vts_def;
|
||||
const struct regval *reg_list;
|
||||
};
|
||||
|
||||
struct ov2685 {
|
||||
struct i2c_client *client;
|
||||
struct clk *xvclk;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator_bulk_data supplies[OV2685_NUM_SUPPLIES];
|
||||
|
||||
bool streaming;
|
||||
struct mutex mutex;
|
||||
struct v4l2_subdev subdev;
|
||||
struct media_pad pad;
|
||||
struct v4l2_ctrl *anal_gain;
|
||||
struct v4l2_ctrl *exposure;
|
||||
struct v4l2_ctrl *hblank;
|
||||
struct v4l2_ctrl *vblank;
|
||||
struct v4l2_ctrl *test_pattern;
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
|
||||
const struct ov2685_mode *cur_mode;
|
||||
};
|
||||
|
||||
#define to_ov2685(sd) container_of(sd, struct ov2685, subdev)
|
||||
|
||||
/* PLL settings bases on 24M xvclk */
|
||||
static struct regval ov2685_1600x1200_regs[] = {
|
||||
{0x0103, 0x01},
|
||||
{0x0100, 0x00},
|
||||
{0x3002, 0x00},
|
||||
{0x3016, 0x1c},
|
||||
{0x3018, 0x44},
|
||||
{0x301d, 0xf0},
|
||||
{0x3020, 0x00},
|
||||
{0x3082, 0x37},
|
||||
{0x3083, 0x03},
|
||||
{0x3084, 0x09},
|
||||
{0x3085, 0x04},
|
||||
{0x3086, 0x00},
|
||||
{0x3087, 0x00},
|
||||
{0x3501, 0x4e},
|
||||
{0x3502, 0xe0},
|
||||
{0x3503, 0x27},
|
||||
{0x350b, 0x36},
|
||||
{0x3600, 0xb4},
|
||||
{0x3603, 0x35},
|
||||
{0x3604, 0x24},
|
||||
{0x3605, 0x00},
|
||||
{0x3620, 0x24},
|
||||
{0x3621, 0x34},
|
||||
{0x3622, 0x03},
|
||||
{0x3628, 0x10},
|
||||
{0x3705, 0x3c},
|
||||
{0x370a, 0x21},
|
||||
{0x370c, 0x50},
|
||||
{0x370d, 0xc0},
|
||||
{0x3717, 0x58},
|
||||
{0x3718, 0x80},
|
||||
{0x3720, 0x00},
|
||||
{0x3721, 0x09},
|
||||
{0x3722, 0x06},
|
||||
{0x3723, 0x59},
|
||||
{0x3738, 0x99},
|
||||
{0x3781, 0x80},
|
||||
{0x3784, 0x0c},
|
||||
{0x3789, 0x60},
|
||||
{0x3800, 0x00},
|
||||
{0x3801, 0x00},
|
||||
{0x3802, 0x00},
|
||||
{0x3803, 0x00},
|
||||
{0x3804, 0x06},
|
||||
{0x3805, 0x4f},
|
||||
{0x3806, 0x04},
|
||||
{0x3807, 0xbf},
|
||||
{0x3808, 0x06},
|
||||
{0x3809, 0x40},
|
||||
{0x380a, 0x04},
|
||||
{0x380b, 0xb0},
|
||||
{0x380c, 0x06},
|
||||
{0x380d, 0xa4},
|
||||
{0x380e, 0x05},
|
||||
{0x380f, 0x0e},
|
||||
{0x3810, 0x00},
|
||||
{0x3811, 0x08},
|
||||
{0x3812, 0x00},
|
||||
{0x3813, 0x08},
|
||||
{0x3814, 0x11},
|
||||
{0x3815, 0x11},
|
||||
{0x3819, 0x04},
|
||||
{0x3820, 0xc0},
|
||||
{0x3821, 0x00},
|
||||
{0x3a06, 0x01},
|
||||
{0x3a07, 0x84},
|
||||
{0x3a08, 0x01},
|
||||
{0x3a09, 0x43},
|
||||
{0x3a0a, 0x24},
|
||||
{0x3a0b, 0x60},
|
||||
{0x3a0c, 0x28},
|
||||
{0x3a0d, 0x60},
|
||||
{0x3a0e, 0x04},
|
||||
{0x3a0f, 0x8c},
|
||||
{0x3a10, 0x05},
|
||||
{0x3a11, 0x0c},
|
||||
{0x4000, 0x81},
|
||||
{0x4001, 0x40},
|
||||
{0x4008, 0x02},
|
||||
{0x4009, 0x09},
|
||||
{0x4300, 0x00},
|
||||
{0x430e, 0x00},
|
||||
{0x4602, 0x02},
|
||||
{0x481b, 0x40},
|
||||
{0x481f, 0x40},
|
||||
{0x4837, 0x18},
|
||||
{0x5000, 0x1f},
|
||||
{0x5001, 0x05},
|
||||
{0x5002, 0x30},
|
||||
{0x5003, 0x04},
|
||||
{0x5004, 0x00},
|
||||
{0x5005, 0x0c},
|
||||
{0x5280, 0x15},
|
||||
{0x5281, 0x06},
|
||||
{0x5282, 0x06},
|
||||
{0x5283, 0x08},
|
||||
{0x5284, 0x1c},
|
||||
{0x5285, 0x1c},
|
||||
{0x5286, 0x20},
|
||||
{0x5287, 0x10},
|
||||
{REG_NULL, 0x00}
|
||||
};
|
||||
|
||||
#define OV2685_LINK_FREQ_330MHZ 330000000
|
||||
static const s64 link_freq_menu_items[] = {
|
||||
OV2685_LINK_FREQ_330MHZ
|
||||
};
|
||||
|
||||
static const char * const ov2685_test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
"Color Bar",
|
||||
"Color Bar FADE",
|
||||
"Random Data",
|
||||
"Black White Square",
|
||||
"Color Square"
|
||||
};
|
||||
|
||||
static const int ov2685_test_pattern_val[] = {
|
||||
OV2685_TEST_PATTERN_DISABLED,
|
||||
OV2685_TEST_PATTERN_COLOR_BAR,
|
||||
OV2685_TEST_PATTERN_COLOR_BAR_FADE,
|
||||
OV2685_TEST_PATTERN_RANDOM,
|
||||
OV2685_TEST_PATTERN_BW_SQUARE,
|
||||
OV2685_TEST_PATTERN_COLOR_SQUARE,
|
||||
};
|
||||
|
||||
static const struct ov2685_mode supported_modes[] = {
|
||||
{
|
||||
.width = 1600,
|
||||
.height = 1200,
|
||||
.exp_def = 0x04ee,
|
||||
.hts_def = 0x06a4,
|
||||
.vts_def = 0x050e,
|
||||
.reg_list = ov2685_1600x1200_regs,
|
||||
},
|
||||
};
|
||||
|
||||
/* Write registers up to 4 at a time */
|
||||
static int ov2685_write_reg(struct i2c_client *client, u16 reg,
|
||||
u32 len, u32 val)
|
||||
{
|
||||
u32 val_i, buf_i;
|
||||
u8 buf[6];
|
||||
u8 *val_p;
|
||||
__be32 val_be;
|
||||
|
||||
if (len > 4)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = reg >> 8;
|
||||
buf[1] = reg & 0xff;
|
||||
|
||||
val_be = cpu_to_be32(val);
|
||||
val_p = (u8 *)&val_be;
|
||||
buf_i = 2;
|
||||
val_i = 4 - len;
|
||||
|
||||
while (val_i < 4)
|
||||
buf[buf_i++] = val_p[val_i++];
|
||||
|
||||
if (i2c_master_send(client, buf, len + 2) != len + 2)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2685_write_array(struct i2c_client *client,
|
||||
const struct regval *regs)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
|
||||
ret = ov2685_write_reg(client, regs[i].addr,
|
||||
OV2685_REG_VALUE_08BIT, regs[i].val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read registers up to 4 at a time */
|
||||
static int ov2685_read_reg(struct i2c_client *client, u16 reg,
|
||||
u32 len, u32 *val)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
u8 *data_be_p;
|
||||
__be32 data_be = 0;
|
||||
__be16 reg_addr_be = cpu_to_be16(reg);
|
||||
int ret;
|
||||
|
||||
if (len > 4)
|
||||
return -EINVAL;
|
||||
|
||||
data_be_p = (u8 *)&data_be;
|
||||
/* Write register address */
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = 2;
|
||||
msgs[0].buf = (u8 *)®_addr_be;
|
||||
|
||||
/* Read data from register */
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = len;
|
||||
msgs[1].buf = &data_be_p[4 - len];
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret != ARRAY_SIZE(msgs))
|
||||
return -EIO;
|
||||
|
||||
*val = be32_to_cpu(data_be);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ov2685_fill_fmt(const struct ov2685_mode *mode,
|
||||
struct v4l2_mbus_framefmt *fmt)
|
||||
{
|
||||
fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
||||
fmt->width = mode->width;
|
||||
fmt->height = mode->height;
|
||||
fmt->field = V4L2_FIELD_NONE;
|
||||
}
|
||||
|
||||
static int ov2685_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct ov2685 *ov2685 = to_ov2685(sd);
|
||||
struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
|
||||
|
||||
/* only one mode supported for now */
|
||||
ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2685_get_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct ov2685 *ov2685 = to_ov2685(sd);
|
||||
struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
|
||||
|
||||
ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
if (code->index >= ARRAY_SIZE(supported_modes))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
int index = fse->index;
|
||||
|
||||
if (index >= ARRAY_SIZE(supported_modes))
|
||||
return -EINVAL;
|
||||
|
||||
fse->code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
||||
|
||||
fse->min_width = supported_modes[index].width;
|
||||
fse->max_width = supported_modes[index].width;
|
||||
fse->max_height = supported_modes[index].height;
|
||||
fse->min_height = supported_modes[index].height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the delay in us by clock rate and clock cycles */
|
||||
static inline u32 ov2685_cal_delay(u32 cycles)
|
||||
{
|
||||
return DIV_ROUND_UP(cycles, OV2685_XVCLK_FREQ / 1000 / 1000);
|
||||
}
|
||||
|
||||
static int __ov2685_power_on(struct ov2685 *ov2685)
|
||||
{
|
||||
int ret;
|
||||
u32 delay_us;
|
||||
struct device *dev = &ov2685->client->dev;
|
||||
|
||||
ret = clk_prepare_enable(ov2685->xvclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable xvclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
|
||||
|
||||
ret = regulator_bulk_enable(OV2685_NUM_SUPPLIES, ov2685->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable regulators\n");
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
/* The minimum delay between power supplies and reset rising can be 0 */
|
||||
gpiod_set_value_cansleep(ov2685->reset_gpio, 0);
|
||||
/* 8192 xvclk cycles prior to the first SCCB transaction */
|
||||
delay_us = ov2685_cal_delay(8192);
|
||||
usleep_range(delay_us, delay_us * 2);
|
||||
|
||||
/* HACK: ov2685 would output messy data after reset(R0103),
|
||||
* writing register before .s_stream() as a workaround
|
||||
*/
|
||||
ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list);
|
||||
if (ret)
|
||||
goto disable_supplies;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_supplies:
|
||||
regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
|
||||
disable_clk:
|
||||
clk_disable_unprepare(ov2685->xvclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ov2685_power_off(struct ov2685 *ov2685)
|
||||
{
|
||||
/* 512 xvclk cycles after the last SCCB transaction or MIPI frame end */
|
||||
u32 delay_us = ov2685_cal_delay(512);
|
||||
|
||||
usleep_range(delay_us, delay_us * 2);
|
||||
clk_disable_unprepare(ov2685->xvclk);
|
||||
gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
|
||||
regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
|
||||
}
|
||||
|
||||
static int ov2685_s_stream(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct ov2685 *ov2685 = to_ov2685(sd);
|
||||
struct i2c_client *client = ov2685->client;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ov2685->mutex);
|
||||
|
||||
on = !!on;
|
||||
if (on == ov2685->streaming)
|
||||
goto unlock_and_return;
|
||||
|
||||
if (on) {
|
||||
ret = pm_runtime_get_sync(&ov2685->client->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
goto unlock_and_return;
|
||||
}
|
||||
ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler);
|
||||
if (ret) {
|
||||
pm_runtime_put(&client->dev);
|
||||
goto unlock_and_return;
|
||||
}
|
||||
ret = ov2685_write_reg(client, REG_SC_CTRL_MODE,
|
||||
OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STREAMING);
|
||||
if (ret) {
|
||||
pm_runtime_put(&client->dev);
|
||||
goto unlock_and_return;
|
||||
}
|
||||
} else {
|
||||
ov2685_write_reg(client, REG_SC_CTRL_MODE,
|
||||
OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STANDBY);
|
||||
pm_runtime_put(&ov2685->client->dev);
|
||||
}
|
||||
|
||||
ov2685->streaming = on;
|
||||
|
||||
unlock_and_return:
|
||||
mutex_unlock(&ov2685->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct ov2685 *ov2685 = to_ov2685(sd);
|
||||
struct v4l2_mbus_framefmt *try_fmt;
|
||||
|
||||
mutex_lock(&ov2685->mutex);
|
||||
|
||||
try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0);
|
||||
/* Initialize try_fmt */
|
||||
ov2685_fill_fmt(&supported_modes[0], try_fmt);
|
||||
|
||||
mutex_unlock(&ov2685->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __maybe_unused ov2685_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct ov2685 *ov2685 = to_ov2685(sd);
|
||||
|
||||
return __ov2685_power_on(ov2685);
|
||||
}
|
||||
|
||||
static int __maybe_unused ov2685_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct ov2685 *ov2685 = to_ov2685(sd);
|
||||
|
||||
__ov2685_power_off(ov2685);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ov2685_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(ov2685_runtime_suspend,
|
||||
ov2685_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct ov2685 *ov2685 = container_of(ctrl->handler,
|
||||
struct ov2685, ctrl_handler);
|
||||
struct i2c_client *client = ov2685->client;
|
||||
s64 max_expo;
|
||||
int ret;
|
||||
|
||||
/* Propagate change of current control to all related controls */
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_VBLANK:
|
||||
/* Update max exposure while meeting expected vblanking */
|
||||
max_expo = ov2685->cur_mode->height + ctrl->val - 4;
|
||||
__v4l2_ctrl_modify_range(ov2685->exposure,
|
||||
ov2685->exposure->minimum, max_expo,
|
||||
ov2685->exposure->step,
|
||||
ov2685->exposure->default_value);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pm_runtime_get_if_in_use(&client->dev) <= 0)
|
||||
return 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
ret = ov2685_write_reg(ov2685->client, OV2685_REG_EXPOSURE,
|
||||
OV2685_REG_VALUE_24BIT, ctrl->val << 4);
|
||||
break;
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
ret = ov2685_write_reg(ov2685->client, OV2685_REG_GAIN,
|
||||
OV2685_REG_VALUE_16BIT, ctrl->val);
|
||||
break;
|
||||
case V4L2_CID_VBLANK:
|
||||
ret = ov2685_write_reg(ov2685->client, OV2685_REG_VTS,
|
||||
OV2685_REG_VALUE_16BIT,
|
||||
ctrl->val + ov2685->cur_mode->height);
|
||||
break;
|
||||
case V4L2_CID_TEST_PATTERN:
|
||||
ret = ov2685_write_reg(ov2685->client, OV2685_REG_TEST_PATTERN,
|
||||
OV2685_REG_VALUE_08BIT,
|
||||
ov2685_test_pattern_val[ctrl->val]);
|
||||
break;
|
||||
default:
|
||||
dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
|
||||
__func__, ctrl->id, ctrl->val);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
};
|
||||
|
||||
pm_runtime_put(&client->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops ov2685_video_ops = {
|
||||
.s_stream = ov2685_s_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops ov2685_pad_ops = {
|
||||
.enum_mbus_code = ov2685_enum_mbus_code,
|
||||
.enum_frame_size = ov2685_enum_frame_sizes,
|
||||
.get_fmt = ov2685_get_fmt,
|
||||
.set_fmt = ov2685_set_fmt,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops ov2685_subdev_ops = {
|
||||
.video = &ov2685_video_ops,
|
||||
.pad = &ov2685_pad_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
static const struct v4l2_subdev_internal_ops ov2685_internal_ops = {
|
||||
.open = ov2685_open,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct v4l2_ctrl_ops ov2685_ctrl_ops = {
|
||||
.s_ctrl = ov2685_set_ctrl,
|
||||
};
|
||||
|
||||
static int ov2685_initialize_controls(struct ov2685 *ov2685)
|
||||
{
|
||||
const struct ov2685_mode *mode;
|
||||
struct v4l2_ctrl_handler *handler;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
u64 exposure_max;
|
||||
u32 pixel_rate, h_blank;
|
||||
int ret;
|
||||
|
||||
handler = &ov2685->ctrl_handler;
|
||||
mode = ov2685->cur_mode;
|
||||
ret = v4l2_ctrl_handler_init(handler, 8);
|
||||
if (ret)
|
||||
return ret;
|
||||
handler->lock = &ov2685->mutex;
|
||||
|
||||
ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
|
||||
0, 0, link_freq_menu_items);
|
||||
if (ctrl)
|
||||
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
|
||||
pixel_rate = (link_freq_menu_items[0] * 2 * OV2685_LANES) /
|
||||
OV2685_BITS_PER_SAMPLE;
|
||||
v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
|
||||
0, pixel_rate, 1, pixel_rate);
|
||||
|
||||
h_blank = mode->hts_def - mode->width;
|
||||
ov2685->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
|
||||
h_blank, h_blank, 1, h_blank);
|
||||
if (ov2685->hblank)
|
||||
ov2685->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
|
||||
ov2685->vblank = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
|
||||
V4L2_CID_VBLANK, mode->vts_def - mode->height,
|
||||
OV2685_VTS_MAX - mode->height, 1,
|
||||
mode->vts_def - mode->height);
|
||||
|
||||
exposure_max = mode->vts_def - 4;
|
||||
ov2685->exposure = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
|
||||
V4L2_CID_EXPOSURE, OV2685_EXPOSURE_MIN,
|
||||
exposure_max, OV2685_EXPOSURE_STEP,
|
||||
mode->exp_def);
|
||||
|
||||
ov2685->anal_gain = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
|
||||
V4L2_CID_ANALOGUE_GAIN, OV2685_GAIN_MIN,
|
||||
OV2685_GAIN_MAX, OV2685_GAIN_STEP,
|
||||
OV2685_GAIN_DEFAULT);
|
||||
|
||||
ov2685->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
|
||||
&ov2685_ctrl_ops, V4L2_CID_TEST_PATTERN,
|
||||
ARRAY_SIZE(ov2685_test_pattern_menu) - 1,
|
||||
0, 0, ov2685_test_pattern_menu);
|
||||
|
||||
if (handler->error) {
|
||||
ret = handler->error;
|
||||
dev_err(&ov2685->client->dev,
|
||||
"Failed to init controls(%d)\n", ret);
|
||||
goto err_free_handler;
|
||||
}
|
||||
|
||||
ov2685->subdev.ctrl_handler = handler;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_handler:
|
||||
v4l2_ctrl_handler_free(handler);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov2685_check_sensor_id(struct ov2685 *ov2685,
|
||||
struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &ov2685->client->dev;
|
||||
int ret;
|
||||
u32 id = 0;
|
||||
|
||||
ret = ov2685_read_reg(client, OV2685_REG_CHIP_ID,
|
||||
OV2685_REG_VALUE_16BIT, &id);
|
||||
if (id != CHIP_ID) {
|
||||
dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "Detected OV%04x sensor\n", CHIP_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov2685_configure_regulators(struct ov2685 *ov2685)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OV2685_NUM_SUPPLIES; i++)
|
||||
ov2685->supplies[i].supply = ov2685_supply_names[i];
|
||||
|
||||
return devm_regulator_bulk_get(&ov2685->client->dev,
|
||||
OV2685_NUM_SUPPLIES,
|
||||
ov2685->supplies);
|
||||
}
|
||||
|
||||
static int ov2685_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct ov2685 *ov2685;
|
||||
int ret;
|
||||
|
||||
ov2685 = devm_kzalloc(dev, sizeof(*ov2685), GFP_KERNEL);
|
||||
if (!ov2685)
|
||||
return -ENOMEM;
|
||||
|
||||
ov2685->client = client;
|
||||
ov2685->cur_mode = &supported_modes[0];
|
||||
|
||||
ov2685->xvclk = devm_clk_get(dev, "xvclk");
|
||||
if (IS_ERR(ov2685->xvclk)) {
|
||||
dev_err(dev, "Failed to get xvclk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
|
||||
return ret;
|
||||
}
|
||||
if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ)
|
||||
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
|
||||
|
||||
ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ov2685->reset_gpio)) {
|
||||
dev_err(dev, "Failed to get reset-gpios\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ov2685_configure_regulators(ov2685);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get power regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&ov2685->mutex);
|
||||
v4l2_i2c_subdev_init(&ov2685->subdev, client, &ov2685_subdev_ops);
|
||||
ret = ov2685_initialize_controls(ov2685);
|
||||
if (ret)
|
||||
goto err_destroy_mutex;
|
||||
|
||||
ret = __ov2685_power_on(ov2685);
|
||||
if (ret)
|
||||
goto err_free_handler;
|
||||
|
||||
ret = ov2685_check_sensor_id(ov2685, client);
|
||||
if (ret)
|
||||
goto err_power_off;
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
ov2685->subdev.internal_ops = &ov2685_internal_ops;
|
||||
ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
#endif
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
ov2685->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
ov2685->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||
ret = media_entity_pads_init(&ov2685->subdev.entity, 1, &ov2685->pad);
|
||||
if (ret < 0)
|
||||
goto err_power_off;
|
||||
#endif
|
||||
|
||||
ret = v4l2_async_register_subdev(&ov2685->subdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "v4l2 async register subdev failed\n");
|
||||
goto err_clean_entity;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_idle(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clean_entity:
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
media_entity_cleanup(&ov2685->subdev.entity);
|
||||
#endif
|
||||
err_power_off:
|
||||
__ov2685_power_off(ov2685);
|
||||
err_free_handler:
|
||||
v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
|
||||
err_destroy_mutex:
|
||||
mutex_destroy(&ov2685->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov2685_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct ov2685 *ov2685 = to_ov2685(sd);
|
||||
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
media_entity_cleanup(&sd->entity);
|
||||
#endif
|
||||
v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
|
||||
mutex_destroy(&ov2685->mutex);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
__ov2685_power_off(ov2685);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id ov2685_of_match[] = {
|
||||
{ .compatible = "ovti,ov2685" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ov2685_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver ov2685_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ov2685",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &ov2685_pm_ops,
|
||||
.of_match_table = of_match_ptr(ov2685_of_match),
|
||||
},
|
||||
.probe = &ov2685_probe,
|
||||
.remove = &ov2685_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(ov2685_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("OmniVision ov2685 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user